Skip to content

TonConnect

TonConnect 是一个链接钱包和 DApps(Web3 应用程序)的开放协议,它使用一个桥梁(JS Bridge 或者 Http Bridge)在两个应用程序和/或设备之间建立链接,并开始通信。

Bitget Wallet 已完全支持 TonConnect。

TonConnect 的交互形式

  1. 通过桌面版浏览器访问 DApp,可选择插件连接和二维码,如未安装插件钱包则跳转插件钱包下载页,也可通过手机端钱包 App 扫码链接。
  2. 在手机端钱包 App 中打开 DApp,如果支持则直接链接钱包,否则会打开对应钱包的下载页。
  3. 在手机端非钱包 App(包括手机端浏览器) 中打开 DApp 时,会通过 deeplink 打开钱包 App。

安装

bash
#Add @tonconnect/ui package, up to latest
npm i @tonconnect/ui
#Add @tonconnect/ui package, up to latest
npm i @tonconnect/ui

开发示例

TonConnect Demo 完整代码

*通过设置 walletsListConfiguration.includeWallets 的值来将自定义钱包添加进wallets-list。
*使用 await tonConnectUI.openSingleWalletModal("bitgetTonWallet") 连接指定单钱包。

js
import { TonConnectUI } from "@tonconnect/ui";
import React, { useState } from "react";

//Instantiate TonConnect
const tonConnectUI = new TonConnectUI({
  manifestUrl: "https://<YOUR_APP_URL>/tonconnect-manifest.json",
  buttonRootId: "<YOUR_CONNECT_BUTTON_ANCHOR_ID>",
  /**
   * Add custom wallet to wallets list
   */
  walletsListConfiguration: {
    includeWallets: [
      {
        name: "Bitget Wallet",
        appName: "bitgetTonWallet",
        imageUrl:
          "https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png",
        deepLink: "bitkeep://",
        universalLink: "https://bkcode.vip/ton-connect",
        bridgeUrl: "https://bridge.tonapi.io/bridge",
        platforms: ["ios", "android", "chrome"],
      },
    ],
  },
  // connector: "your tonConnect instance",
  //...
});

//Change options if needed
tonConnectUI.uiOptions = {
  language: "en",
  uiPreferences: {
    theme: THEME.DARK,
  },
};

//Get wallet list
const walletsList = await tonConnectUI.getWallets();
/* walletsList is 
{
    name: string;
    imageUrl: string;
    tondns?: string;
    aboutUrl: string;
    universalLink?: string;
    deepLink?: string;
    bridgeUrl?: string;
    jsBridgeKey?: string;
    injected?: boolean; // true if this wallet is injected to the webpage
    embedded?: boolean; // true if the dapp is opened inside this wallet's browser
}[] 
 */

//Open wallet selection list
await tonConnectUI.openModal();

//Close wallet selection list
tonConnectUI.closeModal();

//Get the current modal status
const currentModalState = tonConnectUI.modalState;

//Subscribe to modal window state changes
const unsubscribeModal = tonConnectUI.onModalStateChange(
  (state: WalletsModalState) => {
    // update state/reactive variables to show updates in the ui
    // state.status will be 'opened' or 'closed'
    // if state.status is 'closed', you can check state.closeReason to find out the reason
  }
);

//Specify the connection wallet
await tonConnectUI.openSingleWalletModal("bitgetTonWallet");

tonConnectUI.closeSingleWalletModal();

const unsubscribe = tonConnectUI.onSingleWalletModalStateChange((state) => {
  console.log("Modal state changed:", state);
});

// Call `unsubscribe` when you want to stop listening to the state changes
unsubscribe();

//Get the currently connected Wallet and WalletInfo
const currentWallet = tonConnectUI.wallet;
const currentWalletInfo = tonConnectUI.walletInfo;
const currentAccount = tonConnectUI.account;
const currentIsConnectedStatus = tonConnectUI.connected;

//Subscribe to connection status changes
const unsubscribe = tonConnectUI.onStatusChange((walletAndwalletInfo) => {
  // update state/reactive variables to show updates in the ui
});

//disconnect
await tonConnectUI.disconnect();

//Send transaction
const transaction = {
  validUntil: Math.floor(Date.now() / 1000) + 60, // 60 sec
  messages: [
    {
      address: "EQBBJBB3HagsujBqVfqeDUPJ0kXjgTPLWPFFffuNXNiJL0aA",
      amount: "20000000",
      // stateInit: "base64bocblahblahblah==" // just for instance. Replace with your transaction initState or remove
    },
    {
      address: "EQDmnxDMhId6v1Ofg_h5KR5coWlFG6e86Ro3pc7Tq4CA0-Jn",
      amount: "60000000",
      // payload: "base64bocblahblahblah==" // just for instance. Replace with your transaction payload or remove
    },
  ],
};

try {
  const result = await tonConnectUI.sendTransaction(transaction);
  // you can use signed boc to find the transaction
  const someTxData = await myAppExplorerService.getTransaction(result.boc);
  alert("Transaction was sent successfully", someTxData);
} catch (e) {
  console.error(e);
}

//Used within TMA (Telegram Mini App)
//The TonConnect UI works the same way in TMA as it does in a regular website! Basically, dApp developers don’t need to make any changes. The only thing you need to set up is a dynamic return strategy. Currently, it is not possible for TMA wallets to redirect back to a previously opened TMA-dApp like the native wallet app does. This means that you need to specify the return policy as a link to the TMA, which is only applied when the dApp is opened in TMA mode.
tonConnectUI.uiOptions = {
  twaReturnUrl: "https://t.me/durov",
};

//Add a connection request parameter (ton_proof) to set the status to "ready" and define the tonProof value. The parameters passed will be applied to connection requests (QR and Universal Links). Remove the loader if it is enabled with status "Loading" (e.g. you get an error instead of a response from the backend). A connection request will be created without any additional parameters.
tonConnectUI.setConnectRequestParameters({
  state: "loading",
});
tonConnectUI.setConnectRequestParameters({
  state: "ready",
  value: {
    tonProof: "<your-proof-payload>",
  },
});
tonConnectUI.setConnectRequestParameters(null);

// fetch you tonProofPayload from the backend
const tonProofPayload: string | null = await fetchTonProofPayloadFromBackend();

if (!tonProofPayload) {
  tonConnectUI.setConnectRequestParameters(null);
} else {
  tonConnectUI.setConnectRequestParameters({
    state: "ready",
    value: { tonProof: tonProofPayload },
  });
}

//When the wallet is connected, you can find the ton_proof result in the wallet object:
tonConnectUI.onStatusChange((wallet) => {
  if (
    wallet &&
    wallet.connectItems?.tonProof &&
    "proof" in wallet.connectItems.tonProof
  ) {
    checkProofInYourBackend(wallet.connectItems.tonProof.proof);
  }
});
import { TonConnectUI } from "@tonconnect/ui";
import React, { useState } from "react";

//Instantiate TonConnect
const tonConnectUI = new TonConnectUI({
  manifestUrl: "https://<YOUR_APP_URL>/tonconnect-manifest.json",
  buttonRootId: "<YOUR_CONNECT_BUTTON_ANCHOR_ID>",
  /**
   * Add custom wallet to wallets list
   */
  walletsListConfiguration: {
    includeWallets: [
      {
        name: "Bitget Wallet",
        appName: "bitgetTonWallet",
        imageUrl:
          "https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png",
        deepLink: "bitkeep://",
        universalLink: "https://bkcode.vip/ton-connect",
        bridgeUrl: "https://bridge.tonapi.io/bridge",
        platforms: ["ios", "android", "chrome"],
      },
    ],
  },
  // connector: "your tonConnect instance",
  //...
});

//Change options if needed
tonConnectUI.uiOptions = {
  language: "en",
  uiPreferences: {
    theme: THEME.DARK,
  },
};

//Get wallet list
const walletsList = await tonConnectUI.getWallets();
/* walletsList is 
{
    name: string;
    imageUrl: string;
    tondns?: string;
    aboutUrl: string;
    universalLink?: string;
    deepLink?: string;
    bridgeUrl?: string;
    jsBridgeKey?: string;
    injected?: boolean; // true if this wallet is injected to the webpage
    embedded?: boolean; // true if the dapp is opened inside this wallet's browser
}[] 
 */

//Open wallet selection list
await tonConnectUI.openModal();

//Close wallet selection list
tonConnectUI.closeModal();

//Get the current modal status
const currentModalState = tonConnectUI.modalState;

//Subscribe to modal window state changes
const unsubscribeModal = tonConnectUI.onModalStateChange(
  (state: WalletsModalState) => {
    // update state/reactive variables to show updates in the ui
    // state.status will be 'opened' or 'closed'
    // if state.status is 'closed', you can check state.closeReason to find out the reason
  }
);

//Specify the connection wallet
await tonConnectUI.openSingleWalletModal("bitgetTonWallet");

tonConnectUI.closeSingleWalletModal();

const unsubscribe = tonConnectUI.onSingleWalletModalStateChange((state) => {
  console.log("Modal state changed:", state);
});

// Call `unsubscribe` when you want to stop listening to the state changes
unsubscribe();

//Get the currently connected Wallet and WalletInfo
const currentWallet = tonConnectUI.wallet;
const currentWalletInfo = tonConnectUI.walletInfo;
const currentAccount = tonConnectUI.account;
const currentIsConnectedStatus = tonConnectUI.connected;

//Subscribe to connection status changes
const unsubscribe = tonConnectUI.onStatusChange((walletAndwalletInfo) => {
  // update state/reactive variables to show updates in the ui
});

//disconnect
await tonConnectUI.disconnect();

//Send transaction
const transaction = {
  validUntil: Math.floor(Date.now() / 1000) + 60, // 60 sec
  messages: [
    {
      address: "EQBBJBB3HagsujBqVfqeDUPJ0kXjgTPLWPFFffuNXNiJL0aA",
      amount: "20000000",
      // stateInit: "base64bocblahblahblah==" // just for instance. Replace with your transaction initState or remove
    },
    {
      address: "EQDmnxDMhId6v1Ofg_h5KR5coWlFG6e86Ro3pc7Tq4CA0-Jn",
      amount: "60000000",
      // payload: "base64bocblahblahblah==" // just for instance. Replace with your transaction payload or remove
    },
  ],
};

try {
  const result = await tonConnectUI.sendTransaction(transaction);
  // you can use signed boc to find the transaction
  const someTxData = await myAppExplorerService.getTransaction(result.boc);
  alert("Transaction was sent successfully", someTxData);
} catch (e) {
  console.error(e);
}

//Used within TMA (Telegram Mini App)
//The TonConnect UI works the same way in TMA as it does in a regular website! Basically, dApp developers don’t need to make any changes. The only thing you need to set up is a dynamic return strategy. Currently, it is not possible for TMA wallets to redirect back to a previously opened TMA-dApp like the native wallet app does. This means that you need to specify the return policy as a link to the TMA, which is only applied when the dApp is opened in TMA mode.
tonConnectUI.uiOptions = {
  twaReturnUrl: "https://t.me/durov",
};

//Add a connection request parameter (ton_proof) to set the status to "ready" and define the tonProof value. The parameters passed will be applied to connection requests (QR and Universal Links). Remove the loader if it is enabled with status "Loading" (e.g. you get an error instead of a response from the backend). A connection request will be created without any additional parameters.
tonConnectUI.setConnectRequestParameters({
  state: "loading",
});
tonConnectUI.setConnectRequestParameters({
  state: "ready",
  value: {
    tonProof: "<your-proof-payload>",
  },
});
tonConnectUI.setConnectRequestParameters(null);

// fetch you tonProofPayload from the backend
const tonProofPayload: string | null = await fetchTonProofPayloadFromBackend();

if (!tonProofPayload) {
  tonConnectUI.setConnectRequestParameters(null);
} else {
  tonConnectUI.setConnectRequestParameters({
    state: "ready",
    value: { tonProof: tonProofPayload },
  });
}

//When the wallet is connected, you can find the ton_proof result in the wallet object:
tonConnectUI.onStatusChange((wallet) => {
  if (
    wallet &&
    wallet.connectItems?.tonProof &&
    "proof" in wallet.connectItems.tonProof
  ) {
    checkProofInYourBackend(wallet.connectItems.tonProof.proof);
  }
});

相关阅读