Skip to content

TonConnect

TonConnect

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

TonConnect 的交互形式

Dapp 接入Bitget Wallet后,根据场景的不同以下几种交互形式:

Telegram Mini App

若 Dapp 提供了 Telegram Mini App,用户可访问 Telegram Mini App 中的 Dapp

  1. 可选择使用Bitget Wallet APP,会通过 deeplink 打开Bitget Wallet APP进行链接,否则会打开对应钱包的下载页
  2. 可选择使用Bitget Wallet Lite,Telegram 会拉起Bitget Wallet Lite Mini App 进行链接
  3. (即将到来...)若 Dapp 注册到了Bitget Wallet Lite Dapp 中心,那么即使 Dapp 未提供Telegram Mini App,用户也可通过 Bitget Wallet Lite 的Dapp 中心访问该Dapp,并进行钱包链接交互

移动端 Dapp

若 Dapp 提供了移动端的适配版本,用户可通过手机端访问Dapp

  1. 可选择在 Bitget Wallet中打开 DApp,并直接与Bitget Wallet建立链接
  2. 也可在手机端非Bitget Wallet APP(包括手机端浏览器) 中打开 DApp 时,会通过 deeplink 打开Bitget Wallet APP进行链接,否则会打开对应钱包的下载页

PC 端Dapp

若 Dapp 提供了PC端的适配版本,用户可通过桌面版浏览器访问 DApp

  1. 可选择Bitget Wallet Chrome Extension连接,如未安装插件钱包则跳转插件钱包下载页
  2. 也可以选择使用Bitget Wallet APPBitget Wallet Lite扫描二维码链接

集成指南

接下来会介绍如何在 Dapp 中集成Bitget Wallet,通过一次配置,将同时完成Bitget WalletBitget Wallet Chrome ExtensionBitget Wallet Lite 的集成

安装

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

开发示例

有两个配置方法可以将 Bitget WalletBitget Wallet Lite 配置到 Ton Connect 的钱包链接选项中:

  1. 通过设置 walletsListConfiguration.includeWallets的以下示例代码中的值来完成配置
    • 可在钱包链接弹框里,展示出Bitget WalletBitget Wallet Lite的钱包入口
    • 对于已经集成过Bitget Wallet 的Dapp,直接更新以下配置,即可完成Bitget Wallet Lite 接入
js
includeWallets: [
    {
    appName: "bitgetWalletLite",
    name: "Bitget Wallet Lite",
    imageUrl: "https://raw.githubusercontent.com/bitgetwallet/download/main/logo/png/bitget_wallet_lite_logo.png",
    aboutUrl: "https://web3.bitget.com",
    universalLink: "https://t.me/BitgetWallet_TGBot?attach=wallet",
    bridgeUrl: "https://ton-connect-bridge.bgwapi.io/bridge",
    platforms: ["ios", "android", "macos", "windows", "linux"]
    },
    {
    name: "Bitget Wallet",
    appName: "bitgetTonWallet",
    jsBridgeKey: "bitgetTonWallet",
    imageUrl:
        "https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png",
    aboutUrl: "https://web3.bitget.com",
    bridgeUrl: "https://ton-connect-bridge.bgwapi.io/bridge",
    universalLink: "https://bkcode.vip/ton-connect",
    deepLink: "bitkeep://",
    platforms: ["ios", "android", "chrome"],
    },
]
includeWallets: [
    {
    appName: "bitgetWalletLite",
    name: "Bitget Wallet Lite",
    imageUrl: "https://raw.githubusercontent.com/bitgetwallet/download/main/logo/png/bitget_wallet_lite_logo.png",
    aboutUrl: "https://web3.bitget.com",
    universalLink: "https://t.me/BitgetWallet_TGBot?attach=wallet",
    bridgeUrl: "https://ton-connect-bridge.bgwapi.io/bridge",
    platforms: ["ios", "android", "macos", "windows", "linux"]
    },
    {
    name: "Bitget Wallet",
    appName: "bitgetTonWallet",
    jsBridgeKey: "bitgetTonWallet",
    imageUrl:
        "https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png",
    aboutUrl: "https://web3.bitget.com",
    bridgeUrl: "https://ton-connect-bridge.bgwapi.io/bridge",
    universalLink: "https://bkcode.vip/ton-connect",
    deepLink: "bitkeep://",
    platforms: ["ios", "android", "chrome"],
    },
]
  1. 更推荐的方法是,通过调用以下代码,直接指定连接 Bitget Wallet,效果如下图:
await tonConnectUI.openSingleWalletModal("bitgetTonWallet") // 直接链接 Bitget Wallet 

await tonConnectUI.openSingleWalletModal("bitgetWalletLite") // 直接链接 Bitget Wallet Lite
await tonConnectUI.openSingleWalletModal("bitgetTonWallet") // 直接链接 Bitget Wallet 

await tonConnectUI.openSingleWalletModal("bitgetWalletLite") // 直接链接 Bitget Wallet Lite

Bitget Wallet

Bitget Wallet Lite

以下是代码示例:

TonConnect Demo 完整代码

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

const tonConnectUI = new TonConnectUI({
  manifestUrl: "https://app.ston.fi/tonconnect-manifest.json",
  walletsListConfiguration: {
    includeWallets: [
      {
        appName: 'bitgetWalletLite',
        name: 'Bitget Wallet Lite',
        imageUrl:
          'https://raw.githubusercontent.com/bitgetwallet/download/main/logo/png/bitget_wallet_lite_logo.png',
        aboutUrl: 'https://web3.bitget.com',
        universalLink: 'https://t.me/BitgetWallet_TGBot?attach=wallet',
        bridgeUrl: 'https://ton-connect-bridge.bgwapi.io/bridge',
        platforms: ['ios', 'android', 'macos', 'windows', 'linux'],
      },
      {
        name: 'Bitget Wallet',
        appName: 'bitgetTonWallet',
        jsBridgeKey: 'bitgetTonWallet',
        imageUrl:
          'https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png',
        aboutUrl: 'https://web3.bitget.com',
        bridgeUrl: 'https://ton-connect-bridge.bgwapi.io/bridge',
        universalLink: 'https://bkcode.vip/ton-connect',
        deepLink: 'bitkeep://',
        platforms: ['ios', 'android', 'chrome'],
      },
    ],
  },
});

// uiOptions
tonConnectUI.uiOptions = {
  language: 'en', // type Locales
  uiPreferences: {
      theme: THEME.DARK
  },
  actionsConfiguration: {
     /**
     * Specifies return url for TMA connections.
     * This will be applied as a return strategy if dApp is opened as a TMA and user selects TMA wallet (overrides `returnStrategy` if).
     */
     twaReturnUrl: "https://t.me/<YOUR TMA APP>",
  }
};

export default function TonConnectDApp() {
  const [currentInfo, setCurrentInfo] = useState({});
  const [proof, setProof] = useState('');

  const getWallets = async () => await tonConnectUI.getWallets();

  const openModal = async () => await tonConnectUI.openModal();
  const closeModal = async () => tonConnectUI.closeModal();
  const openBitgetWalletLite = async () => {
    if(tonConnectUI.connected) {
      await disconnect()
    }
    await tonConnectUI.openSingleWalletModal("bitgetWalletLite");
  }
  const openBitgetTonWallet = async () => {
    if(tonConnectUI.connected) {
      await disconnect()
    }
    await tonConnectUI.openSingleWalletModal("bitgetTonWallet");
  }

  const currentWallet = () => tonConnectUI.wallet;
  const currentWalletInfo = () => tonConnectUI.walletInfo;

  const currentAccount = () => tonConnectUI.account;
  const currentIsConnectedStatus = () => tonConnectUI.connected;
  const disconnect = async () => await tonConnectUI.disconnect();
  
  const onStatusChange = async () => {
    const unsubscribe = tonConnectUI.onStatusChange((walletInfo) => {
      console.log("walletInfo", walletInfo);
    });
    return unsubscribe;
  };

  const onModalChange = async () => {
    const unsubscribe = tonConnectUI.onModalStateChange((WalletsModalState) => {
      console.log("WalletsModalState", WalletsModalState);
    });
    return unsubscribe;
  };

  const sendTransaction = async () => {
    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
        },
      ],
    };
    return await tonConnectUI.sendTransaction(transaction);
  };

  useEffect(() => {
    // update tonProof when refresh
    setProof(localStorage.getItem("tonProof") ?? '');
  }, [])

  useEffect(() => {
    tonConnectUI.onStatusChange((wallet) => {
      // get tonProof
      // When the wallet is connected, you can find the ton_proof result in the wallet object
      console.log('onStatusChange:', wallet)
      if (wallet?.connectItems?.tonProof && 'proof' in wallet.connectItems.tonProof) {
        // do something with tonProof
        // checkProofInYourBackend(wallet.connectItems.tonProof.proof)
        localStorage.setItem('tonProof', JSON.stringify(wallet.connectItems.tonProof.proof))
        setProof(JSON.stringify(wallet.connectItems.tonProof.proof))
      }
    })
  }, [])

  // connect and get proof
  const connectToGetProof = async () => {
   console.log('isConnected:', tonConnectUI.connected, tonConnectUI.account)
   if(tonConnectUI.connected) {
     await disconnect()
     localStorage.removeItem('tonProof')
     setProof('')
   }
    try {
      // enable ui loader
      tonConnectUI.setConnectRequestParameters({
        state: 'loading'
      })
      // payload message for proof
      const messageJson = {
        user_id: "testUserID",
        amount: 10
      }
      // to hex string
      const payload = Buffer.from(JSON.stringify(messageJson), 'utf-8').toString('hex')
      // add tonProof to the connect request
      tonConnectUI.setConnectRequestParameters({
        state: 'ready',
        value: { tonProof: payload }
      })
      // connect
      // You can find ton_proof result in the wallet object when wallet will be connected
      tonConnectUI.openSingleWalletModal('bitgetTonWallet')
      // or
      // await tonConnectUI.openSingleWalletModal("bitgetWalletLite");
    } catch (error) {
      console.log(error)
    }
  }

  const funcNames = [
    "openBitgetWalletLite",
    "openBitgetTonWallet",
    "openModal",
    "closeModal",
    "currentWallet",
    "currentWalletInfo",
    "currentAccount",
    "currentIsConnectedStatus",
    "disconnect",
    "getWallets",
    "onStatusChange",
    "onModalChange",
    "sendTransaction",
    "getProof",
  ];
  return (
    <>
      <h2>Ton Connect DApp Demo</h2>
      <div style={{ display: "flex", flexWrap: 'wrap', gap: 20, marginBottom: 20 }}>
        {[
          openBitgetWalletLite,
          openBitgetTonWallet,
          openModal,
          closeModal,
          currentWallet,
          currentWalletInfo,
          currentAccount,
          currentIsConnectedStatus,
          disconnect,
          getWallets,
          onStatusChange,
          onModalChange,
          sendTransaction,
        ].map((func, index) => (
          <div key={index}>
            <button
              onClick={async () => {
                try {
                  setCurrentInfo({
                    "function name": func.name,
                    "function returns": await func(),
                  });
                } catch (e) {
                  console.error(e);
                }
              }}
            >
              {`${func?.name || funcNames[index]} Button`}
            </button>
          </div>
        ))}
      <button style={{width: 'fit-content'}} onClick={connectToGetProof}>connectToGetProof</button>
      </div>
      {Object.keys(currentInfo).map((k) => (
        <div key={k} style={{ wordWrap: "break-word" }}>
          {k}: {JSON.stringify(currentInfo[k])}
        </div>
      ))}
      {proof && <p style={{ wordWrap: "break-word" }}>proof: {proof}</p>}
    </>
  );
}
import { TonConnectUI, THEME } from "@tonconnect/ui";
import React, { useState, useEffect } from "react";

const tonConnectUI = new TonConnectUI({
  manifestUrl: "https://app.ston.fi/tonconnect-manifest.json",
  walletsListConfiguration: {
    includeWallets: [
      {
        appName: 'bitgetWalletLite',
        name: 'Bitget Wallet Lite',
        imageUrl:
          'https://raw.githubusercontent.com/bitgetwallet/download/main/logo/png/bitget_wallet_lite_logo.png',
        aboutUrl: 'https://web3.bitget.com',
        universalLink: 'https://t.me/BitgetWallet_TGBot?attach=wallet',
        bridgeUrl: 'https://ton-connect-bridge.bgwapi.io/bridge',
        platforms: ['ios', 'android', 'macos', 'windows', 'linux'],
      },
      {
        name: 'Bitget Wallet',
        appName: 'bitgetTonWallet',
        jsBridgeKey: 'bitgetTonWallet',
        imageUrl:
          'https://raw.githubusercontent.com/bitkeepwallet/download/main/logo/png/bitget%20wallet_logo_iOS.png',
        aboutUrl: 'https://web3.bitget.com',
        bridgeUrl: 'https://ton-connect-bridge.bgwapi.io/bridge',
        universalLink: 'https://bkcode.vip/ton-connect',
        deepLink: 'bitkeep://',
        platforms: ['ios', 'android', 'chrome'],
      },
    ],
  },
});

// uiOptions
tonConnectUI.uiOptions = {
  language: 'en', // type Locales
  uiPreferences: {
      theme: THEME.DARK
  },
  actionsConfiguration: {
     /**
     * Specifies return url for TMA connections.
     * This will be applied as a return strategy if dApp is opened as a TMA and user selects TMA wallet (overrides `returnStrategy` if).
     */
     twaReturnUrl: "https://t.me/<YOUR TMA APP>",
  }
};

export default function TonConnectDApp() {
  const [currentInfo, setCurrentInfo] = useState({});
  const [proof, setProof] = useState('');

  const getWallets = async () => await tonConnectUI.getWallets();

  const openModal = async () => await tonConnectUI.openModal();
  const closeModal = async () => tonConnectUI.closeModal();
  const openBitgetWalletLite = async () => {
    if(tonConnectUI.connected) {
      await disconnect()
    }
    await tonConnectUI.openSingleWalletModal("bitgetWalletLite");
  }
  const openBitgetTonWallet = async () => {
    if(tonConnectUI.connected) {
      await disconnect()
    }
    await tonConnectUI.openSingleWalletModal("bitgetTonWallet");
  }

  const currentWallet = () => tonConnectUI.wallet;
  const currentWalletInfo = () => tonConnectUI.walletInfo;

  const currentAccount = () => tonConnectUI.account;
  const currentIsConnectedStatus = () => tonConnectUI.connected;
  const disconnect = async () => await tonConnectUI.disconnect();
  
  const onStatusChange = async () => {
    const unsubscribe = tonConnectUI.onStatusChange((walletInfo) => {
      console.log("walletInfo", walletInfo);
    });
    return unsubscribe;
  };

  const onModalChange = async () => {
    const unsubscribe = tonConnectUI.onModalStateChange((WalletsModalState) => {
      console.log("WalletsModalState", WalletsModalState);
    });
    return unsubscribe;
  };

  const sendTransaction = async () => {
    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
        },
      ],
    };
    return await tonConnectUI.sendTransaction(transaction);
  };

  useEffect(() => {
    // update tonProof when refresh
    setProof(localStorage.getItem("tonProof") ?? '');
  }, [])

  useEffect(() => {
    tonConnectUI.onStatusChange((wallet) => {
      // get tonProof
      // When the wallet is connected, you can find the ton_proof result in the wallet object
      console.log('onStatusChange:', wallet)
      if (wallet?.connectItems?.tonProof && 'proof' in wallet.connectItems.tonProof) {
        // do something with tonProof
        // checkProofInYourBackend(wallet.connectItems.tonProof.proof)
        localStorage.setItem('tonProof', JSON.stringify(wallet.connectItems.tonProof.proof))
        setProof(JSON.stringify(wallet.connectItems.tonProof.proof))
      }
    })
  }, [])

  // connect and get proof
  const connectToGetProof = async () => {
   console.log('isConnected:', tonConnectUI.connected, tonConnectUI.account)
   if(tonConnectUI.connected) {
     await disconnect()
     localStorage.removeItem('tonProof')
     setProof('')
   }
    try {
      // enable ui loader
      tonConnectUI.setConnectRequestParameters({
        state: 'loading'
      })
      // payload message for proof
      const messageJson = {
        user_id: "testUserID",
        amount: 10
      }
      // to hex string
      const payload = Buffer.from(JSON.stringify(messageJson), 'utf-8').toString('hex')
      // add tonProof to the connect request
      tonConnectUI.setConnectRequestParameters({
        state: 'ready',
        value: { tonProof: payload }
      })
      // connect
      // You can find ton_proof result in the wallet object when wallet will be connected
      tonConnectUI.openSingleWalletModal('bitgetTonWallet')
      // or
      // await tonConnectUI.openSingleWalletModal("bitgetWalletLite");
    } catch (error) {
      console.log(error)
    }
  }

  const funcNames = [
    "openBitgetWalletLite",
    "openBitgetTonWallet",
    "openModal",
    "closeModal",
    "currentWallet",
    "currentWalletInfo",
    "currentAccount",
    "currentIsConnectedStatus",
    "disconnect",
    "getWallets",
    "onStatusChange",
    "onModalChange",
    "sendTransaction",
    "getProof",
  ];
  return (
    <>
      <h2>Ton Connect DApp Demo</h2>
      <div style={{ display: "flex", flexWrap: 'wrap', gap: 20, marginBottom: 20 }}>
        {[
          openBitgetWalletLite,
          openBitgetTonWallet,
          openModal,
          closeModal,
          currentWallet,
          currentWalletInfo,
          currentAccount,
          currentIsConnectedStatus,
          disconnect,
          getWallets,
          onStatusChange,
          onModalChange,
          sendTransaction,
        ].map((func, index) => (
          <div key={index}>
            <button
              onClick={async () => {
                try {
                  setCurrentInfo({
                    "function name": func.name,
                    "function returns": await func(),
                  });
                } catch (e) {
                  console.error(e);
                }
              }}
            >
              {`${func?.name || funcNames[index]} Button`}
            </button>
          </div>
        ))}
      <button style={{width: 'fit-content'}} onClick={connectToGetProof}>connectToGetProof</button>
      </div>
      {Object.keys(currentInfo).map((k) => (
        <div key={k} style={{ wordWrap: "break-word" }}>
          {k}: {JSON.stringify(currentInfo[k])}
        </div>
      ))}
      {proof && <p style={{ wordWrap: "break-word" }}>proof: {proof}</p>}
    </>
  );
}

相关阅读