多链 DApp
介绍
多链DApp,即支持多条区块链网络的去中心化应用,是当前区块链技术发展的重要方向之一。通过支持多条链,DApp能够提供更广泛的功能和更灵活的用户体验。本教程将以Bitget Wallet为例,详细介绍多链DApp的两种主要业务场景,以及如何通过Inject Provider和Http Bridge实现链的切换。
业务场景
多链DApp主要有两个业务场景:
1. 单链业务,支持多条链
这种场景下,DApp的核心业务是单链的,但用户可以在初始化时选择目标链。具体的例子有:
- Uniswap:一个去中心化交易所(DEX),允许用户在以太坊及其Layer 2上进行代币交换。
- PancakeSwap:一个在币安智能链(BSC)上运行的去中心化交易所(DEX),支持多种代币的交易和流动性提供。
在这个场景中,DApp在不同链上提供相同的功能,用户可以根据需求选择不同的链来进行交互。实现这种支持的主要挑战在于确保DApp在不同链上的部署和操作一致性,并处理各链之间的差异。
2. 跨链业务
这种场景下,DApp需要在多个链之间进行通讯,完成复杂的业务流程。可以选择支持多条链的异构钱包,或者在不同的链之间切换钱包。具体的例子有:
- Babylon的早期版本:利用
Cosmos
实现跨链DeFi功能,需要同时使用钱包链接BTC
和Babylon
。
在这个场景中,DApp需要在不同链之间传递数据和资产,通常需要较为复杂的跨链协议和机制。这类业务的实现难度更高,需要处理不同链之间的数据一致性、交易安全性和跨链通信的效率等问题。
实现链的切换
实现多链DApp的重要一环是提供链的切换功能。本文将介绍如何通过Inject Provider和Http Bridge实现链的切换。
1. Inject Provider切换链
Inject Provider是一种常见的Dapp连接钱包的方法,通过使用Inject Provider,允许DApp在用户界面中切换链。其实现步骤如下:
1. 检测当前链
DApp首先需要检测用户当前连接的区块链网络。这通常通过Web3提供的API来实现。例如,在以太坊上,可以使用web3.eth.net.getId()
来获取当前的网络ID。
web3.eth.net.getId().then(netId => {
console.log("Current Network ID:", netId);
});
web3.eth.net.getId().then(netId => {
console.log("Current Network ID:", netId);
});
2. 提供用户切换链的UI
在DApp的用户界面上提供切换链的选项。这可以是一个下拉菜单、按钮或其他用户界面组件,允许用户选择他们想要切换到的区块链网络。
<select id="networkSelector">
<option value="1">Ethereum Mainnet</option>
<option value="8453">Base</option>
<!-- Add other networks as needed -->
</select>
<select id="networkSelector">
<option value="1">Ethereum Mainnet</option>
<option value="8453">Base</option>
<!-- Add other networks as needed -->
</select>
3. 监听用户选择
当用户选择一个新的网络时,DApp需要捕捉到这个事件并进行相应处理。
document.getElementById("networkSelector").addEventListener("change", event => {
const newNetworkId = event.target.value;
switchNetwork(newNetworkId);
});
document.getElementById("networkSelector").addEventListener("change", event => {
const newNetworkId = event.target.value;
switchNetwork(newNetworkId);
});
4. 根据用户的操作选择相对应的Provider
如果是同一个主网的情况下,一般不需要再次选择不同的Provider,如从以太坊主网切换到Base链后,Bitget Wallet钱包提供的Provider依然是window.bitkeep.ethereum
。
但如果是不同主网之间的切换,如从以太坊切换到了BTC,那么则需要更换不同的Provider,即从window.bitkeep.ethereum
切换到了window.bitkeep.unisat
,不同的Provider提供的API也是不同的,这一点请参考对应的Provider的API文档。
5. 切换链
DApp通过调用Bitget Wallet钱包提供出的Provider的API来请求用户切换到新的链。
async function switchNetwork(chainId) {
try {
await window.bitkeep.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: `0x${parseInt(chainId).toString(16)}` }],
});
console.log("Network switched successfully");
} catch (switchError) {
// 处理错误
console.error("Failed to switch network", switchError);
// 如果链没有被添加到BitgetWallet,你可以请求用户添加链
if (switchError.code === 4902) {
try {
await window.bitkeep.ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: `0x${parseInt(chainId).toString(16)}`,
chainName: 'Base',
nativeCurrency: {
name: 'Ether',
symbol: 'ETH',
decimals: 18,
},
rpcUrls: ['https://api.mycryptoapi.com/eth'],
blockExplorerUrls: ['https://etherscan.io'],
},
],
});
} catch (addError) {
console.error("Failed to add network", addError);
}
}
}
}
async function switchNetwork(chainId) {
try {
await window.bitkeep.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: `0x${parseInt(chainId).toString(16)}` }],
});
console.log("Network switched successfully");
} catch (switchError) {
// 处理错误
console.error("Failed to switch network", switchError);
// 如果链没有被添加到BitgetWallet,你可以请求用户添加链
if (switchError.code === 4902) {
try {
await window.bitkeep.ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: `0x${parseInt(chainId).toString(16)}`,
chainName: 'Base',
nativeCurrency: {
name: 'Ether',
symbol: 'ETH',
decimals: 18,
},
rpcUrls: ['https://api.mycryptoapi.com/eth'],
blockExplorerUrls: ['https://etherscan.io'],
},
],
});
} catch (addError) {
console.error("Failed to add network", addError);
}
}
}
}
6. 重新初始化DApp:
切换链后,DApp需要重新初始化所有与区块链交互的实例,例如合约实例、Web3或Ethers.js提供的Provider等。
async function initializeDApp() {
const provider = new ethers.providers.Web3Provider(window.bitkeep.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractABI, signer);
// 调用相关方法
try {
const result = await contract.someMethod();
console.log(result);
} catch (error) {
console.error("Error calling contract method:", error);
}
}
// 调用初始化函数
initializeDApp();
async function initializeDApp() {
const provider = new ethers.providers.Web3Provider(window.bitkeep.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractABI, signer);
// 调用相关方法
try {
const result = await contract.someMethod();
console.log(result);
} catch (error) {
console.error("Error calling contract method:", error);
}
}
// 调用初始化函数
initializeDApp();
2. Http Bridge切换链
Http Bridge 是另一种常见的链切换方法,经常见到的场景是应用在 WalletConnect
,但请注意,WalletConnect
仅仅是 Http Bridge 的其中一种形式。通过Http Bridge将允许DApp通过HTTP请求来通知钱包切换链。
以WalletConnect
为例,可以通过如下步骤对Provider进行初始化:
import WalletConnectProvider from "@walletconnect/web3-provider";
import Web3 from "web3";
// 1. 创建WalletConnect Provider
const provider = new WalletConnectProvider({
infuraId: "YOUR_INFURA_ID", // Required
rpc: {
8453: "https://api.mycryptoapi.com/eth", // Base Chain
1: "https://mainnet.infura.io/v3/YOUR_INFURA_ID", // Ethereum Mainnet
// 添加更多网络RPC URL
},
});
// 2. 启动Provider
provider.enable().then(() => {
const web3 = new Web3(provider);
// 在这里初始化DApp,例如获取账户,设置合约实例等
web3.eth.getAccounts().then(accounts => {
console.log("Accounts:", accounts);
});
});
import WalletConnectProvider from "@walletconnect/web3-provider";
import Web3 from "web3";
// 1. 创建WalletConnect Provider
const provider = new WalletConnectProvider({
infuraId: "YOUR_INFURA_ID", // Required
rpc: {
8453: "https://api.mycryptoapi.com/eth", // Base Chain
1: "https://mainnet.infura.io/v3/YOUR_INFURA_ID", // Ethereum Mainnet
// 添加更多网络RPC URL
},
});
// 2. 启动Provider
provider.enable().then(() => {
const web3 = new Web3(provider);
// 在这里初始化DApp,例如获取账户,设置合约实例等
web3.eth.getAccounts().then(accounts => {
console.log("Accounts:", accounts);
});
});
当用户使用支持WalletConnect
的 Bitget Wallet 钱包APP与Dapp建立连接后,后续步骤将与使用Inject Provider的流程一致,此处省略。
总结
通过Bitget Wallet,开发者可以轻松实现对多链的支持,并通过灵活的链切换机制,提供用户友好的多链交互体验。希望这篇教程能够为您的多链DApp开发提供有价值的指导。