- Send Workflow: How a crosschain message packet is created, fees calculated via the Message Library, and sent from the source chain.
- DVN Verification Workflow: How an application’s configured decentralized verifier networks (DVNs) initialize and later verify the message payload.
-
Executor Workflow: How the Executor program finally executes the message (invoking the receiving OApp via an
lzReceivecall).
Send Overview
When a user sends a crosschain message, the following high–level steps occur:Endpoint Program
-
Send Instruction on the LayerZero Endpoint:
TheSendinstruction is called on the Endpoint program via a CPI call from another program:- Increments the outbound nonce.
- Constructs a unique packet (including a GUID computed via a hash of parameters).
- Invokes the send library (e.g. ULN302) via CPI to calculate fee allocations and emit the corresponding events.
SendUln302 Program
-
Fee Quotation and Payment via CPI:
The send library (ULN302) uses instructions likeQuoteExecutorandQuoteDvnvia a series of CPI calls to programs such as the Executor and DVN. -
Endpoint Packet Emission:
Finally, after fee calculations and transfers, the Endpoint program emits an event (e.g.PacketSentEvent) and the packet is recorded onchain.
Verification Workflow
After the send operation, the DVNs must verify the message on the destination chain before message execution. On Solana, every account must be explicitly allocated with sufficient space. For DVN verification, this means a dedicated payload hash account is first created and initialized. This ensures that when a DVN writes its witness, the storage exists and is correctly sized.DVN Verification
Each DVN individually performs the following steps:-
Initialization with
ReceiveULN.init_verify:
The DVN callsinit_verifyon the ULN program to create and initialize a dedicatedConfirmationsaccount. Theinit_verifymethod initializes the Confirmations’s accountvaluefield asNone, and stores its PDA bump. -
Invocation with
invoke:
After initialization, the DVN triggers its own verification logic via aninvokeinstruction. This CPI call executes internal checks (such as signature verification and configuration validation) and, in the process, calls into the ULN’s verification logic by triggering a CPI call to theverifyinstruction. -
Final Verification via
ReceiveULN.verify:
Once the DVN’s internal verification logic completes and the conditions are met, the ULN program finalizes the DVN verification by calling its ownverifyfunction. This function updates the DVN-specific payload hash and emits aPayloadVerifiedEventto signal that the message has been verified by that DVN.
-
ReceiveUln.init_verify(): Initializes a dedicated payload hash account with an empty hash. -
DVN.invoke(): Executes the DVN’s internal verification logic and triggers the ULN’sverifyinstruction via a nested CPI. -
ReceiveUln.verify(): The ULN finalizes the verification by updating the payload hash and emitting aPayloadVerifiedEvent.
Commit Verification
After all required verifications have been submitted (meeting the X of Y of N configuration), the payload hash can then be committed. The commit verification process ensures that the verified message is recorded in the Endpoint’s messaging channel. This process comprises two primary steps:-
Initialization via
Endpoint.init_verifyon the Endpoint:
Before committing the verification, the system callsinit_verifyon the Endpoint. This creates and initializes a dedicated payload hash account, reserving space for the verification data. The account is set up with an initial empty payload hash (EMPTY_PAYLOAD_HASH) and a bump value for PDA derivation. -
Committing Verification via
commitVerificationon ReceiveUln302:
Once the payload hash account is initialized and DVN confirmations have been collected, theReceiveUln302.commitVerification()function is called to finalize the verification by:- Validating the Packet Header:
It checks that the header version is correct and that the destination endpoint ID (EID) matches the ULN302’s configured EID. - Verifying DVN Confirmations:
It calculates the number of DVN confirmation accounts (both required and optional) and uses helper functions (e.g.,check_verifiableandverified) to ensure that every DVN has provided sufficient confirmation. - CPI to the Endpoint’s
verifyInstruction:
If all checks pass, a CPI call is made to the Endpoint’sverifyfunction. This call updates the payload hash stored in the dedicated account and emits aPacketVerifiedEvent, thereby recording the verified message on the Endpoint’s messaging channel.
- Validating the Packet Header:
-
Insert Hash into the Endpoint’s Message Channel via
verify:
The Endpoint’sverifymethod is the final step in the commit verification process. Once invoked via CPI, it performs the following actions:- Nonce Management:
It checks if the packet’s nonce is greater than the current inbound nonce and updates the pending inbound nonce if necessary. - Updating the Payload Hash:
The verified payload hash is written into the payload hash account. - Event Emission:
APacketVerifiedEventis emitted, signaling that the packet has been verified and recorded onchain.
- Nonce Management:
-
Endpoint.init_verify(): Creates and initializes a dedicated payload hash account with an empty hash. -
ReceiveUln302.commitVerification(): Validates the packet header and DVN confirmations, then commits the verification by calling the Endpoint’sverifyvia CPI. -
Endpoint.verify(): Inserts the verified payload hash into the messaging channel, updates nonce management, and emits aPacketVerifiedEvent.
Receive Workflow
The Solana receive flow is divided into three primary stages:-
Execute:
The Executor program initiates the message execution process by calling itsexecuteinstruction. In this step, the Executor:- Gathers all required accounts.
-
Invokes downstream instructions via CPI to eventually call
lzReceive. - Checks that its lamport balance does not drop unexpectedly.
-
If the CPI call fails, an alert is triggered via
lzReceiveAlert.
-
LzReceiveTypes – Account Assembly:
ThelzReceiveTypesinstruction gathers all the accounts required by the final message execution. This step constructs the list of accounts—including PDAs for the peer, configuration accounts, token escrow (if needed), token destination, mint, and various system accounts—based on the parameters of the received message. -
LzReceive – Final Message Execution:
Finally, thelzReceiveinstruction executes the received message. This is where the actual processing occurs. In this step, the program must implement safety checks that clear the payload to prevent reentrancy and double execution. Specifically, it:- Clears the Payload:
Updates nonces, verifies that the payload hash matches the verified data, and deletes the message from storage. - Performs Token Operations (if applicable):
Depending on the message type, it may mint tokens or perform transfers. - Emits an Event:
Signals that the message has been successfully received and processed.
- Clears the Payload:
Key Solana-Specific Considerations
-
Explicit Safety Checks:
Unlike the EVM, where safety checks such as payload clearing are handled by a provided inheritance pattern, the Solana OApp must explicitly implement these checks within itslzReceivelogic. This includes updating nonces, verifying payload integrity, and deleting processed messages to prevent reentrancy or double execution. -
CPI and Account Assembly:
The flow (execute→lzReceiveTypes→lzReceive) relies on explicit CPI calls, with each instruction receiving a full list of pre-allocated accounts. There is no runtime dispatch or inheritance; all required accounts must be passed along manually. -
Token Operations:
When the message carries token transfers (as in OFT), token operations (transfer or mint) are executed withinlzReceivevia CPI calls to the Token Program.
lzReceive.