Wanchain Message Cross Chain Development Handbook
Welcome to the developer handbook for the Wanchain Message Bridge Protocol! This handbook aims to provide readers with a clear and systematic guide to understanding and using the Wanchain Message Bridge Protocol in order to build their own cross-chain applications.
The Wanchain Message Bridge Protocol is a technology that enables communication between different blockchain networks. It not only provides a way for different blockchains to communicate and interact with each other, but also greatly enhances the security and reliability of cross-chain transactions by adopting MPC (Multi-Party Computation) and cryptography-based secure threshold signature technology.
This handbook will provide you with a detailed guide on how to use the Wanchain Message Bridge Protocol to build cross-chain applications. We will start with basic cross-chain concepts and protocol structure, then delve into the various interfaces of the protocol and their secure usage methods, and finally use examples to demonstrate how to use these interfaces and protocols to build your own cross-chain applications.
Whether you are an experienced blockchain developer or a novice interested in cross-chain technology, we believe that you can find the information you need in this handbook. We look forward to seeing you use the Wanchain Message Bridge Protocol to build impressive cross-chain applications and jointly promote the advancement of blockchain technology.
The target readers of this handbook are primarily developers interested in blockchain development and cross-chain technology. We expect readers to have a certain foundation in Solidity programming and a basic understanding of blockchain and cross-chain technology. However, even if you are a beginner, as long as you are passionate about learning new technologies, we believe that you can benefit from this handbook.
Welcome to the Quick Start section! This section aims to provide developers with a simple and quick introduction guide to help you understand and start using the Wanchain Message Bridge Protocol in the shortest possible time. We will introduce the necessary preparations and how to perform basic operations of the protocol for you. You can quickly become familiar with the usage of the protocol through this section and lay a solid foundation for future development.
Before you start using the Wanchain Message Bridge Protocol, you need to complete some necessary preparations. We will use https://remix.ethereum.org/, an online Solidity IDE, as our development environment.
The steps are as follows:
- 1.
- 2.Click the file explorer icon in the left navigation bar of Remix.

- 1.In the file explorer area, click the "+" icon to create a new project. You can name the project whatever you like.

- 1.In your project, click the "+" icon to create a solidity file such as "MyContracts.sol".

After completing the above steps, you have successfully created a new project and imported the protocol's basic code that we provide. Now, you have completed the necessary preparations and can start to familiarize yourself with and use the Wanchain Message Bridge Protocol.
After completing the necessary preparations, you can now become familiar with and use the Wanchain Message Bridge Protocol. The following are the basic operating steps of the protocol:
- 1.In your project, create a new contract file. You can click the "+" icon in the file explorer area on the left to create a new file.
- 2.In the new contract file, you need to integrate from WmbApp. Specifically, you need to use the
is
keyword in your contract declaration to indicate that your contract inherits from WmbApp. This way, your contract can access all public and protected members provided by WmbApp. For example, you can declare your contract like this:// SPDX-License-Identifier: MITpragma solidity 0.8.18;import "@wandevs/message/contracts/app/WmbApp.sol";contract MyContract is WmbApp {// Your contract codes} - 3.You need to override the
_wmbReceive
function in your contract._wmbReceive
is a protected function provided by WmbApp, and it will be called when your contract receives a cross-chain message. You can write your own_wmbReceive
function according to your application needs to define how your contract should act when it receives a cross-chain message.function _wmbReceive(bytes calldata data,bytes32 messageId,uint256 fromChainId,address fromSC) internal override {// do something you want...} - 4.When initializing the contract, you need to call the
initialize
function of WmbApp. Theinitialize
function takes two parameters:admin
and_wmbGateway
. You should pass in the address of the administrator account asadmin
and the address of the WmbGateway as_wmbGateway
. For example:constructor(address admin, address _wmbGateway) WmbApp() {initialize(admin, _wmbGateway);// Your initialization code} - 5.In your contract, you may need to send messages or contract calls to other chains. At this time, you can call the
_dispatchMessage
function. This is a protected function provided by WmbApp, which can send messages to the chain or contract you specified.The_dispatchMessage
function takes four parameters:toChainId
: The ID of the chain that will receive the message.toAddress
: The address of the contract that will receive the message.msgData
: The message data you want to send.feeAmount
: The token address of the fee you are willing to pay.
You can call the_dispatchMessage
function like this:function sendMessage(uint256 toChainId, address toAddress, bytes memory msgData,uint feeAmount) public payable {_dispatchMessage(toChainId, toAddress, msgData, feeAmount);}In this example, we created asendMessage
function that takes the same parameters and simply calls the_dispatchMessage
function. You can define your own function in your contract and call the_dispatchMessage
function according to your needs. - 6.Before calling the
_dispatchMessage
function, you need to use theestimateFee
function to estimate the fee.estimateFee
is a public function provided by WmbApp, which can help you calculate the fee required to send a cross-chain message.TheestimateFee
function takes two parameters:toChain
: The BIP44 ChainId of the chain that will receive the message.gasLimit
: The gas limit required to execute the contract call on the receiving chain.
You need to use the fee value returned by theestimateFee
function as thefeeAmount
parameter of the_dispatchMessage
function. You can usemsg.value
to pass in the native token of your chain as the fee, or use the balance of your contract as the fee.For example, you can call the_dispatchMessage
function like this:function sendMessage(uint256 toChainId, address toAddress,bytes memory msgData, uint256 gasLimit) public payable {uint256 fee = estimateFee(toChainId, gasLimit);require(msg.value >= fee, "Insufficient fee");_dispatchMessage(toChainId, toAddress, msgData, msg.value);}In this example, we modified thesendMessage
function, added thegasLimit
parameter, and called theestimateFee
function to calculate the fee inside the function. Then, we check whethermsg.value
is greater than or equal to the calculated fee. If it is not enough, an exception is thrown. Finally, we call the_dispatchMessage
function and usemsg.value
as the fee. Now, you have learned how to estimate and pay the fee for sending cross-chain messages. Next, we will detail the other interfaces of the protocol and their secure usage methods. - 7.WmbApp also provides a function called
_dispatchMessageBatch
, which can be used to send transactions in batches to different contract addresses in the target chain. This function can be used to interact with multiple different contracts or to ensure the sequential execution of multiple operations.The_dispatchMessageBatch
function accepts three parameters:toChainId
: the ID of the chain that will receive the message.messages
: an array containing multiple Message structures. Each Message structure contains a target address and a message data.fee
: the token address of the fee you are willing to pay.
You can call the_dispatchMessageBatch
function like this:function sendMessageBatch(uint256 toChainId, Message[] memory messages, uint256 gasLimit)public payable {uint256 fee = estimateFee(toChainId, gasLimit);require(msg.value >= fee, "Insufficient fee");_dispatchMessageBatch(toChainId, messages, msg.value);}In this example, we create asendMessageBatch
function that accepts the same parameters and calculates the fee using theestimateFee
function. Then, we check ifmsg.value
is greater than or equal to the calculated fee. If it is not, an exception is thrown. Finally, we call the_dispatchMessageBatch
function usingmsg.value
as the fee. - 8.After your contract is deployed and initialized, the administrator needs to call the
setTrustedRemotes
function to explicitly specify which chains and contracts have permission to send cross-chain messages to your contract. This is an important step to ensure the security of your contract.ThesetTrustedRemotes
function accepts three parameters:fromChainIds
: an array containing multiple chain IDs, each of which is a uint type.froms
: an array containing multiple contract addresses, each of which is an address type. Each address corresponds to the chain ID at the same position in thefromChainIds
array.trusted
: an array containing multiple Boolean values, each of which represents whether the corresponding chain and contract is trusted and can send cross-chain messages to your contract.
After completing all of the above steps, your contract is fully ready to receive and send cross-chain messages. Please note that you need to ensure the security of your contract and only trust the chains and contracts that you believe can send cross-chain messages to your contract. You can compile and deploy it to blockchain by MetaMask wallet in remix.
Now that you have mastered the basics of the Wanchain message cross-chain protocol, you can define your own contracts to receive and send cross-chain messages according to your application needs. Next, we will provide a detailed introduction to the various interfaces of the protocol and their secure usage methods.
When sending cross-chain messages, you need to fill in the BIP44 standard ChainId of the target chain. The following table lists the currently supported chains and their corresponding ChainId values:
Chain Name | BIP44 ChainId | Gateway Address |
---|---|---|
Ethereum Goerli Testnet | 2147483708 | 0x9454C2F15F308098163623D5E7deCe366793efD3 |
Avalanche Fuji Testnet | 2147492648 | 0x8Ee72C8194ec8A527B1D4981742727437091C913 |
Wanchain Testnet | 2153201998 | 0xEB14407Edc497a73934dE08D5c3079BB1F5f145D |
XDC Apothem Testnet | 2147484198 | 0x8c1b9daD87BFC48DF48b15baA19d0FB163030169 |
Arbitrum Goerli Testnet | 1073741826 | 0x1ed3538383bbfdb80343b18f85d6c5a5fb232fb6 |
Optimism Goerli Testnet | 2147484262 | 0xc6ae1db6c66d909f7bfeeeb24f9adb8620bf9dbf |
Polygon Mumbai Testnet | 2147484614 | 0x45463b2d973bd3304a2cad1f9765b098ece4afce |
Energi Testnet | 2147493445 | 0x9e8aafd785f8cc9aebb4b6fbf817ee988e85fede |
When writing smart contracts and performing cross-chain operations, please ensure that you use the correct ChainId value.

- 1.Gateway Contract: A smart contract deployed on each chain as an entry point for third-party DApps interaction. The Gateway contract includes basic interfaces such as send and receive for cross-chain message sending and receiving.
- 2.Off-chain Storeman Agent: Code that can be integrated into the current Storeman agent, responsible for listening to Gateway events and interacting with the peer chain's Gateway contract to implement cross-chain message transmission. The Storeman Agent uses MPC signature technology to sign cross-chain messages, ensuring information security and reliability to prevent tampering.
- 3.Third-party DApp Contract: A smart contract deployed on various chains by third-party projects that interacts with the Gateway contract to implement cross-chain functionality and its own business logic. It is developed by the third-party project and does not require Wanchain deployment and maintenance.
- 4.MPC Signature Verification Contract: A multi-party computation signature verification contract used to verify signature data on the chain, which can reuse existing verification contracts on the current chain to ensure the security and reliability of cross-chain messages during the cross-chain process.
These components together build a secure and efficient cross-chain message system, enabling seamless communication between different blockchain networks.
In the Wanchain MPC-based cross-chain messaging solution, the information flow is as follows:
- 1.Cross-chain message sending:
- The user or third-party DApp's smart contract initiates a cross-chain message request by calling the send interface of the Gateway contract. The request includes the target chain ID, target contract address, message content, and related cross-chain parameters, and returns a globally unique messageId to uniquely identify each cross-chain request.
- The Gateway contract checks the sending request, including parameter validity, sender permissions, etc. Legal requests will be recorded on the chain in the form of events.
- The off-chain Agent listens to the cross-chain message sending events on the chain's Gateway contract and obtains cross-chain request information.
- 2.Cross-chain message processing and signing:
- The off-chain Agent processes the received cross-chain request information, including verifying the legality of the cross-chain request and constructing cross-chain messages.
- The off-chain Agent uses MPC signature technology to sign the cross-chain message in collaboration with other off-chain Agents to ensure the security of the cross-chain message during transmission.
- 3.Cross-chain message receiving:
- The off-chain Agent sends the signed cross-chain message to the target chain's Gateway contract by calling its receive interface.
- The target chain's Gateway contract receives the cross-chain message through the receive interface. During the reception process, the contract verifies the signature and the legality of the relevant parameters.
- After successful verification, the Gateway contract forwards the cross-chain message to the target smart contract (third-party DApp contract) to complete the cross-chain message transmission.
Through the above information flow, seamless communication between different blockchain networks is achieved. During the entire process, the collaboration between on-chain contracts and off-chain Agents, as well as the application of MPC signature verification contracts, ensure the security and effectiveness of cross-chain message transmission.
When calling the interface of the target chain's third-party DApp contract, the third-party contract can encapsulate and call the interfaces of other related DApps according to its own business logic needs, combining multiple DApps for use. This part does not need to be managed by Wanchain and can be freely configured.
The gas limit restriction, cross-chain fee analysis, and failed transaction rollback during the cross-chain process will be introduced in later chapters.
EIP-5164 is an Ethereum cross-chain messaging interface that defines a standardized cross-chain communication method. Through this interface, developers can implement standardized cross-chain message transmission and processing, thereby simplifying the implementation and integration of cross-chain communication.
The interface defines several related events and methods:
1) Events
- 1.
MessageDispatched
: Triggered when a cross-chain message is successfully sent, including messageId, sender address, target chain ID, target contract address, and message data. - 2.
MessageBatchDispatched
: Triggered when a batch of cross-chain messages are successfully sent, including messageId, sender address, target chain ID, and message array. - 3.
MessageIdExecuted
: Triggered when a cross-chain message is successfully executed, including the source chain ID and messageId.
2) Methods
- 1.
dispatchMessage
: Used to send a single cross-chain message, accepting target chain ID, target contract address, and message data as parameters. Returns a unique messageId. - 2.
dispatchMessageBatch
: Used to send a batch of cross-chain messages, accepting target chain ID and message array as parameters. Returns a unique messageId.
2) Methods
- 1.
dispatchMessage
: Used to send a single cross-chain message, accepts target chain ID, target contract address, and message data as parameters. Returns a unique message ID. - 2.
dispatchMessageBatch
: Used to send a batch of cross-chain messages, accepts target chain ID and message array as parameters. Returns a unique message ID. - 3.
MessageExecutor
is a comment that requires contracts implementing this interface to add ABI-packaged (messageId, fromChainId, from) to calldata when executing each cross-chain message.
3) Error Types
- 1.
MessageIdAlreadyExecuted
: An error triggered when attempting to execute an already executed message ID. - 2.
MessageFailure
: An error triggered when a message execution fails, containing the message ID and error data. - 3.
MessageBatchFailure
: An error triggered when batch message execution fails, containing the message ID, message index, and error data.
The
IWmbGateway
file is the interface definition of the Wanchain Message Bridge Gateway contract. The interface extends and expands the EIP-5164 interface and includes the following interfaces:dispatchMessage
Send a message to a specified address on a specified chain and attach the corresponding data.
function dispatchMessage(
uint256 toChainId,
address to,
bytes calldata data
) external payable returns (bytes32 messageId);
Parameter explanation:
toChainId
(uint256): The chain ID of the target chain.to
(address): The address of the target contract on the target chain.data
(bytes): The data sent to the target contract.
Return value explanation:
messageId
(bytes32): The unique identifier of the sent message.
dispatchMessageBatch
Send a batch of messages to a specified chain.
function dispatchMessageBatch(
uint256 toChainId,
Message[] calldata messages
) external payable returns (bytes32 messageId);
Parameter explanation:
toChainId
(uint256): The chain ID of the target chain.messages
(Message[]): An array containing the target addresses and data to be sent to each target contract.
Return value explanation:
messageId
(bytes32): The unique identifier of the sent message batch.
receiveMessage
Receive a message from another link and verify the sender's signature.
function receiveMessage(
bytes32 messageId,
uint256 sourceChainId,
address sourceContract,
address targetContract,
bytes calldata messageData,
uint256 gasLimit,
bytes32 smgID,
bytes calldata r,
bytes32 s
) external;
Parameter explanation:
messageId
(bytes32): The unique identifier of the message to prevent replay attacks.sourceChainId
(uint256): The chain ID of the source chain.sourceContract
(address): The address of the source contract on the source chain.targetContract
(address): The address of the target contract on the target chain.messageData
(bytes): The data sent in the message.gasLimit
(uint256): The maximum gas consumption for the message call.smgID
(bytes32): Wanchain Storeman Group ID that signed the message.r
(bytes): R component of the SMG MPC signature.s
(bytes32): S component of the SMG MPC signature.
receiveBatchMessage
Receive a batch of messages from another link and verify the sender's signature.
function receiveBatchMessage(
bytes32 messageId,
uint256 sourceChainId,
address sourceContract,
Message[] calldata messages,
uint256 gasLimit,
bytes32 smgID,
bytes calldata r,
bytes32 s
) external;
Parameter explanation:
messageId
(bytes32): The unique identifier of the message to prevent replay attacks.sourceChainId
(uint256): The chain ID of the source chain.sourceContract
(address): The address of the source contract on the source chain.messages
(Message[]): An array of messages containing the target addresses and data to be sent to each target contract.gasLimit
(uint256): The maximum gas consumption for the message call.smgID
(bytes32): Wanchain Storeman Group ID that signed the message.r
(bytes): R component of the SMG MPC signature.s
(bytes32): S component of the SMG MPC signature.
estimateFee
Estimate the fee required to send a message to the target chain.
function estimateFee(
uint256 targetChainId,
uint256 gasLimit
) external view returns (uint256 fee);
Parameter explanation:
targetChainId
(uint256): The chain ID of the target chain.gasLimit
(uint256): The maximum gas consumption for the message call when calling a third-party DApp contract during cross-chain message transmission.
Return value explanation:
fee
(uint256): The estimated fee required for cross-chain message transmission.
Other public read-only interfaces are shown in the following table:
Variable name | Meaning |
---|---|
chainId | The slip-0044 standard chainId of the local chain |
maxGasLimit | The maximum global gas limit for messages |
minGasLimit | The minimum global gas limit for messages |
defaultGasLimit | The default gas limit for messages |
maxMessageLength | The maximum message length |
signatureVerifier | The address of the signature verification contract |
wanchainStoremanAdminSC | The address of the Wanchain Storeman Admin contract |
messageExecuted | The mapping of message ID to execution status |
baseFees | The mapping of target chain ID to basic fees for obtaining the target chain's fee benchmark |
messageGasLimit | The mapping of message ID to gas limit, storing the gas limit value set for each message |
nonces | The mapping of source chain ID -> target chain ID -> source contract -> target contract -> nonce for preventing replay attacks |
supportedDstChains | The mapping of target chain ID to support status |
Cross-chain transactions require a certain amount of fees, and the calculation of fees needs to consider the gas limit value of the target chain. When estimating fees, it is necessary to calculate based on factors such as the gas limit value of the target chain and the size of the transaction data. At the same time, each chain needs to be independently configured according to different target chains.
The formula for calculating fees is as follows:
estimatedFee = gasLimit * baseFee
Where gasLimit is the target contract call gasLimit passed when calling the send interface. BaseFee is the unit price set by management after comprehensive consideration of different chain prices. Here, comprehensive consideration includes gas fee consumption on the chain, the current price of the native currency on the current chain and the target chain, gasPrice and reasonable income.
When setting baseFee, three points should be considered comprehensively:
- 1.The price difference between the original chain and the target chain: The value of different native currencies on different chains may differ greatly, so when calculating fees, it is necessary to adjust according to the actual currency price to ensure the reasonable cost of cross-chain transactions.
- 2.The default gasPrice of the target chain: The gas price of each chain is different, and the transaction fee needs to consider the gasPrice of the target chain to calculate the cross-chain transaction fee more accurately.
- 3.Reasonable handling fees: In order to ensure the sustainable operation of the cross-chain transaction platform, a certain proportion of handling fees needs to be reasonably charged. When configuring baseFee, the balance between operating costs and revenue should be comprehensively considered to avoid excessive handling fees leading to user loss.
In the case where the gasLimit is set but the target chain's gasLimit is insufficient, third-party DApps can retry failed transactions on their own. When retrying, it is not limited by the gas limit, which can avoid transaction failures due to insufficient gas limit. When retrying failed transactions, DApps can reset gasLimit according to the actual situation to ensure that the transaction can be successfully executed.
When calling the target chain contract, the try-catch interface can be used to handle transaction failures. When a transaction fails, according to EIP-5164, an Error containing the MessageId and error information will be directly reverted.
If the reason for the failure is insufficient gas, users can resubmit the transaction with a higher gasLimit.
If you do not want the failed transaction to be re-executed, you need to capture errors and actively restrict them in the DApp contract.
Third-party DApps can inherit and develop their own cross-chain applications from the APP template, and all interactions with the Gateway are encapsulated in the APP template. The APP template is divided into two types: 1) WmbApp simple template; 2) WmbRetryableApp App template that can retry errors.
- 1.The simple template directly forwards the message without any error caching. Failed transactions cannot be retried within the contract.
- 2.The retryable template caches error transactions and can retry or read the messageId information that occurred in the error within the contract.
For messages with strict execution order requirements,
dispatchMessageBatch
interface can be used to send batch messages, and the execution order in this interface can be strictly guaranteed. If any one message fails, the entire transaction will be rolled back. The ordinary dispatchMessage interface does not guarantee strict sequential execution. If the third party wants to guarantee the order, it can customize the contract code in its DApp.- 1.Prevent reentrancy attacks: Use the nonReentrant function to restrict reentrancy for three interfaces that involve sending messages, because these interfaces have refund callback sender operations.
- 2.Prevent replay attacks: Use a globally unique messageId recorded in the contract to prevent possible replay attacks.
- 3.Administrator permissions: Use the AccessControl library to restrict function access.
Inherit from the RetryableApp contract to implement a cross-chain application that can record error messages on-chain and customize retry rules.
See details in:
examples/CCPoolV2.sol
Based on the multi-chain token issuance mechanism, you can issue your own token on multiple blockchains and perform unrestricted cross-chain transfers and transfers between chains.
See details in:
examples/mcToken.sol
With message cross-chain, you can enable existing tokens to perform permissionless cross-chain transfers.
See details in:
examples/ccPoolV1.sol
When the cross-chain fails due to insufficient balance in the pool, you can choose to refund the assets to the user's wallet on the original chain.
See details in:
examples/ccPoolV2.sol
Q1: How to handle cross-chain failures on the target chain?
A: Third-party DApp smart contracts need to consider possible failure scenarios in advance during the design phase, including whether failed transactions need to be retried, whether failed transactions need to be recorded on-chain, and whether feedback messages need to be sent to the original chain. The Storeman in Wanchain's message cross-chain will not actively retry failed transactions, and third-party DApps need to handle them according to their own needs. For example, when a transaction fails due to insufficient gas limit, the third-party DApp can retry by using the signed data. When a transaction fails due to logical errors, the third-party DApp can consider whether to send feedback messages.
See details in:
examples/ccPoolV2.sol
Q2: How to know how much gas limit is required for executing a transaction on the target chain?
A: You can estimate it in advance by filling in a large number to ensure success, or you can estimate the gas fee in real-time offl-chain and estimate a good value.
Q3: How to make users bear the cross-chain transaction fee themselves?
A: Just send the transaction fee as a payable value along with the transaction when building it.
Q4: How to make users use message cross-chain for free and let the project bear the cross-chain transaction fee?
A: The project only needs to pre-deposit enough native coin in the DApp contract to use as the transaction fee.