Lifecycle of a Message
Last updated
Last updated
In this document, we'll walk through an end-to-end example of sending a cross-chain message using Nomad.
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 dispatch
on the Home contract, enqueuing the message to be sent.
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 Dispatch
event is emitted, which signals to all relevant parties (ie. the Updater) that a new root has been generated.
This function emits an update
event which signals to Relayers that a new update has occurred.
A Relayer (which is trustless and permissionless), will call update
passing in the _oldRoot
, _newRoot
, and the _signature
which 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 prove
on 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.
Once handle
is 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.
The first step is Alice uses some interface (either the Token Bridge GUI or Etherscan) to construct a transaction to be sent to the BridgeRouter contract .
is an example of a xApp contract that follows . It exists as the entry point for users like Alice to interact with on the origin chain.
In this case, Alice's transaction will call the on the BridgeRouter.
Format the message to be sent, adhering to the contract
Once has been called on the Ethereum Home contract, the application router contract's job is done. This is where the Nomad protocol's work begins.
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.
As new roots are generated, the Updater calls 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.
Once an update has been made on the Home, anyone may call update
on any to effectively relay the new root to the destination chain.
An update on the Ethereum Home may be relayed to any number of Replicas corresponding to this Home, per . In this example, we will only cover the Moonbeam Replica.
After elapses, individual messages (ie. Alice's transaction to bridge 1000 USDC) can be proved against the new root.
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 process
on the Replica. The Replica will then forward the message to the BridgeRouter contract on Moonbeam, and invoke .
Astute readers may notice that we assumed that Nomad's optimistic dispute window elapsed without fraud being flagged. To learn more about how fraud detection, flagging and recovery works in Nomad, please check out in the Security section.