Skip to main content
lzAsset contracts implement the standard IOFT interface for Omnichain Fungible Tokens (OFTs). However, transferring between the Native Mesh (issuer-controlled) and the lzAsset Mesh (LayerZero-managed) requires routing through a Hub Chain using the MultiHopComposer. For architecture and concepts, see lzAsset Managed Service.

The IOFT Interface

All lzAsset token contracts (on both Native and lzAsset chains) implement the standard IOFT interface. You interact with them using the standard send() and quoteSend() methods, identical to any other OFT deployment.

Transfer Types

There are two types of transfers in the lzAsset ecosystem:
  1. Direct Transfers (Within the same mesh)
    • Within the lzAsset mesh: Standard OFT transfer.
    • Native to Native: Standard OFT transfer (if multiple native chains exist).
  2. Cross-Mesh Transfers (Between meshes)
    • Native → lzAsset: Must route through the Hub Chain.
    • lzAsset → Native: Must route through the Hub Chain.

Direct Transfers (Standard)

For transfers within the same mesh (e.g., lzAsset chain A to lzAsset chain B), simply construct a standard SendParam with the destination endpoint ID and recipient address. No special composition is required.

Cross-Mesh Transfers (Multi-Hop)

To move assets between the Native Mesh and the lzAsset Mesh, the transfer must be routed through the MultiHopComposer on the Hub Chain. This is a two-hop process:
  1. Hop 1: Source Chain → Hub Chain (Composer)
  2. Hop 2: Hub Chain (Composer) → Destination Chain
You initiate this entire flow from the source chain by encoding the instructions for the second hop into the composeMsg of the first hop.

Constructing the Send

You must construct two SendParam structs: one for the final destination (Hop 2) and one for the Hub (Hop 1).

1. Prepare the Second Hop (Hub → Destination)

First, define where the tokens should go after they reach the Hub.

2. Prepare the First Hop (Source → Hub)

Next, wrap the second hop inside the parameters for the first hop. The destination is the Hub Chain, and the recipient is the MultiHopComposer contract. Critical Requirements:
  • dstEid: Must be the Hub Chain ID.
  • to: Must be the address of the MultiHopComposer on the Hub.
  • composeMsg: Must be the encoded nextHopParam from Step 1.
  • Gas & Value: You must pay for the second hop’s gas and fee on the source chain.

Full Implementation Example

Here is a complete Solidity example of how to format and send a cross-mesh lzAsset transfer.

composeMsg Encoding

When you call send() with a composeMsg, the OFT automatically wraps your data with additional context before delivering it to the composer:
  • nonce - Transaction tracking
  • srcEid - Source chain endpoint ID
  • amountLD - Amount transferred
  • composeFrom - Original sender address (bytes32)
  • Your composeMsg payload
The MultiHopComposer uses OFTComposeMsgCodec.composeMsg(_message) to extract your encoded SendParam from the full message.

Fee Estimation

Estimating the fee for a multi-hop transaction requires a two-step process because the source chain cannot directly quote the cost of the second hop (Hub → Destination).

Step 1: Quote the Second Hop (Hub → Destination)

You must call IOFT.quoteSend() on the Hub Chain’s OFT contract (the lockbox or adapter) to get the exact fee for the transfer from Hub to final destination. This quote must be obtained off-chain before constructing your source transaction:

Step 2: Pack Quote into First Hop Options

Once you have the nativeFee for the second hop, include it in the options for the first hop (Source → Hub):
  1. Add lzReceiveOption: Gas for the Hub OFT’s _lzReceive (credits tokens + calls sendCompose)
  2. Add lzComposeOption: Gas for MultiHopComposer.lzCompose() execution, plus the nativeFee as msg.value
  3. Quote First Hop: Call quoteSend() on the source chain. The returned fee includes everything needed for the full journey.

Fee Flow

The msg.value passed via addExecutorLzComposeOption is delivered to the MultiHopComposer on the Hub. The composer then uses this value to pay for the IOFT.send() call that initiates the second hop.

Finding Addresses

Always verify the correct MultiHopComposer address for your specific lzAsset token pair. Some deployments may use different Hub chains or composer instances.