structCRCMessage {uint8 version; // Version of the protocol this message confirms touint256 destinationChainId; // The “chain id” of the network this message is intended foruint64 nonce; // A nonce used as an anti-replay attack mechanism. Randomly generated by the user. address user; // An arbitrary address that is the actual sender of the message. Can be used by smart contracts that automate the messaging to specify the address of the user or be the same as the msg.sender.
address target; // The address of a contract that the CRC Smart contract will send the Payload to when finalizing the CRC.
bytes payload; // Arbitrary bytes that will be sent as calldata to the Execution Target address in the destination contract when finalizing the CRC.
uint256 stateRelayFee; // Fee in wei that the sender will be locking as a reward for the first relayer that brings the state containing this information inside the destination network.
uint256 deliveryFee; // Fee in wei that the sender will be locking as a reward for the first relayer that triggers the execution of the CRC delivery. Could be 0 if the Sender is willing to finalize it itself.
bytes extra; // Arbitrary bytes that will be sent alongside the data for dapps to make sense of }
Most of these can be fairly static. For example the Demo bridge uses the following parameters:
functionsendMessage(uint64 nonce,uint256 value) internal {bytesmemory payload = abi.encode(msg.sender, value); Types.CRCMessage memory message = Types.CRCMessage( WISP_VERSION,// 0 counterpartyChainId,// destination chain id nonce,// random nonce from the user msg.sender,// the sender counterparty,// the address of the bridge in the destination rollup payload,// the message payload0,// state relay fee0,// message relay fee hex""// extra data );bytes32 messageHash = outbox.sendMessage(message); }
Receiving Messages
In order to receive a message the target contract must conform to the following interface:
/// @notice Interface that the contracts receiving messages should implement/// @author Perseveranceinterface IMessageReceiver {/// @notice receives CRCMessageEnvelope/// @param envelope the message envelope you are receivingfunctionreceiveMessage(Types.CRCMessageEnvelopecalldata envelope,uint256 sourceChainId ) externalreturns (bool success);}
The target contract will be called by the relevant Inbox contract. In the demo this is the OptimismInbox contract for the destination rollup. This means that the target must ensure that their receiveMessage function is called by the inbox contract:
modifieronlyInbox() {require(msg.sender == inbox,"not sent by the inbox contract"); _; }
The full example from the demo app is:
functionreceiveMessage(Types.CRCMessageEnvelopecalldata envelope,uint256 sourceChainId ) externalvirtualonlyInboxreturns (bool success) {address receiver;uint256 value; (receiver, value) = abi.decode( envelope.message.payload, (address,uint256) );// Do something with the message and its payloadreturntrue; }
Contract addresses
The addresses for the currently supported rollups are: