LayerZero V2 Part 2: How a Message Travels
This is Part 2 of a series on LayerZero V2. Part 1 covers the basics.
Let’s trace a message from Chain A to Chain B, step by step.
Phase 1: Sending (Chain A)
Step 1: Your app calls send() on the OFT contract
Step 2: OFT burns/locks tokens and builds the message
Step 3: OFT calls _lzSend() → EndpointV2.send()
Step 4: Endpoint routes to SendUln302 (the MessageLib)
Step 5: SendUln302 encodes the message into a Packet
Step 6: SendUln302 collects fees (DVN + Executor + treasury)
Step 7: SendUln302 emits an event with the packet dataAt this point, the message exists on Chain A as an event log. Nothing has happened on Chain B yet.
The Packet Structure
Every message becomes a Packet:
struct Packet {
uint64 nonce; // Sequential message counter
uint32 srcEid; // Source chain endpoint ID
address sender; // Your contract on Chain A
uint32 dstEid; // Destination chain endpoint ID
bytes32 receiver; // Your contract on Chain B (bytes32 for non-EVM)
bytes32 guid; // Globally unique ID for this message
bytes message; // The actual payload
}The guid is generated deterministically from the nonce, source, and destination. It uniquely identifies every message across all chains.
Phase 2: Verification (Off-Chain)
Step 8: DVNs monitor Chain A for LayerZero events
Step 9: Each DVN independently verifies the message
Step 10: Each DVN submits a verification attestation on Chain BThe DVNs work independently. They don’t talk to each other. Each one separately confirms “yes, this message is real” by:
- Checking the block header on Chain A
- Confirming the transaction exists
- Validating the packet data
- Waiting for the required block confirmations (e.g., 15 for Ethereum, 5 for L2s)
- Submitting a
payloadHashattestation on Chain B
Phase 3: Execution (Chain B)
Step 11: ReceiveUln302 checks: have enough DVNs verified?
Step 12: Executor calls EndpointV2.lzReceive()
Step 13: Endpoint calls your app's _lzReceive() → tokens minted/unlockedThe ReceiveUln302 checks two conditions:
- All required DVNs have verified ✓
- At least threshold optional DVNs have verified ✓
Only then can the message be delivered.
The Whole Flow
Chain A Off-Chain Chain B
App.send()
↓
Endpoint.send()
↓
SendUln302
↓ (emit event)
DVN 1 verifies ──→ attest on B
DVN 2 verifies ──→ attest on B
DVN 3 verifies ──→ attest on B
↓
ReceiveUln302
(quorum met?)
↓
Executor ──────→ Endpoint.lzReceive()
↓
App._lzReceive()
(mint tokens)Nonce Management
LayerZero uses nonces to track messages. There are three types:
- Outbound nonce: Incremented on every send. Sequential, never skipped.
- Inbound nonce: Tracks which messages have been verified on the destination.
- Lazy inbound nonce: Tracks the highest consecutively executed nonce.
Ordered vs Unordered Delivery
By default, messages can be executed in any order (unordered). But the nonce system still provides censorship resistance — all prior nonces must be verified before any nonce can execute.
For strict ordering, add addExecutorOrderedExecutionOption() to your options. This forces messages to execute in nonce order — but if message N fails, N+1, N+2… are blocked until N is resolved.
When Things Go Wrong
A Message Fails to Execute
The message is still verified. Anyone can retry by calling lzReceive() directly with the correct parameters. The Executor has no monopoly.
A Message Is Stuck
Recovery options:
| Action | What It Does | Who Can Call |
|---|---|---|
| Retry | Re-execute a failed message | Anyone |
| Skip | Skip a stuck nonce (message is lost) | OApp owner |
| Clear | Clear a stuck compose message | OApp owner |
| Nilify | Invalidate a maliciously verified message | OApp owner |
| Burn | Clean up nilified state | OApp owner |
Latency
How long does the whole process take?
- L2 → L2 (1 DVN): ~1-2 minutes
- Typical (2-3 DVNs): ~5-15 minutes
- High security (5+ DVNs): ~15-30 minutes
Latency = max(source finality wait, DVN verification time, destination execution)
The bottleneck is usually waiting for block confirmations on the source chain (15 blocks on Ethereum ≈ 3 minutes).
Next
- Part 3: The DVN Security Model — How verification works and what can go wrong