Skip to content

多链 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功能,需要同时使用钱包链接BTCBabylon

在这个场景中,DApp需要在不同链之间传递数据和资产,通常需要较为复杂的跨链协议和机制。这类业务的实现难度更高,需要处理不同链之间的数据一致性、交易安全性和跨链通信的效率等问题。

实现链的切换

实现多链DApp的重要一环是提供链的切换功能。本文将介绍如何通过Inject Provider和Http Bridge实现链的切换。

1. Inject Provider切换链

Inject Provider是一种常见的Dapp连接钱包的方法,通过使用Inject Provider,允许DApp在用户界面中切换链。其实现步骤如下:

1. 检测当前链

DApp首先需要检测用户当前连接的区块链网络。这通常通过Web3提供的API来实现。例如,在以太坊上,可以使用web3.eth.net.getId()来获取当前的网络ID。

js
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的用户界面上提供切换链的选项。这可以是一个下拉菜单、按钮或其他用户界面组件,允许用户选择他们想要切换到的区块链网络。

html
<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需要捕捉到这个事件并进行相应处理。

js
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来请求用户切换到新的链。

js
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等。

js
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进行初始化:

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

当用户使用支持WalletConnectBitget Wallet 钱包APP与Dapp建立连接后,后续步骤将与使用Inject Provider的流程一致,此处省略。

总结

通过Bitget Wallet,开发者可以轻松实现对多链的支持,并通过灵活的链切换机制,提供用户友好的多链交互体验。希望这篇教程能够为您的多链DApp开发提供有价值的指导。