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
ovmL1TXORIGIN
matches 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: A whitelisted 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
messageNonce
storage variable and the hash is stored in thesentMessages
mapping.Stage 3: The
messageNonce
is then incremented.The L2CrossDomainMessenger contract then passes the
xDomainCallData
to theOVM_L2ToL1MessagePasser.passMessageToL1()
function. Note thatxDomainCalldata
is hashed withmsg.sender
(i.e. ovmCaller) and written to thesentMessages
mapping.
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.sentMessages
mapping. The function also checks that our transaction has not already been written to thesuccessfulMessages
mapping.
Stage 3: The address of the L2
ovmCALLER
is then written to thexdomainMessageSender
state variable.The call is then executed, allowing the target to query the value of the
L1CrossDomainMessenger.xDomainMessageSender
for authorization.
Stage 4: In the case of a successful condition, it is added to the
successfulMessages
and cannot be relayed again.Stage 5: Regardless of the successful condition, an entry is written to the
relayedMessages
mapping.
The End
The receiver (i.e.
SynthetixBridgeToOptimism
) checks that the caller is theL1CrossDomainMessenger
and thexDomainSender
is thesynthetixBridgeToBase
on 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
enqueue
on 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
L2CrossDomainMessenger
contract.Stage 2: The cross domain message is deemed valid if the
ovmL1TXORIGIN
is in theL1CrossDomainMessenger
contract. 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
successfulMessages
mapping is checked to verify thatxDomainCalldataHash
has 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_L2ToL1MessagePasse
r and this check should be removed in favor of putting thesentMessages
mapping into the L2xDM.
Stage 6: The address of the L2
ovmCALLER
is then written to thexDomainMessageSender
state variable. The call is then executed, allowing the target to query the value of theL1CrossDomainMessenger.xDomainMessageSender
for 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