- App initiates SSE connection with bridge;
- App passes connection info to the wallet via universal link or deeplink or QR code;
- Wallet connects to the bridge with given parameters, and save connection info locally;
- Wallet sends account information to the app using bridge;
- App receives message and save connection info locally;
- App reads connection info from localstorage
- App connects to the bridge
- User opens the wallet, the wallet connects to the bridge using stored connection info
- App checks existing of the
window.[walletJsBridgeKey].tonconnect
- App calls
window.[walletJsBridgeKey].tonconnect.connect()
and waits for a response - Wallet sends account information to the app;
- App and wallet are in a connected state
- App generates request and sends it to the bridge
- Bridge forwards message to the wallet
- Wallet generates response and sends it to the bridge
- Bridge forwards message to the app
User clicks button “Connect Wallet” in the app.
App creates app’s Client Keypair (a, A):
(a,A) <- nacl.box.keyPair()
App generates the InitialRequest. See requests spec.
App creates a universal link to a target wallet:
https://<wallet-universal-url>?v=2&id=<to_hex_str(A)>&r=<urlsafe(json.stringify(ConnectRequest))>
When using the JS bridge, the same request is sent via the connect()
call:
window.[walletJsBridgeKey].tonconnect.connect(2, <InitialRequest>)
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.
The link may be embedded in a QR code or clicked directly.
App connects to the bridge (link to bridge api) and listens for events using its Client ID A.
App is not yet in the connected state, and may restart the whole process at any moment.
Wallet opens up a link or QR code, reads plaintext app’s Client ID (A from parameter “id”) and InitialRequest (from parameter “r”).
Wallet computes the InitialResponse.
Wallet generates its own Client Keypair (b,B) and stores alongside app’s info and ID.
Wallet encrypts the response and sends it to the Bridge using app’s Client ID A.
Wallet connects to the bridge (link to bridge api) and listens for events using its Client ID B.
App receives the event from the bridge that contains the encrypted message from the Client ID B.
App decrypts the message and parses it as InitialResponse.
If the reply is valid, App reads wallet info (address, public key, proof of ownership etc.) and remembers the wallet’s ID B.
The session is considered established in the app when it has the wallet’s ID and can send requests directly to it through the bridge.
When the user performs an action in the app, it may request confirmation from the wallet.
App generates a request.
App encrypts it to the wallet’s key B (see below).
App sends the encrypted message to B over the Bridge.
App shows “pending confirmation” UI to let user know to open the wallet.
Wallet receives the encrypted message through the Bridge.
Wallet decrypts the message and is now assured that it came from the app with ID A.
Wallet shows the confirmation dialog to the user, signs transaction and replies over the bridge with user’s decision: “Ok, sent” or “User cancelled”.
App receives the encrypted message, decrypts it and closes the “pending confirmation” UI.