Lifecycle of a Message
In this document, we'll walk through an end-to-end example of sending a cross-chain message using Nomad.
Cross-chain message lifecycle
Let's use an example of a user, Alice, who wants to send 1000 USDC from her account on Ethereum to the same one on Moonbeam, using the Nomad Token Bridge application.
The BridgeRouter contract, triggered by Alice's transaction, will begin executing its business logic (as encoded by the app developer). In this case, it will:
- Perform basic validation (eg.
_amount > 0)
- Check whether the token to be sent is local or remote (USDC is local)
- Accordingly escrow or burn the amount to be sent (USDC will be escrowed)
After the business logic is executed, the BridgeRouter contract will call
dispatchon the Home contract, enqueuing the message to be sent.
The Home contract formats and hashes the message, and inserts it into its Merkle tree. The Merkle tree in the Home contract is the core data structure in Nomad, and contains all the messages to be sent from that Home.
The new message is inserted as a leaf, and then merkelized to generate a new Merkle root, which is stored in the Home's queue. Finally, a
Dispatchevent is emitted, which signals to all relevant parties (ie. the Updater) that a new root has been generated.
As new roots are generated, the Updater calls the
updatefunction on the Ethereum Home contract, committing to the current root and the new root with their digital signature. This signature acts as an attestation on the accumulator root, which can now be relayed to a destination chain.
This function emits an
updateevent which signals to Relayers that a new update has occurred.
A Relayer (which is trustless and permissionless), will call
updatepassing in the
_newRoot, and the
_signaturewhich the Updater generated. This will "kick off" the dispute window for the new root, after which messages can be proven and processed.
To prove a message, anyone can call
proveon the Replica contract, passing in a leaf corresponding to the message, merkle path and index of the leaf to prove inclusion in the new root.
If this succeeds, the message will be processed, meaning it will be forwarded to the corresponding application router on the destination chain.
In this case, a Processor (which is also trustless and permissionless) will prove inclusion of Alice's message in the new root, and then call
processon the Replica. The Replica will then forward the message to the BridgeRouter contract on Moonbeam, and invoke its
handleis called on the Moonbeam BridgeRouter, the BridgeRouter will execute application business logic on its side to complete the bridging process for Alice. In this case, it will mint 1000 Nomad USDC (or madUSDC) to Alice's address on the Moonbeam side.
Voila! We have successfully bridged tokens and sent a message via Nomad.