Skip to article content Layerzeroscan

Layerzeroscan separates lzReceive execution from optional lzCompose calls

Layerzeroscan distinguishes lzReceive execution from optional lzCompose execution when tracking LayerZero V2 messages on the destination blockchain. In the EVM composition flow, the receiving application handles lzReceive, while a composer contract handles the later call. Separate execution records show whether the destination application processed the message and whether its composed action succeeded. Queuing a compose payload does not confirm its execution. An operation requiring composition needs the composer result as well as the receive result.

Shared destination context and separate callbacks

Both callbacks belong to destination-side execution in the LayerZero V2 EVM model, with composition following the receiving application’s initial handling of a message. An Omnichain Application (OApp) implements the receiving logic. A composer contract implements the optional follow-up logic. Each callback can change application state, although the receiving contract and composer have distinct responsibilities.

The destination Endpoint routes these calls, while an Executor provides the configured delivery service. The explorer reports their outcomes. The receiving application supplies the message’s globally unique identifier (GUID) when queuing composition. The destination application receives the cross-chain payload; the composer receives the follow-up payload the application prepares.

Verification before receive execution

Configured source confirmations and Decentralized Verifier Network (DVN) checks precede destination reception, so verification progress answers a different question from either callback result. The API separates verification fields from destination execution fields. Verification establishes whether the message has met its configured verification requirements. It does not run the application’s receive logic or the composer’s follow-up logic. Execution still depends on the destination contracts and the resources available for their calls.

Receive execution and application state

Receive execution begins when the destination Endpoint invokes the receiving application with the verified message and the application’s logic processes its contents. In the EVM OApp pattern, lzReceive reaches the internal _lzReceive implementation. That implementation determines the message’s immediate effect, such as updating application state or crediting tokens through an Omnichain Fungible Token (OFT) contract.

The Scan API uses destination.status to track lzReceive execution on the destination chain. SUCCEEDED confirms this receive execution. The field says nothing by itself about a separate composer callback’s success. The contract code determines which application changes that successful invocation includes.

Base EVM OFT receive logic credits the destination recipient before queuing any configured composition.

The base EVM OFT flow credits tokens to its configured to address, which identifies the composer when composition is intended. That credit does not establish that a final wallet received the output of the composer’s later operation. The token recipient and any later output recipient can differ.

Queued composition and its message inputs

In the receiving-application flow, the OApp calls sendCompose with the target composer, message GUID, compose index, and encoded payload for the follow-up action. The Endpoint records the payload hash and emits a ComposeSent event. The base EVM OFT flow queues composition only when the incoming message includes compose data.

The sendCompose operation queues work; it does not execute the composer’s callback. The standard EVM OFT flow prepares compose data for execution in a separate transaction. During lzCompose execution, the Endpoint checks the supplied payload against the queued hash before invoking the composer. The composer then decodes the payload using its expected format.

The composer should authenticate its calling Endpoint and expected compose sender before executing a payload. The base EVM OApp receiver identifies itself as the compose-message sender by default; custom implementations can allow other senders. A matching GUID alone does not establish a trusted application. The receiver separately checks its Endpoint and configured source peer.

Can lzCompose fail after lzReceive succeeds?

A separate lzCompose call can fail after lzReceive succeeds, leaving a successful receive result alongside an unsuccessful compose result in the message record.

A failed compose call does not revert an earlier successful receive transaction in the separate-transaction EVM composition flow. For standard composed OFT delivery, the earlier token credit therefore remains intact. The destination tokens can remain at the composer while its follow-up action remains incomplete.

A receive result of SUCCEEDED and a compose result of FAILED describe different calls, so they can coexist. Treating the failed follow-up as a failed initial credit would misidentify the operation needing attention.

The composer contract contains the business logic behind the failed action. Any available retry or recovery must fit that implementation and the actual failure. A later attempt can encounter the same contract condition or resource shortage. The failure status alone supplies neither a refund instruction nor a promised recovery time.

Layerzeroscan: Can lzCompose fail after lzReceive succeeds?

View full-size image

Separate gas budgets and execution funding

Executor options allocate gas and native value to receive and compose callbacks separately, and the composed call’s index selects its corresponding execution allowance. The receive option controls lzReceive . The compose option controls the indexed lzCompose call. The gas limit caps computation, while msg.value specifies native currency supplied with the callback. A larger receive allowance does not automatically enlarge a compose allowance.

Composition also creates work inside the initial receive call: constructing and queuing its payload consumes receive-side gas. The later composer call needs resources for its own logic. Longer payloads and more complex destination code can increase these requirements. The transaction quote reflects configured execution requirements alongside verification and service costs. Destination gas pricing and token conversion affect that quote.

Which callback result confirms the intended action?

An action implemented entirely by receive logic needs its receive outcome; an action requiring a composer also needs that callback’s successful execution result.

  1. Identify whether the intended operation ends in the receiving application or includes a queued composer action. A destination.lzCompose.status value of N/A means this message has no compose call.
  2. Read destination.status : WAITING describes pending execution, VALIDATING_TX marks a submitted execution transaction, and SUCCEEDED confirms receive execution.
  3. If composition applies, read destination.lzCompose.status separately: WAITING means lzCompose has not run, VALIDATING_TX records transaction submission, and SUCCEEDED confirms successful compose execution.
  4. For composed OFT delivery, distinguish tokens credited to the composer from the intended output of its follow-up action.
  5. When receive execution succeeds and composition fails, locate the failure in the composer action without reclassifying the earlier receive result.

Inline calls and asynchronous composition

LayerZero V2 EVM applications support inline contract calls inside receive logic as well as queued composition, creating different boundaries for application state changes. An EVM OApp can call other contracts directly from its _lzReceive implementation. Those calls share the receive transaction. An uncaught revert in an inline call rolls back the receive call’s state changes. This scope concerns destination execution, not an automatic rollback of the original source transaction.

Horizontal composition moves the follow-up into the separate composer execution context. That separation changes failure handling and resource allocation; it does not change what the application asked the composer to do. Contract interactions inside receive logic therefore do not automatically represent lzCompose activity. The EVM interface for a dedicated composer callback is IOAppComposer .

Layerzeroscan: quick answers

What does WAITING_FOR_COMPOSE_SENT_EVENT mean in a compose record?

WAITING_FOR_COMPOSE_SENT_EVENT means the Scan API is waiting for the compose-sent event. This status does not establish a successful lzCompose invocation or an executed composer transaction. It differs from WAITING, which identifies an lzCompose call that has not yet occurred.

Can one lzReceive invocation create multiple composed messages?

Custom OApps can queue multiple composed messages from one lzReceive execution. The base EVM OFT implementation queues one composed message at index 0 when its incoming message includes composition. Additional composed calls require custom receive logic. One successful composed call does not prove that every queued call succeeded.

Does a native token drop confirm that lzCompose ran?

A successful native token drop confirms the drop, while destination.lzCompose.status separately reports composed execution. The destination.nativeDrop.status field describes the native drop’s outcome. Its N/A value means this message includes no native drop. These fields distinguish funding a destination address from running the composer’s application code.

Which status distinguishes a simulated compose revert from failed compose execution?

The destination.lzCompose.status value SIMULATION_REVERTED identifies a reverted lzCompose simulation. FAILED identifies failed compose execution, while VALIDATING_TX means a compose transaction has been submitted. A simulation result alone does not establish an on-chain execution attempt. An Executor can catch a compose revert, so FAILED need not mean the outer transaction reverted.

Do repeated lzCompose options replace an earlier gas allocation?

Repeated lzCompose options add their gas and msg.value amounts together for the same compose index. They do not replace earlier amounts. Options for different indexes retain separate totals. These rules determine execution allowances; the application’s actual sendCompose calls determine how many composed messages it queues.

- last updated