Skip to content

Multi-chain DApp

introduction

Multichain DApps, which are decentralized applications that support multiple blockchain networks, is an important direction in the development of blockchain technology. By supporting multiple chains, DApps can provide more extensive functionality and a more flexible user experience. This tutorial will use Bitget Wallet as an example to introduce the two main business scenarios of multichain DApps, as well as how to achieve chain switching through Inject Provider and Http Bridge.

Business Scenarios

Multichain DApps have two main business scenarios:

1. Single-chain business with support for multiple chains

In this scenario, the core business of the DApp is single-chain, but users can choose the target chain during initialization. Examples include:

  • Uniswap: A decentralized exchange (DEX) that allows users to swap tokens on Ethereum and its Layer 2 networks.
  • PancakeSwap: A decentralized exchange (DEX) running on the Binance Smart Chain (BSC) that supports trading and liquidity provision for various tokens.

In this scenario, the DApp provides the same functionality on different chains, and users can choose different chains to interact with based on their needs. The main challenge in implementing this support is to ensure consistency in the deployment and operation of the DApp on different chains, and to handle the differences between the chains.

2.Cross-chain business

In this scenario, the DApp needs to communicate between multiple chains to complete complex business processes. It can choose to support a multi-chain heterogeneous wallet, or switch wallets between different chains. Examples include:

  • Early versions of Babylon: Leveraging Cosmos to implement cross-chain DeFi functionality, requiring the use of wallet connections to both BTC and Babylon.

In this scenario, the DApp needs to transfer data and assets between different chains, often requiring more complex cross-chain protocols and mechanisms. The implementation of such business is more challenging, as it requires addressing issues such as data consistency between different chains, transaction security, and the efficiency of cross-chain communication.

Implementing chain switching

Providing chain switching functionality is an important part of implementing a multichain DApp. This article will introduce how to implement chain switching using Inject Provider and Http Bridge.

1. Switching Chains with Inject Provider

Inject Provider is a common method for DApps to connect to wallets, and using Inject Provider allows DApps to switch chains within the user interface. The implementation steps are as follows:

1. Detecting the Current Chain

The DApp first needs to detect the blockchain network the user is currently connected to. This is typically done using the APIs provided by Web3. For example, on Ethereum, you can use web3.eth.net.getId() to get the current network 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. Providing UI for Users to Switch Chains

Provide an option in the DApp's user interface to allow users to switch chains. This can be a dropdown menu, button, or other UI component that allows users to select the blockchain network they want to switch to.

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. Listening for User Selection

When the user selects a new network, the DApp needs to capture this event and handle it accordingly.

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.Selecting the Appropriate Provider Based on User Action

If it's a switch within the same mainnet, you generally don't need to choose a different Provider. For example, when switching from the Ethereum mainnet to the Base chain, the Provider provided by the Bitget Wallet is still window.bitkeep.ethereum.

However, if it's a switch between different mainnets, such as from Ethereum to BTC, you'll need to change the Provider, from window.bitkeep.ethereum to window.bitkeep.unisat. The APIs provided by different Providers are also different, so please refer to the API documentation of the corresponding Provider.

5. Switching the Chain

The DApp can call the API provided by the Bitget Wallet Provider to request that the user switch to the new chain.

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) {
    // Handling Errors
    console.error("Failed to switch network", switchError);
    // If the chain has not been added to BitgetWallet, you can request the user to add the chain
    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) {
    // Handling Errors
    console.error("Failed to switch network", switchError);
    // If the chain has not been added to BitgetWallet, you can request the user to add the chain
    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. Reinitializing the DApp:

After switching the chain, the DApp needs to reinitialize all instances that interact with the blockchain, such as contract instances, Web3 or Ethers.js-provided Providers, etc.

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

  //Call related methods
  try {
    const result = await contract.someMethod();
    console.log(result);
  } catch (error) {
    console.error("Error calling contract method:", error);
  }
}

//Call the initialization function
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);

  //Call related methods
  try {
    const result = await contract.someMethod();
    console.log(result);
  } catch (error) {
    console.error("Error calling contract method:", error);
  }
}

//Call the initialization function
initializeDApp();

2. Switching Chains with Http Bridge

Http Bridge is another common method for chain switching, often seen in the context of WalletConnect, but please note that WalletConnect is just one form of Http Bridge. Using Http Bridge will allow the DApp to notify the wallet to switch chains through an HTTP request.

Using WalletConnect as an example, you can initialize the Provider as follows:

js
import WalletConnectProvider from "@walletconnect/web3-provider";
import Web3 from "web3";

// 1. Create 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
    // Add more network RPC URLs
  },
});

// 2. launch Provider
provider.enable().then(() => {
  const web3 = new Web3(provider);

  // Initialize DApp here, such as getting account, setting contract instance, etc.
  web3.eth.getAccounts().then((accounts) => {
    console.log("Accounts:", accounts);
  });
});
import WalletConnectProvider from "@walletconnect/web3-provider";
import Web3 from "web3";

// 1. Create 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
    // Add more network RPC URLs
  },
});

// 2. launch Provider
provider.enable().then(() => {
  const web3 = new Web3(provider);

  // Initialize DApp here, such as getting account, setting contract instance, etc.
  web3.eth.getAccounts().then((accounts) => {
    console.log("Accounts:", accounts);
  });
});

After the user connects the Bitget Wallet app (which supports WalletConnect) to the DApp, the subsequent steps will be consistent with the process of using Inject Provider, so I'll skip those here.

summary

Through Bitget Wallet, developers can easily implement support for multiple chains and provide a user-friendly multi-chain interaction experience through a flexible chain switching mechanism. We hope this tutorial can provide valuable guidance for your multichain DApp development.