Example Requirement: You need to obtain the value corresponding to a key from the dictionaryList on chain A, and then pass the key and its corresponding value to chain B for storage, so that chain B can also retrieve the value corresponding to the key.
Necessary Conditions:
On the source chain, the Omni service interface and contract address are required to initiate a cross-chain event.
On the target chain, the IMapoExecutor must be introduced to implement the mapoExecute method.
We initiate a cross-chain event on source chain A.
"@butternetwork/omniservice/contracts/interface/IMOSV3.sol";
contract A {
//The contract address of OmniService on chain A
IMOSV3 public imosv3;
mapping(string => string) public dictionaryList;
function sendDictionaryMessage(
uint256 _tochainId, //The chain ID of the target chain.
bytes memory _target, //The contract address on the target chain.
string memory _key //The message key on chain A.
) external payable {
//Encode the message that needs to be cross-chain.
bytes memory data = abi.encode(_key, dictionaryList[_key]);
IMOSV3.MessageData memory mData = IMOSV3.MessageData(
false,
IMOSV3.MessageType.MESSAGE, //Select MESSAGE for cross-chain transmission.
_target,
data,
500000,
0
);
//Encode the MessageData structure for cross-chain transmission.
bytes memory mDataBytes = abi.encode(mData);
//Retrieve the amount of fee required for cross-chain transaction.
(uint256 amount, ) = imosv3.getMessageFee(_tochainId, address(0), 500000);
//Initiate the cross-chain request using OmniChain Service
imosv3.transferOut{value: amount}(_tochainId, mDataBytes, address(0));
}
}
After messager detects the cross-chain log, it will execute the cross-chain message on chain B.
We implement mapoExecute on chain B to finalize the cross-chain message execution.
import "@butternetwork/omniservice/contracts/interface/IMapoExecutor.sol";
contract B is IMapoExecutor {
mapping(bytes32 => bool) orderList;
//In a simple example, here's a mapping used to store cross-chain data
//(this can be any other type, this is just a simple example)
mapping(string => string) public dictionary;
function mapoExecute(
uint256 _fromChain,
uint256 _toChain,
bytes calldata _fromAddress,
bytes32 _orderId,
bytes calldata _message
) external override returns (bytes memory newMessage) {
//On the target chain,
//we can check if the orderId has been used by the source chain's chain ID (_fromChain),
//the target chain's chain ID (_toChain),
//the source chain contract address (_fromAddress),
//even customizing some content within the message (_message) for inspection.
//Here's a simple example to check if orderId has been used
require(!orderList[_orderId],"The order id already exists");
//Parse the cross-chain data to obtain the corresponding value.
(string memory key, string memory val) = abi.decode(_message, (string, string));
//Assign the data correctly to complete the cross-chain message execution.
dictionary[key] = val;
//Confirm that the order ID has been used.
orderList[_orderId] = true;
return newMessage;
}
}
Advantages of MESSAGE:
Cross-chain bytes are customizable according to specific needs.
High scalability in execution on the target chain.