The on-chain API for receiving cross-chain messages
Receive messages from other chains by implementing the handle() method in your cross-chain application.
Interface
The handle method passes a cross-chain message to the application.
_origin is a Nomad domain. List of domains here
_nonce is unique for each message within a (origin domain, destination domain) tuple. Many apps won't need to use this field, but it can be used to ensure uniqueness of a message.
_sender is the address that sent the message on the origin domain
_message contains the contents of the cross-chain message
/*
* @notice Receive a message from a sender on the origin domain
* @param _origin Domain of the origin chain
* @param _nonce Unique nonce for the (origin, destination) tuple.
* @param _sender Address of sender on origin chain as bytes32
* @param _message Raw bytes content of message
*/
function handle(
uint32 _origin,
uint32 _nonce,
bytes32 _sender,
bytes memory _message
) external;
Hello World
The example app we know and love - but make it cross-chain 🤝
import {TypeCasts} from "@nomad-xyz/contracts-core/libs/TypeCasts.sol";
contract HelloWorld {
// emitted when a Hello message is received
event Hello(uint32 origin, address sender, string memory message);
/*
* @notice Receive a Hello message from any sender :)
* @param _origin Domain of the origin chain
* @param _sender Address of sender on origin chain as bytes32
* @param _message Raw bytes content of message
*/
function handle(
uint32 _origin,
uint32 _nonce,
bytes32 _sender,
bytes memory _message
) onlyReplica {
address _sendr = TypeCasts.bytes32ToAddress(_sender);
// emit the message so off-chain friends can see it
emit Hello(_origin, _sendr, _message);
}
}
Example Usage
Ready to get a little more advanced? Let's play PingPong across chains 🏓
contract PingPong {
// registry of opponents on each chain
mapping(uint32 => bytes32) public opponents;
// emitted when a Ping volley is received
event Ping(uint32 domain, bytes32 opponent, uint256 volleyNumber);
// emitted when a Pong volley is received
event Pong(uint32 domain, bytes32 opponent, uint256 volleyNumber);
/**
* @notice Start a PingPong match with the destination chain
* by serving the ball.
* @param _destination The domain to initiate the match with
*/
function handle(
uint32 _origin,
uint32 _nonce,
bytes32 _sender,
bytes memory _message
) onlyReplica {
// validate the message comes from a known opponent
require(opponents[_origin] == _sender, "not a registered opponent!");
// decode the message contents using abi.decode
bool _ping;
uint256 _volley;
(_ping, _volley) = abi.decode(_message, (bool, uint256));
// emit an event for your off-chain spectators
if (ping) {
emit Ping(_origin, _sender, _volley);
} else {
emit Pong(_origin, _sender, _volley);
}
// send a PingPong message back to your opponent!
bytes memory _message = abi.encode(!_ping, _volley + 1);
// dispatch your message across chains
home.dispatch(_origin, _sender, _message);
}
}