Skip to content

Ton DApp Integration Guide

For Ton DApp, Bitget Wallet currently provides integration through TonConnect. By completing the steps in this guide, you can achieve full-scenario integration in one go:

  • Integrate Bitget Wallet and Bitget Wallet Lite in Web DApp
  • Integrate Bitget Wallet and Bitget Wallet Lite in Telegram Mini App

TonConnect

TonConnect is an open protocol that connects wallets and DApps (Web3 applications). It uses a bridge (JS Bridge or Http Bridge) to establish a connection between two applications and/or devices and starts communication.

Bitget Wallet fully supports TonConnect.

Interaction Forms of TonConnect:

  1. When accessing the DApp through a desktop browser, you can choose to connect via a plugin or QR code. If the plugin wallet is not installed, it will redirect to the plugin wallet download page. You can also scan the QR code with the mobile wallet app to connect.
  2. When opening the DApp in the mobile wallet app, it will directly connect to the wallet if supported; otherwise, it will open the corresponding wallet download page.
  3. When opening the DApp in a non-wallet mobile app (including mobile browsers), it will use a deeplink to open the wallet app.

Install

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

Development Example

There are two configuration methods to integrate Bitget Wallet into the wallet connection options of Ton Connect:

  1. By setting the value of walletsListConfiguration.includeWallets to add the custom wallet to the wallets-list.
  2. The recommended method is to directly specify the connection to Bitget Wallet using await tonConnectUI.openSingleWalletModal("bitgetTonWallet"), as shown in the image below:

Here is the code example:

TonConnect Demo Full Code

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>}
    </>
  );
}