Starting on L2:
- Any account on L2 may call
OVM_L2CrossDomainMessenger.sendMessage()
with the information for the L1 message (akaxDomainCalldata
)- (ie.
_target
,msg.sender
,_message
) - This data is hashed with the
messageNonce
storage variable, and the hash is store in thesentMessages
mapping (this is not actually used AFAIK) - The
messageNonce
is then incremented.
- (ie.
- The
OVM_L2CrossDomainMessenger
then passes thexDomainCalldata
toOVM_L2ToL1MessagePasser.passMessageToL1()
- the
xDomainCalldata
is hashed withmsg.sender
(ie.ovmCaller
), and written to thesentMessages
mapping.
- the
Then on L1:
- The
Relayer
(and only theRelayer
) may callOVM_L1CrossDomainMessenger.relayMessage()
providing the raw message inputs and an L2 inclusion proof.- The relayer checks the following things:
- in
_verifyStateRootProof()
:- checks that the fraud proof window has closed for the batch to which the transaction belongs
- checks that the batch is stored in the
OVM_ChainStorageContainer
- (all state changing functions are
onlyOwner
protected in theOVM_ChainStorageContainer
)
- (all state changing functions are
- in
_verifyStorageProof()
:- checks the proof to confirm that the message data provided is in the
OVM_L2ToL1MessagePasser.sentMessages
mapping
- checks the proof to confirm that the message data provided is in the
- checks that this transaction has not already been written to the
successfulMessages
mapping.
- in
- The address of the L2 call is then written to the
xDomainMessageSender
state var - the call is then executed
- if it succeeds it is added to the
successfulMessages
and cannot be relayed again - regardless of success, and entry is written to the
relayedMessages
mapping
- The relayer checks the following things:
Then the receiver (in this case SynthetixBridgeToOptimism
):
- Checks that the caller is the
OVM_L1CrossDomainMessenger
and that thexDomainMessageSender
is thesynthetixBridgeToBase
on L2.