TonConnect
TonConnect
TonConnect 是一个链接钱包和 DApps(Web3 应用程序)的开放协议,它使用一个桥梁(JS Bridge 或者 Http Bridge)在两个应用程序和/或设备之间建立链接,并开始通信。
TonConnect 的交互形式
Dapp 接入Bitget Wallet后,根据场景的不同以下几种交互形式:
Telegram Mini App
若 Dapp 提供了 Telegram Mini App,用户可访问 Telegram Mini App 中的 Dapp
- 可选择使用
Bitget Wallet APP
,会通过 deeplink 打开Bitget Wallet APP
进行链接,否则会打开对应钱包的下载页 - 可选择使用
Bitget Wallet Lite
,Telegram 会拉起Bitget Wallet Lite
Mini App 进行链接 - (即将到来...)若 Dapp 注册到了
Bitget Wallet Lite
Dapp 中心,那么即使 Dapp 未提供Telegram Mini App,用户也可通过Bitget Wallet Lite
的Dapp 中心访问该Dapp,并进行钱包链接交互
移动端 Dapp
若 Dapp 提供了移动端的适配版本,用户可通过手机端访问Dapp
- 可选择在
Bitget Wallet
中打开 DApp,并直接与Bitget Wallet
建立链接 - 也可在手机端
非Bitget Wallet APP
(包括手机端浏览器) 中打开 DApp 时,会通过 deeplink 打开Bitget Wallet APP
进行链接,否则会打开对应钱包的下载页
PC 端Dapp
若 Dapp 提供了PC端的适配版本,用户可通过桌面版浏览器访问 DApp
- 可选择
Bitget Wallet Chrome Extension
连接,如未安装插件钱包则跳转插件钱包下载页 - 也可以选择使用
Bitget Wallet APP
或Bitget Wallet Lite
扫描二维码链接
集成指南
接下来会介绍如何在 Dapp 中集成Bitget Wallet
,通过一次配置,将同时完成Bitget Wallet
,Bitget Wallet Chrome Extension
和 Bitget 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 Wallet
和 Bitget Wallet Lite
配置到 Ton Connect
的钱包链接选项中:
- 通过设置
walletsListConfiguration.includeWallets
的以下示例代码中的值来完成配置- 可在钱包链接弹框里,展示出
Bitget Wallet
和Bitget 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"],
},
]
- 更推荐的方法是,通过调用以下代码,直接指定连接 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
以下是代码示例:
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>}
</>
);
}