diff --git a/docs/develop/dapps/ton-connect/protocol/README.md b/docs/develop/dapps/ton-connect/protocol/README.md deleted file mode 100644 index c090111326..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Protocol specifications - -Understand how TON Connect works under the hood. - -## Who is this section for? - -- If you implement a wallet -- If you develop an SDK -- If you want to learn how TON Connect works - -## Sections overview - -* [Protocol workflows](/develop/dapps/ton-connect/protocol/workflow) is an overview of all the protocols involved in TON Connect. -* [Bridge API](/develop/dapps/ton-connect/protocol/bridge) specifies how the data is transmitted between the app and the wallet. -* [Session protocol](/develop/dapps/ton-connect/protocol/session) ensures end-to-end encrypted communication over the bridge. -* [Requests protocol](/develop/dapps/ton-connect/protocol/requests-responses) defines requests and responses for the app and the wallet. -* [Wallet guidelines](/develop/dapps/ton-connect/protocol/wallet-guidelines) defines guidelines for wallet developers. - -## FAQ - -#### I am building an HTML/JS app, what should I read? - -Simply use the [Supported SDKs](/develop/dapps/ton-connect/developers) and do not worry about the underlying protocols. - -#### I need an SDK in my favorite language - -Please take the [JS SDK](/develop/dapps/ton-connect/developers) as a reference and check out the protocol docs above. - -#### How do you detect whether the app is embedded in the wallet? - -JS SDK does that for you; just get wallets list `connector.getWallets()` and check `embedded` property of the corresponding list item. If you build your own SDK you should check `window.[targetWalletJsBridgeKey].tonconnect.isWalletBrowser`. - -#### How do you detect if the wallet is a browser extension? - -Like with embedded apps (see above), JS SDK detects it for you via `injected` property of the corresponding `connector.getWallets()` list item. If you build your own SDK you should check that `window.[targetWalletJsBridgeKey].tonconnect` exists. - -#### How to implement backend authorization with tonconnect? - -[See an example of dapp-backend](https://github.com/ton-connect/demo-dapp-backend) - -#### How do I make my own bridge? - -You don’t need to, unless you are building a wallet. - -If you build a wallet, you will need to provide a bridge. See our [reference implementation in Go](https://github.com/ton-connect/bridge). - -Keep in mind that the wallet’s side of the bridge API is not mandated. - -For a quick start you can use the common TON Connect bridge [github.com/ton-connect/bridge2](https://github.com/ton-connect/bridge2). - -#### I make a wallet, how do I add it to the list of wallets? - -Submit a pull request for the [wallets-list](https://github.com/ton-blockchain/wallets-list) repository and fill our all the necessary metadata. - -Apps may also add wallets directly through the SDK. diff --git a/docs/develop/dapps/ton-connect/protocol/bridge.md b/docs/develop/dapps/ton-connect/protocol/bridge.md deleted file mode 100644 index 44caf7e115..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/bridge.md +++ /dev/null @@ -1,202 +0,0 @@ -# Bridge API - -Bridge is a transport mechanism to deliver messages from the app to the wallet and vice versa. - -* **Bridge is maintained by the wallet provider**. App developers do not have to choose or build a bridge. Each wallet’s bridge is listed in the [wallets-list](https://github.com/ton-blockchain/wallets-list) config. -* **Messages are end-to-end encrypted.** Bridge does not see the contents or long-term identifiers of the app or wallet. -* **Communication is symmetrical.** Bridge does not distinguish between apps and wallets: both are simply clients. -* Bridge keeps separate queues of messages for each recipient’s **Client ID**. - -Bridge comes in two flavors: - -- [HTTP Bridge](#http-bridge): for the external apps and services. -- [JS Bridge](#js-bridge): for apps opened within the wallet; or when the wallet is a browser extension. - -## HTTP Bridge - -Client with ID **A** connects to the bridge to listen to incoming requests. - -**Client ID is semi-private:** apps and wallets are not supposed to share their IDs with other entities to avoid having their messages removed unexpectedly. - -**Client can subscribe on few Client IDs** - in this case it should enumerate IDs separated with commas. For example: `?client_id=,,` - -```tsx -request - GET /events?client_id= - - Accept: text/event-stream -``` - -**Subscribing to the bridge second (any other) time** - -```tsx -request - GET /events?client_id=&last_event_id= - - Accept: text/event-stream -``` - -**lastEventId** – the eventId of the last SSE event wallet got over the bridge. In this case wallet will fetch all the events which happened after the last connection. - -Sending message from client A to client B. Bridge returns error if ttl is too high. - -```tsx -request - POST /message?client_id=?to=&ttl=300&topic= - - body: -``` - - -The `topic` [optional] query parameter can be used by the bridge to deliver the push notification to the wallet. If the parameter is given, it must correspond to the RPC method called inside the encrypted `message`. - -Bridge buffers messages up to TTL (in secs), but removes them as soon as the recipient receives the message. - -If the TTL exceeds the hard limit of the bridge server, it should respond with HTTP 400. Bridges should support at least 300 seconds TTL. - -When the bridge receives a message `base64_encoded_message` from client `A` addressed to client `B`, it generates a message `BridgeMessage`: - -```js -{ - "from": , - "message": -} -``` - -and sends it to the client B via SSE connection -```js -resB.write(BridgeMessage) -``` - -### Heartbeat - -To keep the connection, bridge server should periodically send a "heartbeat" message to the SSE channel. Client should ignore such messages. -So, the bridge heartbeat message is a string with word `heartbeat`. - - -## Universal link - -When the app initiates the connection it sends it directly to the wallet via the QR code or a universal link. - -```bash -https://? - v=2& - id=& - r=& - ret=back -``` - -Parameter **v** specifies the protocol version. Unsupported versions are not accepted by the wallets. - -Parameter **id** specifies app’s Client ID encoded as hex (without '0x' prefix). - -Parameter **r** specifies URL-safe json [ConnectRequest](/develop/dapps/ton-connect/protocol/requests-responses#initiating-connection). - -Parameter **ret** (optional) specifies return strategy for the deeplink when user signs/declines the request. -- 'back' (default) means return to the app which initialized deeplink jump (e.g. browser, native app, ...), -- 'none' means no jumps after user action; -- a URL: wallet will open this URL after completing the user's action. Note, that you shouldn't pass your app's URL if it is a webpage. This option should be used for native apps to work around possible OS-specific issues with `'back'` option. - -`ret` parameter should be supported for empty deeplinks -- it might be used to specify the wallet behavior after other actions confirmation (send transaction, sign raw, ...). -```bash -https://?ret=back -``` - - -The link may be embedded in a QR code or clicked directly. - -The initial request is unencrypted because (1) there is no personal data being communicated yet, (2) app does not even know the identity of the wallet. - -### Unified deeplink `tc` -In addition to its own universal link, the wallet must support the unified deeplink. - -This allows applications to create a single qr code, which can be used to connect to any wallet. - -More specifically, the wallet must support `tc://` deeplink as well as its own ``. - -Therefore, the following `connect request` must be processed by the wallet: - -```bash -tc://? - v=2& - id=& - r=& - ret=back -``` - - -## JS bridge - -Used by the embedded apps via the injected binding `window..tonconnect`. - -`wallet-js-bridge-key` can be specified in the [wallets list](https://github.com/ton-blockchain/wallets-list) - -JS bridge runs on the same device as the wallet and the app, so communication is not encrypted. - -The app works directly with plaintext requests and responses, without session keys and encryption. - -```tsx -interface TonConnectBridge { - deviceInfo: DeviceInfo; // see Requests/Responses spec - walletInfo?: WalletInfo; - protocolVersion: number; // max supported Ton Connect version (e.g. 2) - isWalletBrowser: boolean; // if the page is opened into wallet's browser - connect(protocolVersion: number, message: ConnectRequest): Promise; - restoreConnection(): Promise; - send(message: AppRequest): Promise; - listen(callback: (event: WalletEvent) => void): () => void; -} -``` - -Just like with the HTTP bridge, wallet side of the bridge does not receive the app requests except for [ConnectRequest](/develop/dapps/ton-connect/protocol/requests-responses#initiating-connection) until the session is confirmed by the user. Technically, the messages arrive from the webview into the bridge controller, but they are silently ignored. - -SDK around the implements **autoconnect()** and **connect()** as silent and non-silent attempts at establishing the connection. - -### walletInfo (optional) -Represents wallet metadata. Might be defined to make an injectable wallet works with TonConnect even if the wallet is not listed in the [wallets-list.json](https://github.com/ton-blockchain/wallets-list). - -Wallet metadata format: -```ts -interface WalletInfo { - name: string; - image: ; - tondns?: string; - about_url: ; -} -``` - -Detailed properties description: https://github.com/ton-blockchain/wallets-list#entry-format. - -If `TonConnectBridge.walletInfo` is defined and the wallet is listed in the [wallets-list.json](https://github.com/ton-blockchain/wallets-list), `TonConnectBridge.walletInfo` properties will override corresponding wallet properties from the wallets-list.json. - - -### connect() - -Initiates connect request, this is analogous to QR/link when using the HTTP bridge. - -If the app was previously approved for the current account — connects silently with ConnectEvent. Otherwise shows confirmation dialog to the user. - -You shouldn't use the `connect` method without explicit user action (e.g. connect button click). If you want automatically try to restore previous connection, you should use the `restoreConnection` method. - -### restoreConnection() - -Attempts to restore the previous connection. - -If the app was previously approved for the current account — connects silently with the new `ConnectEvent` with only a `ton_addr` data item. - - -Otherwise returns `ConnectEventError` with error code 100 (Unknown app). - - -### send() - -Sends a [message](/develop/dapps/ton-connect/protocol/requests-responses#messages) to the bridge, excluding the ConnectRequest (that goes into QR code when using HTTP bridge and into connect when using JS Bridge). -Directly returns promise with WalletResponse, so you don't need to wait for responses with `listen`; - -### listen() - -Registers a listener for events from the wallet. - -Returns unsubscribe function. - -Currently, only `disconnect` event is available. Later there will be a switch account event and other wallet events. diff --git a/docs/develop/dapps/ton-connect/protocol/requests-responses.md b/docs/develop/dapps/ton-connect/protocol/requests-responses.md deleted file mode 100644 index e4ac685017..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/requests-responses.md +++ /dev/null @@ -1,493 +0,0 @@ -# Requests and Responses - -App sends requests to the wallet. Wallet sends responses and events to the app. - -```tsx -type AppMessage = ConnectRequest | AppRequest; - -type WalletMessage = WalletResponse | WalletEvent; -``` - -### App manifest -App needs to have its manifest to pass meta information to the wallet. Manifest is a JSON file named as `tonconnect-manifest.json` following format: - -```json -{ - "url": "", // required - "name": "", // required - "iconUrl": "", // required - "termsOfUseUrl": "", // optional - "privacyPolicyUrl": "" // optional -} -``` - -Best practice is to place the manifest in the root of your app, e.g. `https://myapp.com/tonconnect-manifest.json`. It allows the wallet to handle your app better and improve the UX connected to your app. -Make sure that manifest is available to GET by its URL. - -#### Fields description -- `url` -- app URL. Will be used as the DAppidentifier. Will be used to open the DAppafter click to its icon in the wallet. It is recommended to pass url without closing slash, e.g. 'https://mydapp.com' instead of 'https://mydapp.com/'. -- `name` -- app name. Might be simple, will not be used as identifier. -- `iconUrl` -- Url to the app icon. Must be PNG, ICO, ... format. SVG icons are not supported. Perfectly pass url to a 180x180px PNG icon. -- `termsOfUseUrl` -- (optional) url to the Terms Of Use document. Optional for usual apps, but required for the apps which is placed in the Tonkeeper recommended apps list. -- `privacyPolicyUrl` -- (optional) url to the Privacy Policy document. Optional for usual apps, but required for the apps which is placed in the Tonkeeper recommended apps list. - -### Initiating connection - -App’s request message is **InitialRequest**. - -```tsx -type ConnectRequest = { - manifestUrl: string; - items: ConnectItem[], // data items to share with the app -} - -// In the future we may add other personal items. -// Or, instead of the wallet address we may ask for per-service ID. -type ConnectItem = TonAddressItem | TonProofItem | ...; - -type TonAddressItem = { - name: "ton_addr"; -} -type TonProofItem = { - name: "ton_proof"; - payload: string; // arbitrary payload, e.g. nonce + expiration timestamp. -} -``` - -ConnectRequest description: -- `manifestUrl`: link to the app's tonconnect-manifest.json -- `items`: data items to share with the app. - -Wallet responds with **ConnectEvent** message if the user approves the request. - -```tsx -type ConnectEvent = ConnectEventSuccess | ConnectEventError; - -type ConnectEventSuccess = { - event: "connect"; - id: number; // increasing event counter - payload: { - items: ConnectItemReply[]; - device: DeviceInfo; - } -} -type ConnectEventError = { - event: "connect_error", - id: number; // increasing event counter - payload: { - code: number; - message: string; - } -} - -type DeviceInfo = { - platform: "iphone" | "ipad" | "android" | "windows" | "mac" | "linux"; - appName: string; // e.g. "Tonkeeper" - appVersion: string; // e.g. "2.3.367" - maxProtocolVersion: number; - features: Feature[]; // list of supported features and methods in RPC - // Currently there is only one feature -- 'SendTransaction'; -} - -type Feature = { name: 'SendTransaction', maxMessages: number } | // `maxMessages` is maximum number of messages in one `SendTransaction` that the wallet supports - { name: 'SignData' }; - -type ConnectItemReply = TonAddressItemReply | TonProofItemReply ...; - -// Untrusted data returned by the wallet. -// If you need a guarantee that the user owns this address and public key, you need to additionally request a ton_proof. -type TonAddressItemReply = { - name: "ton_addr"; - address: string; // TON address raw (`0:`) - network: NETWORK; // network global_id - publicKey: string; // HEX string without 0x - walletStateInit: string; // Base64 (not url safe) encoded stateinit cell for the wallet contract -} - -type TonProofItemReply = TonProofItemReplySuccess | TonProofItemReplyError; - -type TonProofItemReplySuccess = { - name: "ton_proof"; - proof: { - timestamp: string; // 64-bit unix epoch time of the signing operation (seconds) - domain: { - lengthBytes: number; // AppDomain Length - value: string; // app domain name (as url part, without encoding) - }; - signature: string; // base64-encoded signature - payload: string; // payload from the request - } -} - -type TonProofItemReplyError = { - name: "ton_addr"; - error: { - code: ConnectItemErrorCode; - message?: string; - } -} - -enum NETWORK { - MAINNET = '-239', - TESTNET = '-3' -} -``` - -**Connect event error codes:** - -| code | description | -|------|------------------------------| -| 0 | Unknown error | -| 1 | Bad request | -| 2 | App manifest not found | -| 3 | App manifest content error | -| 100 | Unknown app | -| 300 | User declined the connection | - -**Connect item error codes:** - -| code | description | -|------|------------------------------| -| 0 | Unknown error | -| 400 | Method is not supported | - -If the wallet doesn't support the requested `ConnectItem` (e.g. "ton_proof"), it must send reply with the following ConnectItemReply corresponding to the requested item. -with following structure: -```ts -type ConnectItemReplyError = { - name: ""; - error: { - code: 400; - message?: string; - } -} -``` - -### Address proof signature (`ton_proof`) - -If `TonProofItem` is requested, wallet proves ownership of the selected account’s key. The signed message is bound to: - -- Unique prefix to separate messages from on-chain messages. (`ton-connect`) -- Wallet address. -- App domain -- Signing timestamp -- App’s custom payload (where server may put its nonce, cookie id, expiration time). - -``` -message = utf8_encode("ton-proof-item-v2/") ++ - Address ++ - AppDomain ++ - Timestamp ++ - Payload -signature = Ed25519Sign(privkey, sha256(0xffff ++ utf8_encode("ton-connect") ++ sha256(message))) -``` - -where: - -* `Address` is the wallet address encoded as a sequence: - * `workchain`: 32-bit signed integer big endian; - * `hash`: 256-bit unsigned integer big endian; -* `AppDomain` is Length ++ EncodedDomainName - - `Length` is 32-bit value of utf-8 encoded app domain name length in bytes - - `EncodedDomainName` id `Length`-byte utf-8 encoded app domain name -* `Timestamp` 64-bit unix epoch time of the signing operation -* `Payload` is a variable-length binary string. - -Note: payload is variable-length untrusted data. To avoid using unnecessary length prefixes we simply put it last in the message. - -The signature must be verified by public key: - -1. First, try to obtain public key via `get_public_key` get-method on smart contract deployed at `Address`. - -2. If the smart contract is not deployed yet, or the get-method is missing, you need: - - 1. Parse `TonAddressItemReply.walletStateInit` and get public key from stateInit. You can compare the `walletStateInit.code` with the code of standard wallets contracts and parse the data according to the found wallet version. - - 2. Check that `TonAddressItemReply.publicKey` equals to obtained public key - - 3. Check that `TonAddressItemReply.walletStateInit.hash()` equals to `TonAddressItemReply.address`. `.hash()` means BoC hash. - -## Messages - -- All messages from the app to the wallet are requests for an operation. -- Messages from the wallet to the application can be either responses to app requests or events triggered by user actions on the side of the wallet. - -**Available operations:** - -- sendTransaction -- signData -- disconnect - -**Available events:** - -- connect -- connect_error -- disconnect - -### Structure - -**All app requests have the following structure (like json-rpc 2.0)** -```tsx -interface AppRequest { - method: string; - params: string[]; - id: string; -} -``` -Where -- `method`: name of the operation ('sendTransaction', 'signMessage', ...) -- `params`: array of the operation specific parameters -- `id`: increasing identifier that allows to match requests and responses - - -**Wallet messages are responses or events.** - -Response is an object formatted as a json-rpc 2.0 response. Response `id` must match request's id. - -Wallet doesn't accept any request with an id that does not greater the last processed request id of that session. - -```tsx -type WalletResponse = WalletResponseSuccess | WalletResponseError; - -interface WalletResponseSuccess { - result: string; - id: string; -} - -interface WalletResponseError { - error: { code: number; message: string; data?: unknown }; - id: string; -} -``` - -Event is an object with property `event` that is equal to event's name, `id` that is increasing event counter (**not** related to `request.id` because there is no request for an event), and `payload` that contains event additional data. -```tsx -interface WalletEvent { - event: WalletEventName; - id: number; // increasing event counter - payload: ; // specific payload for each event -} - -type WalletEventName = 'connect' | 'connect_error' | 'disconnect'; -``` - -Wallet must increase `id` while generating a new event. (Every next event must have `id` > previous event `id`) - -DAppdoesn't accept any event with an id that does not greater the last processed event id of that session. - -### Methods - -#### Sign and send transaction - -App sends **SendTransactionRequest**: - -```tsx -interface SendTransactionRequest { - method: 'sendTransaction'; - params: []; - id: string; -} -``` - -Where `` is JSON with following properties: - -* `valid_until` (integer, optional): unix timestamp. after th moment transaction will be invalid. -* `network` (NETWORK, optional): The network (mainnet or testnet) where DAppintends to send the transaction. If not set, the transaction is sent to the network currently set in the wallet, but this is not safe and DAppshould always strive to set the network. If the `network` parameter is set, but the wallet has a different network set, the wallet should show an alert and DO NOT ALLOW TO SEND this transaction. -* `from` (string in `:` format, optional) - The sender address from which DAppintends to send the transaction. If not set, wallet allows user to select the sender's address at the moment of transaction approval. If `from` parameter is set, the wallet should DO NOT ALLOW user to select the sender's address; If sending from the specified address is impossible, the wallet should show an alert and DO NOT ALLOW TO SEND this transaction. -* `messages` (array of messages): 1-4 outgoing messages from the wallet contract to other accounts. All messages are sent out in order, however **the wallet cannot guarantee that messages will be delivered and executed in same order**. - -Message structure: -* `address` (string): message destination -* `amount` (decimal string): number of nanocoins to send. -* `payload` (string base64, optional): raw one-cell BoC encoded in Base64. -* `stateInit` (string base64, optional): raw once-cell BoC encoded in Base64. - -#### Common cases -1. No payload, no stateInit: simple transfer without a message. -2. payload is prefixed with 32 zero bits, no stateInit: simple transfer with a text message. -3. No payload or prefixed with 32 zero bits; stateInit is present: deployment of the contract. - -
-Example - -```json5 -{ - "valid_until": 1658253458, - "network": "-239", // enum NETWORK { MAINNET = '-239', TESTNET = '-3'} - "from": "0:348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f", - "messages": [ - { - "address": "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", - "amount": "20000000", - "stateInit": "base64bocblahblahblah==" //deploy contract - },{ - "address": "0:E69F10CC84877ABF539F83F879291E5CA169451BA7BCE91A37A5CED3AB8080D3", - "amount": "60000000", - "payload": "base64bocblahblahblah==" //transfer nft to new deployed account 0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F - } - ] -} -``` -
- - -Wallet replies with **SendTransactionResponse**: - -```tsx -type SendTransactionResponse = SendTransactionResponseSuccess | SendTransactionResponseError; - -interface SendTransactionResponseSuccess { - result: ; - id: string; - -} - -interface SendTransactionResponseError { - error: { code: number; message: string }; - id: string; -} -``` - -**Error codes:** - -| code | description | -|------|-------------------------------| -| 0 | Unknown error | -| 1 | Bad request | -| 100 | Unknown app | -| 300 | User declined the transaction | -| 400 | Method not supported | - - -#### Sign Data (Experimental) - -> WARNING: this is currently an experimental method and its signature may change in the future - -App sends **SignDataRequest**: - -```tsx -interface SignDataRequest { - method: 'signData'; - params: []; - id: string; -} -``` - -Where `` is JSON with following properties: - -* `schema_crc` (integer): indicates the layout of payload cell that in turn defines domain separation. -* `cell` (string, base64 encoded Cell): contains arbitrary data per its TL-B definition. -* `publicKey` (HEX string without 0x, optional): The public key of key pair from which DAppintends to sign the data. If not set, the wallet is not limited in what keypair to sign. If `publicKey` parameter is set, the wallet SHOULD to sign by keypair corresponding this public key; If sign by this specified keypair is impossible, the wallet should show an alert and DO NOT ALLOW TO SIGN this data. - -The signature will be computed in the following way: -`ed25519(uint32be(schema_crc) ++ uint64be(timestamp) ++ cell_hash(X), privkey)` - -[See details](https://github.com/oleganza/TEPs/blob/datasig/text/0000-data-signatures.md) - -Wallet should decode the cell in accordance with the schema_crc and show corresponding data to the user. -If the schema_crc is unknown to the wallet, the wallet should show danger notification/UI to the user. - -Wallet replies with **SignDataResponse**: - -```tsx -type SignDataResponse = SignDataResponseSuccess | SignDataResponseError; - -interface SignDataResponseSuccess { - result: { - signature: string; // base64 encoded signature - timestamp: string; // UNIX timestamp in seconds (UTC) at the moment on creating the signature. - }; - id: string; -} - -interface SignDataResponseError { - error: { code: number; message: string }; - id: string; -} -``` - -**Error codes:** - -| code | description | -|------|---------------------------| -| 0 | Unknown error | -| 1 | Bad request | -| 100 | Unknown app | -| 300 | User declined the request | -| 400 | Method not supported | - - -#### Disconnect operation -When user disconnects the wallet in the dApp, DAppshould inform the wallet to help the wallet save resources and delete unnecessary session. -Allows the wallet to update its interface to the disconnected state. - -```tsx -interface DisconnectRequest { - method: 'disconnect'; - params: []; - id: string; -} -``` - -Wallet replies with **DisconnectResponse**: - -```ts -type DisconnectResponse = DisconnectResponseSuccess | DisconnectResponseError; - -interface DisconnectResponseSuccess { - id: string; - result: { }; -} - -interface DisconnectResponseError { - error: { code: number; message: string }; - id: string; -} -``` - -Wallet **shouldn't** emit a 'Disconnect' event if disconnect was initialized by the dApp. - -**Error codes:** - -| code | description | -|------|---------------------------| -| 0 | Unknown error | -| 1 | Bad request | -| 100 | Unknown app | -| 400 | Method not supported | - - -### Wallet events - -Disconnect - -The event fires when the user deletes the app in the wallet. The app must react to the event and delete the saved session. If the user disconnects the wallet on the app side, then the event does not fire, and the session information remains in the localstorage - -```tsx -interface DisconnectEvent { - type: "disconnect", - id: number; // increasing event counter - payload: { } -} -``` - -Connect - -```tsx -type ConnectEventSuccess = { - event: "connect", - id: number; // increasing event counter - payload: { - items: ConnectItemReply[]; - device: DeviceInfo; - } -} -type ConnectEventError = { - event: "connect_error", - id: number; // increasing event counter - payload: { - code: number; - message: string; - } -} -``` \ No newline at end of file diff --git a/docs/develop/dapps/ton-connect/protocol/session.md b/docs/develop/dapps/ton-connect/protocol/session.md deleted file mode 100644 index a85fb87d6b..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/session.md +++ /dev/null @@ -1,62 +0,0 @@ -# Session protocol - -Session protocol defines client identifiers and offers end-to-end encryption for the app and the wallet. This means the HTTP bridge is fully untrusted and cannot read the user’s data transmitted between the app and the wallet. JS bridge does not use this protocol since both the wallet and the app run on the same device. - -## Definitions - -### Client Keypair - -X25519 keypair for the use with NaCl “crypto_box” protocol. - -``` -a <- random 23 bytes -A <- X25519Pubkey(s) -``` - -or - -``` -(a,A) <- nacl.box.keyPair() -``` - - -### Client ID - -The public key part of the [Client Keypair](#client-keypair) (32 bytes). - -### Session - -A session is defined by a pair of two client IDs. Both the app and the wallet create their own [Client IDs](#client-id). - - -### Creating client Keypair - -``` -(a,A) <- nacl.box.keyPair() -``` - -### Encryption - -All requests from the app (except the initial request) and all responses from the wallet are encrypted. - -Given a binary encoding of message **m**, recipient’s [Client ID](#client-id) **X** and sender’s private key **y** the message is encrypted as follows: - -``` -nonce <- random(24 bytes) -ct <- nacl.box(m, nonce, X, y) -M <- nonce ++ ct -``` - -That is, the final message **M** has the first 24 bytes set to the random nonce. - -### Decryption - -To decrypt the message **M**, the recipient uses its private key **x** and sender’s public key **Y** (aka [Client ID](#client-id)): - -``` -nonce <- M[0..24] -ct <- M[24..] -m <- nacl.box.open(ct, nonce, Y, x) -``` - -Plaintext **m** is recovered and parsed per [Requests/Responses](/develop/dapps/ton-connect/protocol/requests-responses#requests-and-responses). \ No newline at end of file diff --git a/docs/develop/dapps/ton-connect/protocol/wallet-guidelines.md b/docs/develop/dapps/ton-connect/protocol/wallet-guidelines.md deleted file mode 100644 index 38b20ae6bb..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/wallet-guidelines.md +++ /dev/null @@ -1,62 +0,0 @@ -# Wallet Guidelines - -## Networks - -### There aren't many networks. - - At the moment, there are only two networks - Mainnet and Testnet. - In the foreseeable future, the emergence of new Mainnet TON-like networks is not expected. Note that the current Mainnet has a built-in mechanism for alternative networks - workchains. - - -### Hide the Testnet from ordinary users. - -Testnet is used exclusively by developers. Ordinary users should not see the Testnet. -This means that switching to Testnet should not be readily available and users SHOULD NOT be prompted to switch wallet to Testnet even if DAppis in Testnet. -Users switch to Testnet, don't understand this action, can't switch back to Mainnet. - -For these reasons, dapps do not need to switch networks in runtime, on the contrary, it is more preferable to have different instances of DAppon different domains dapp.com, Testnet.dapp.com. -For the same reason there is no `NetworkChanged` or `ChainChanged` event in the Ton Connect protocol. - - -### Do not send anything if the DAppis in Testnet and the wallet is in Mainnet. - - It is necessary to prevent loss of funds when DApptries to send a transaction in Testnet, and the wallet sends it in Mainnet. - - Dapps should explicitly indicate `network` field in `SendTransaction` request. - - If the `network` parameter is set, but the wallet has a different network set, the wallet should show an alert and DO NOT ALLOW TO SEND this transaction. - - The wallet SHOULD NOT offer to switch to another network in this case. - -## Multi accounts - -Multiple network accounts can be created for one key pair. Implement this functionality in your wallet - users will find it useful. - -### In general, there is no current "active" account - -At the moment, the TON Connect is not built on the paradigm that there is one selected account in the wallet, and when the user switches to another account, the `AccountChanged` event is sent to dapp. - -We think of a wallet as a physical wallet that can contain many "bank cards" (accounts). - -In most cases the sender address is not important to dapp, in these cases the user can select the appropriate account at the time of approving the transaction and the transaction will be sent from selected account. - -In some cases, it is important for DAppto send the transaction from a specific address, in which case it explicitly specifies the `from` field in `SendTransaction` request. If `from` parameter is set, the wallet should DO NOT ALLOW user to select the sender's address; If sending from the specified address is impossible, the wallet should show an alert and DO NOT ALLOW TO SEND this transaction. - -### Login flow - -When DAppconnects the wallet, the user selects in the wallet one of their accounts that they want to log into dapp. - -Regardless of what accounts the user uses next in the wallet, DAppworks with the account he received on the connection. - -Just like if you logged into a web service with one of your email accounts - if you then change the email account in the email service, the web service continues to use the one he got when you logged in. - -For this reason, the protocol does not provide the `AccountChanged` event. - -To switch account user need to disconnect (Log out) and connect (Login) again in DAppUI. - -We recommend wallets provide the ability to disconnect session with a specified DAppbecause the DAppmay have an incomplete UI. - -## See Also - -* [TON Connect Overview](/dapps/ton-connect/overview) -* [Connect a Wallet](/dapps/ton-connect/wallet) diff --git a/docs/develop/dapps/ton-connect/protocol/workflow.md b/docs/develop/dapps/ton-connect/protocol/workflow.md deleted file mode 100644 index 0772232244..0000000000 --- a/docs/develop/dapps/ton-connect/protocol/workflow.md +++ /dev/null @@ -1,37 +0,0 @@ -# Workflows - -## Overview - -### First-time connection via http bridge -1. App initiates SSE connection with bridge; -2. App passes connection info to the wallet via universal link or deeplink or QR code; -3. Wallet connects to the bridge with given parameters, and save connection info locally; -4. Wallet sends account information to the app using bridge; -5. App receives message and save connection info locally; - -### Reconnection with http bridge -1. App reads connection info from localstorage -2. App connects to the bridge -3. User opens the wallet, the wallet connects to the bridge using stored connection info - -### First-time connection via js bridge -1. App checks existing of the `window.[walletJsBridgeKey].tonconnect` -2. App calls `window.[walletJsBridgeKey].tonconnect.connect()` and waits for a response -3. Wallet sends account information to the app; - -### Making ordinary requests and responses -1. App and wallet are in a connected state -2. App generates request and sends it to the bridge -3. Bridge forwards message to the wallet -4. Wallet generates response and sends it to the bridge -5. Bridge forwards message to the app - -## Specification - -Read detailed specification [here](https://github.com/ton-blockchain/ton-connect/blob/main/workflows.md#details). - -## See Also - -* [Ton Connect Overview](/dapps/ton-connect/) -* [Integration manual](/develop/dapps/ton-connect/integration) -* [Telegram bot integration manual](/develop/dapps/ton-connect/tg-bot-integration) \ No newline at end of file diff --git a/docs/develop/dapps/ton-connect/react.mdx b/docs/develop/dapps/ton-connect/react.mdx index f7dee24c9b..ccff73246f 100644 --- a/docs/develop/dapps/ton-connect/react.mdx +++ b/docs/develop/dapps/ton-connect/react.mdx @@ -39,12 +39,12 @@ Add the `TonConnectButton`. The TonConnect Button is a universal UI component fo ```tsx export const Header = () => { - return ( -
- My App with React UI - -
- ); + return ( +
+ My App with React UI + +
+ ); }; ``` @@ -53,7 +53,30 @@ You can add className and style props to the button as well. Note that you canno ``` -Moreover, you always can initiate the connection manually, using `useTonConnectUI` hook and [connectWallet](https://github.com/ton-connect/sdk/tree/main/packages/ui#call-connect) method. +Moreover, you always can initiate the connection manually, using `useTonConnectUI` hook and [openModal](https://github.com/ton-connect/sdk/tree/main/packages/ui#open-connect-modal) method. + +```tsx +export const Header = () => { + const [tonConnectUI, setOptions] = useTonConnectUI(); + return ( +
+ My App with React UI + +
+ ); +}; +``` + +#### Connect with a specific wallet +To open a modal window for a specific wallet, use the `openSingleWalletModal()` method. This method takes the wallet's `app_name` as a parameter (refer to the [wallets-list.json]('https://github.com/ton-blockchain/wallets-list/blob/main/wallets-v2.json') file) and opens the corresponding wallet modal. It returns a promise that resolves once the modal window has successfully opened. + +```tsx + +``` ### Redirects @@ -85,50 +108,76 @@ If you want to use some low-level TON Connect UI SDK features in your React app, ### useTonAddress -Use it to get user's current ton wallet address. Pass boolean parameter isUserFriendly to choose format of the address. If wallet is not connected hook will return empty string. +Use it to get user's current ton wallet address. Pass the boolean parameter `isUserFriendly` (default is `true`) to choose the format of the address. If the wallet is not connected, the hook will return an empty string. ```tsx import { useTonAddress } from '@tonconnect/ui-react'; export const Address = () => { - const userFriendlyAddress = useTonAddress(); - const rawAddress = useTonAddress(false); + const userFriendlyAddress = useTonAddress(); + const rawAddress = useTonAddress(false); + + return ( + userFriendlyAddress && ( +
+ User-friendly address: {userFriendlyAddress} + Raw address: {rawAddress} +
+ ) + ); +}; +``` + +### useTonConnectModal +Use this hook to access the functions for opening and closing the modal window. The hook returns an object with the current modal state and methods to open and close the modal. + +```tsx +import { useTonConnectModal } from '@tonconnect/ui-react'; + +export const ModalControl = () => { + const { state, open, close } = useTonConnectModal(); return ( - userFriendlyAddress && ( -
- User-friendly address: {userFriendlyAddress} - Raw address: {rawAddress} -
- ) +
+
Modal state: {state?.status}
+ + +
); }; ``` ### useTonWallet -Use it to get user's current ton wallet. If wallet is not connected hook will return null. +Use this hook to retrieve the user's current TON wallet. +If the wallet is not connected, the hook will return `null`. The `wallet` object provides common data such as the user's address, provider, [TON proof](/develop/dapps/ton-connect/sign), and other attributes (see the [Wallet interface](https://ton-connect.github.io/sdk/interfaces/_tonconnect_sdk.Wallet.html)). -See all wallet's properties +Additionally, you can access more specific details about the connected wallet, such as its name, image, and other attributes (refer to the [WalletInfo interface](https://ton-connect.github.io/sdk/types/_tonconnect_sdk.WalletInfo.html)). -[Wallet interface](https://ton-connect.github.io/sdk/interfaces/_tonconnect_sdk.Wallet.html) -[WalletInfo interface](https://ton-connect.github.io/sdk/types/_tonconnect_sdk.WalletInfo.html) ```tsx import { useTonWallet } from '@tonconnect/ui-react'; export const Wallet = () => { - const wallet = useTonWallet(); + const wallet = useTonWallet(); - return ( - wallet && ( -
- Connected wallet: {wallet.name} - Device: {wallet.device.appName} -
- ) - ); + return ( + wallet && ( +
+ Connected wallet address: {wallet.account.address} + Device: {wallet.device.appName} + Connected via: {wallet.provider} + {wallet.connectItems?.tonProof?.proof && Ton proof: {wallet.connectItems.tonProof.proof}} + +
Connected wallet info:
+
+ {wallet.name} +
+
+ ) + ); }; + ``` ### useTonConnectUI @@ -144,27 +193,21 @@ Use it to get access to the `TonConnectUI` instance and UI options updating func import { Locales, useTonConnectUI } from '@tonconnect/ui-react'; export const Settings = () => { - const [tonConnectUI, setOptions] = useTonConnectUI(); - - const onLanguageChange = (lang: string) => { - setOptions({ language: lang as Locales }); - }; - - return ( -
- - -
- - -
-
- ); + const [tonConnectUI, setOptions] = useTonConnectUI(); + + const onLanguageChange = (language: Locales) => { + setOptions({ language }); + }; + + return ( +
+ + +
+ ); }; ``` @@ -176,13 +219,13 @@ You can use it to detect when connection restoring process if finished. import { useIsConnectionRestored } from '@tonconnect/ui-react'; export const EntrypointPage = () => { - const connectionRestored = useIsConnectionRestored(); + const connectionRestored = useIsConnectionRestored(); - if (!connectionRestored) { - return Please wait...; - } + if (!connectionRestored) { + return Please wait...; + } - return ; + return ; }; ``` @@ -197,27 +240,29 @@ Send TON coins (in nanotons) to a specific address: ```js import { useTonConnectUI } from '@tonconnect/ui-react'; -const transaction = { - messages: [ - { - address: "0:412410771DA82CBA306A55FA9E0D43C9D245E38133CB58F1457DFB8D5CD8892F", // destination address - amount: "20000000" //Toncoin in nanotons - } - ] - -} +const transaction: SendTransactionRequest = { + validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes + messages: [ + { + address: + "0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-", // message destination in user-friendly format + amount: "20000000", // Toncoin in nanotons + }, + ], +}; export const Settings = () => { - const [tonConnectUI, setOptions] = useTonConnectUI(); - - return ( -
- -
- ); + const [tonConnectUI, setOptions] = useTonConnectUI(); + + return ( +
+ +
+ ); }; + ``` - Get more examples here: [Preparing Messages](/develop/dapps/ton-connect/message-builders) @@ -232,95 +277,368 @@ The principle located in Payment Processing (using tonweb). [See more](/develop/ Understand how to sign and verify messages: [Signing and Verification](/develop/dapps/ton-connect/sign) ::: -Use `tonConnectUI.setConnectRequestParameters` function to pass your connect request parameters. +To ensure that the user truly owns the declared address, you can use `ton_proof`. -This function takes one parameter: +Use the `tonConnectUI.setConnectRequestParameters` function to set up your connection request parameters. You can use it for: +- Loading State: Show a loading state while waiting for a response from your backend. +- Ready State with tonProof: Set the state to 'ready' and include the tonProof value. +- If an error occurs, remove the loader and create the connect request without additional parameters. -Set state to 'loading' while you are waiting for the response from your backend. If user opens connect wallet modal at this moment, he will see a loader. ```ts const [tonConnectUI] = useTonConnectUI(); -tonConnectUI.setConnectRequestParameters({ - state: 'loading' -}); +// Set loading state +tonConnectUI.setConnectRequestParameters({ state: "loading" }); + +// Fetch tonProofPayload from backend +const tonProofPayload: string | null = + await fetchTonProofPayloadFromBackend(); + +if (tonProofPayload) { + // Set ready state with tonProof + tonConnectUI.setConnectRequestParameters({ + state: "ready", + value: { tonProof: tonProofPayload }, + }); +} else { + // Remove loader + tonConnectUI.setConnectRequestParameters(null); +} ``` -or +#### Handling ton_proof Result -Set state to 'ready' and define `tonProof` value. Passed parameter will be applied to the connect request (QR and universal link). -```ts -const [tonConnectUI] = useTonConnectUI(); +You can find `ton_proof` result in the `wallet` object when the wallet is connected: -tonConnectUI.setConnectRequestParameters({ - state: 'ready', - value: { - tonProof: '' - } -}); +```ts +useEffect(() => { + tonConnectUI.onStatusChange((wallet) => { + if ( + wallet.connectItems?.tonProof && + "proof" in wallet.connectItems.tonProof + ) { + checkProofInYourBackend( + wallet.connectItems.tonProof.proof, + wallet.account.address + ); + } + }); + }, [tonConnectUI]); ``` -or +#### Structure of ton_proof -Remove loader if it was enabled via `state: 'loading'` (e.g. you received an error instead of a response from your backend). Connect request will be created without any additional parameters. ```ts +type TonProofItemReplySuccess = { + name: "ton_proof"; + proof: { + timestamp: string; // Unix epoch time (seconds) + domain: { + lengthBytes: number; // Domain length + value: string; // Domain name + }; + signature: string; // Base64-encoded signature + payload: string; // Payload from the request + } +} +``` + +You can find an example of authentication on this [page](/develop/dapps/ton-connect/sign#react-example) + +### Wallet Disconnection + +Call to disconnect the wallet: +```js const [tonConnectUI] = useTonConnectUI(); -tonConnectUI.setConnectRequestParameters(null); +await tonConnectUI.disconnect(); ``` +#### Deploying contract -You can call `tonConnectUI.setConnectRequestParameters` multiple times if your tonProof payload has bounded lifetime (e.g. you can refresh connect request parameters every 10 minutes). +Deploying contract using TonConnect is pretty straightforward. You just need to obtain contract code and state init, store it as a cell and send transaction with `stateInit` field provided. +Note, that `CONTRACT_CODE` and `CONTRACT_INIT_DATA` may be found in wrappers. + +```typescript +import { beginCell, Cell, contractAddress, StateInit, storeStateInit } from '@ton/core'; -```ts const [tonConnectUI] = useTonConnectUI(); -// enable ui loader -tonConnectUI.setConnectRequestParameters({ state: 'loading' }); +const init = { + code: Cell.fromBase64(''), + data: Cell.fromBase64('') +} satisfies StateInit; -// fetch you tonProofPayload from the backend -const tonProofPayload: string | null = await fetchTonProofPayloadFromBackend(); +const stateInit = beginCell() + .store(storeStateInit(init)) + .endCell(); -if (!tonProofPayload) { - // remove loader, connect request will be without any additional parameters - tonConnectUI.setConnectRequestParameters(null); -} else { - // add tonProof to the connect request - tonConnectUI.setConnectRequestParameters({ - state: "ready", - value: { tonProof: tonProofPayload } - }); -} +const address = contractAddress(0, init); + +await tonConnectUI.sendTransaction({ + validUntil: Date.now() + 5 * 60 * 1000, // 5 minutes + messages: [ + { + address: address.toRawString(), + amount: '5000000', + stateInit: stateInit.toBoc().toString('base64') + } + ] +}); ``` +## Wrappers -You can find `ton_proof` result in the `wallet` object when wallet will be connected: +Wrappers are classes that simplify interaction with the contract, allowing you to work without concerning yourself with the underlying details. + +- When developing a contract in `funC`, you need to write the wrapper yourself. +- When using the `Tact` language, wrappers are automatically generated for you. + +:::tip +Check out [blueprint](https://github.com/ton-org/blueprint) documentation how to develop and deploy contracts +::: + +Let's take a look at the default `Blueprint` Counter wrapper example and how we can use it: + +
+Wrapper usage +Counter wrapper class: ```ts -import {useTonConnectUI} from "@tonconnect/ui-react"; +import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core'; -const [tonConnectUI] = useTonConnectUI(); +export type CounterConfig = { + id: number; + counter: number; +}; + +export function counterConfigToCell(config: CounterConfig): Cell { + return beginCell().storeUint(config.id, 32).storeUint(config.counter, 32).endCell(); +} + +export const Opcodes = { + increase: 0x7e8764ef, +}; + +export class Counter implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell }, + ) {} + + static createFromAddress(address: Address) { + return new Counter(address); + } + + static createFromConfig(config: CounterConfig, code: Cell, workchain = 0) { + const data = counterConfigToCell(config); + const init = { code, data }; + return new Counter(contractAddress(workchain, init), init); + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().endCell(), + }); + } + + async sendIncrease( + provider: ContractProvider, + via: Sender, + opts: { + increaseBy: number; + value: bigint; + queryID?: number; + }, + ) { + await provider.internal(via, { + value: opts.value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell() + .storeUint(Opcodes.increase, 32) + .storeUint(opts.queryID ?? 0, 64) + .storeUint(opts.increaseBy, 32) + .endCell(), + }); + } + + async getCounter(provider: ContractProvider) { + const result = await provider.get('get_counter', []); + return result.stack.readNumber(); + } + + async getID(provider: ContractProvider) { + const result = await provider.get('get_id', []); + return result.stack.readNumber(); + } +} -useEffect(() => - tonConnectUI.onStatusChange(wallet => { - if (wallet.connectItems?.tonProof && 'proof' in wallet.connectItems.tonProof) { - checkProofInYourBackend(wallet.connectItems.tonProof.proof, wallet.account); - } - }), []); ``` +Then you can use this class in your react component: -### Wallet Disconnection +```ts -Call to disconnect the wallet: -```js -import { useTonConnectUI } from '@tonconnect/ui-react'; +import "buffer"; +import { + TonConnectUI, + useTonConnectUI, + useTonWallet, +} from "@tonconnect/ui-react"; +import { + Address, + beginCell, + Sender, + SenderArguments, + storeStateInit, + toNano, + TonClient, +} from "@ton/ton"; + +class TonConnectProvider implements Sender { + /** + * The TonConnect UI instance. + * @private + */ + private readonly provider: TonConnectUI; + + /** + * The address of the current account. + */ + public get address(): Address | undefined { + const address = this.provider.account?.address; + return address ? Address.parse(address) : undefined; + } + + /** + * Creates a new TonConnectProvider. + * @param provider + */ + public constructor(provider: TonConnectUI) { + this.provider = provider; + } + + /** + * Sends a message using the TonConnect UI. + * @param args + */ + public async send(args: SenderArguments): Promise { + // The transaction is valid for 10 minutes. + const validUntil = Math.floor(Date.now() / 1000) + 600; + + // The address of the recipient, should be in bounceable format for all smart contracts. + const address = args.to.toString({ urlSafe: true, bounceable: true }); + + // The address of the sender, if available. + const from = this.address?.toRawString(); + + // The amount to send in nano tokens. + const amount = args.value.toString(); + + // The state init cell for the contract. + let stateInit: string | undefined; + if (args.init) { + // State init cell for the contract. + const stateInitCell = beginCell() + .store(storeStateInit(args.init)) + .endCell(); + // Convert the state init cell to boc base64. + stateInit = stateInitCell.toBoc().toString("base64"); + } -const [tonConnectUI] = useTonConnectUI(); + // The payload for the message. + let payload: string | undefined; + if (args.body) { + // Convert the message body to boc base64. + payload = args.body.toBoc().toString("base64"); + } + + // Send the message using the TonConnect UI and wait for the message to be sent. + await this.provider.sendTransaction({ + validUntil: validUntil, + from: from, + messages: [ + { + address: address, + amount: amount, + stateInit: stateInit, + payload: payload, + }, + ], + }); + } +} + +const CONTRACT_ADDRESS = "EQAYLhGmznkBlPxpnOaGXda41eEkliJCTPF6BHtz8KXieLSc"; + +const getCounterInstance = async () => { + const client = new TonClient({ + endpoint: "https://testnet.toncenter.com/api/v2/jsonRPC", + }); + + // OR you can use createApi from @ton-community/assets-sdk + // import { + // createApi, + // } from "@ton-community/assets-sdk"; + + // const NETWORK = "testnet"; + // const client = await createApi(NETWORK); + + + const address = Address.parse(CONTRACT_ADDRESS); + const counterInstance = client.open(Counter.createFromAddress(address)); + + return counterInstance; +}; + +export const Header = () => { + const [tonConnectUI, setOptions] = useTonConnectUI(); + const wallet = useTonWallet(); + + const increaseCount = async () => { + const counterInstance = await getCounterInstance(); + const sender = new TonConnectProvider(tonConnectUI); + + await counterInstance.sendIncrease(sender, { + increaseBy: 1, + value: toNano("0.05"), + }); + }; + + const getCount = async () => { + const counterInstance = await getCounterInstance(); + + const count = await counterInstance.getCounter(); + console.log("count", count); + }; + + return ( +
+ {!wallet && ( + + )} + {wallet && ( + <> + + + + )} +
+ ); +}; -await tonConnectUI.disconnect(); ``` +
+ + +### Wrappers for Jettons and NFTs + +To interact with jettons or NFTs you can use [assets-sdk](https://github.com/ton-community/assets-sdk). +This SDK provides wrappers that simplify interaction with these assets. For practical examples, please check our [examples](https://github.com/ton-community/assets-sdk/tree/main/examples) section. ## API Documentation diff --git a/sidebars.js b/sidebars.js index 823d2ffbd1..08e61aaf58 100644 --- a/sidebars.js +++ b/sidebars.js @@ -425,15 +425,10 @@ const sidebars = { label: 'Advanced', items: [ { - type: 'doc', - label: 'TON Connect Protocol', - id: 'develop/dapps/ton-connect/protocol/README', + type: 'link', + label: 'Protocol specification', + href: 'https://github.com/ton-blockchain/ton-connect', }, - 'develop/dapps/ton-connect/protocol/workflow', - 'develop/dapps/ton-connect/protocol/bridge', - 'develop/dapps/ton-connect/protocol/session', - 'develop/dapps/ton-connect/protocol/requests-responses', - 'develop/dapps/ton-connect/protocol/wallet-guidelines', { type: 'link', label: 'Wallets List', diff --git a/src/components/RedirectPage.tsx b/src/components/RedirectPage.tsx new file mode 100644 index 0000000000..4443ddf876 --- /dev/null +++ b/src/components/RedirectPage.tsx @@ -0,0 +1,14 @@ +import React, { useEffect } from 'react' + +const RedirectPage = ({ redirectUrl}: { redirectUrl: string }) => { + // redirect here because current version of docusaurus doesn't support redirect for external links + useEffect(() => { + window.location.href = redirectUrl; + }, []) + + return ( +
+ ) +} + +export default RedirectPage \ No newline at end of file diff --git a/src/pages/develop/dapps/ton-connect/protocol/bridge.tsx b/src/pages/develop/dapps/ton-connect/protocol/bridge.tsx new file mode 100644 index 0000000000..ebb07b3c3f --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/bridge.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page; diff --git a/src/pages/develop/dapps/ton-connect/protocol/index.tsx b/src/pages/develop/dapps/ton-connect/protocol/index.tsx new file mode 100644 index 0000000000..f227e84bcd --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/index.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page; diff --git a/src/pages/develop/dapps/ton-connect/protocol/requests-responses.tsx b/src/pages/develop/dapps/ton-connect/protocol/requests-responses.tsx new file mode 100644 index 0000000000..ff202548ab --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/requests-responses.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page; diff --git a/src/pages/develop/dapps/ton-connect/protocol/session.tsx b/src/pages/develop/dapps/ton-connect/protocol/session.tsx new file mode 100644 index 0000000000..d8de7c3415 --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/session.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page; diff --git a/src/pages/develop/dapps/ton-connect/protocol/wallet-guidelines.tsx b/src/pages/develop/dapps/ton-connect/protocol/wallet-guidelines.tsx new file mode 100644 index 0000000000..77262af840 --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/wallet-guidelines.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page; diff --git a/src/pages/develop/dapps/ton-connect/protocol/workflow.tsx b/src/pages/develop/dapps/ton-connect/protocol/workflow.tsx new file mode 100644 index 0000000000..574984985b --- /dev/null +++ b/src/pages/develop/dapps/ton-connect/protocol/workflow.tsx @@ -0,0 +1,6 @@ +import RedirectPage from '@site/src/components/RedirectPage'; +import React from 'react'; + +const Page = () => + +export default Page;