Cross Domain Messaging
Cross Domain Messaging
Cross Domain Messaging is a great approach to communicating between multiple domains and it allows us to send or receive messages to or from different domains. This section covers the sending and relaying of messages, either from L2 to L1 or from L1 to L2.
Note the following points in the case of Cross Domain Messaging:
From L2 to L1: Messages are validated by verifying the inclusion of the message data in a mapping of a contract on the L2 state.
From L1 to L2: Messages are validated simply by checking that the
ovmL1TXORIGINmatches the expected address.
Cross Domain Messengers Contracts (xDMs)
We have 2 low-level bridge contracts known as the L1 and L2 Cross Domain Messengers. These contracts are paired in the sense that they reference each other’s addresses in order to validate cross domain messages.
L2 to L1 Messaging Flow
Starting on L2
Stage 1: Any account on L2 may call the
L2CrossDomainMessenger.sendMessage()function with the information for the L1 message (aka xDomainCalldata). (i.e. _target, msg.sender, _message)Stage 2: This data is hashed with the
messageNoncestorage variable and the hash is stored in thesentMessagesmapping.Stage 3: The
messageNonceis then incremented.The L2CrossDomainMessenger contract then passes the
xDomainCallDatato theOVM_L2ToL1MessagePasser.passMessageToL1()function. Note thatxDomainCalldatais hashed withmsg.sender(i.e. ovmCaller) and written to thesentMessagesmapping.
Proceeding On L1
Stage 1: The Relayer may call
L1CrossDomainMessenger.relayMessage(), providing the raw message inputs and an L2 inclusion proof.Stage 2: The validity of the message is confirmed by the following functions:
_verifyStateRootProof(): This function checks that the fraud-proof window has been closed for the batch in which our transaction belongs to that. The function also checks that the batch is stored in theChainStorageContainer._verifyStorageProof(): This function checks the proof to confirm that the message data provided is in theOVM_L2ToL1MessagePasser.sentMessagesmapping. The function also checks that our transaction has not already been written to thesuccessfulMessagesmapping.
Stage 3: The address of the L2
ovmCALLERis then written to thexdomainMessageSenderstate variable.The call is then executed, allowing the target to query the value of the
L1CrossDomainMessenger.xDomainMessageSenderfor authorization.
Stage 4: In the case of a successful condition, it is added to the
successfulMessagesand cannot be relayed again.Stage 5: Regardless of the successful condition, an entry is written to the
relayedMessagesmapping.
The End
The receiver (i.e.
SynthetixBridgeToOptimism) checks that the caller is theL1CrossDomainMessengerand thexDomainSenderis thesynthetixBridgeToBaseon L2.
L1 to L2 Messaging Flow
Starting on L1
Stage 1: Any account may call the
L1xDM’s sendMessage()function, specifying the details of the call that the L2xDM should make.Stage 2: The L1xDM calls
enqueueon the CTC to add to the transaction queue with the L2xDM as thetarget. Note that the Transaction.data field should be ABI encoded to call theL2CrossDomainMessenger.relayMessage()function.
Proceeding on L2
Stage 1: A transaction will be sent to the
L2CrossDomainMessengercontract.Stage 2: The cross domain message is deemed valid if the
ovmL1TXORIGINis in theL1CrossDomainMessengercontract. If it is not valid, the execution reverts.Stage 3: If the message is valid, the arguments are ABI encoded and keccak256-hashed to
xDomainCalldataHash.Stage 4: The
successfulMessagesmapping is checked to verify thatxDomainCalldataHashhas not already been executed successfully. Note that if an entry is found insuccessfulMessages, execution reverts.Stage 5: A check is done to disallow calls to the
OVM_L2ToL1MessagePasser, which would allow an attacker to spoof a withdrawal. In this stage, execution reverts if the check fails.Future note: The
OVM_L2ToL1MessagePasser and this check should be removed in favor of putting thesentMessagesmapping into the L2xDM.
Stage 6: The address of the L2
ovmCALLERis then written to thexDomainMessageSenderstate variable. The call is then executed, allowing the target to query the value of theL1CrossDomainMessenger.xDomainMessageSenderfor authorization.Stage 7: In the case of a successful condition, the message is added to the
successfulMessages.
Please feel free to reach out to our Help Center if you have any technical questions.
Last updated