Documentation menu

Executor options & gas

Every quoteSend*, send*, quoteRestore, and restoreFailedMessage call takes an options byte string that tells the LayerZero executor how much destination gas to buy. Omnisea uses standard type-3 options with a single executor lzReceive option.

Encoding

0x0003          uint16  options type (3)
  01            uint8   worker id (1 = executor)
  0021          uint16  option length (33 = 1 + 16 + 16)
  01            uint8   option type (1 = lzReceive)
  <gas>         uint128 destination execution gas
  <value>       uint128 destination msg.value (0 for token transfers)

Reference implementations:

TypeScript (viem)
import { concatHex, numberToHex, type Hex } from "viem";

export function lzReceiveOptions(gas: bigint, value = 0n): Hex {
  return concatHex([
    "0x000301002101",
    numberToHex(gas, { size: 16 }),
    numberToHex(value, { size: 16 }),
  ]);
}
Solidity (OptionsBuilder)
import { OptionsBuilder } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";

bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(400000, 0);

Gas floors

The bridge validates the lzReceive gas inside your options at send/restore time and reverts with InsufficientLayerZeroGas(provided, required) if it is below the floor for the transfer type:

SituationFloorBridge getter
Transfer to a chain where the representation exists (or to the home chain)400,000minTransferGas()
Restore to the source chain400,000minTransferGas()
First transfer - representation must be deployed (isFirstTransfer = true)500,000minCreationGas()

These floors are validation minimums, not recommendations for every route.

Route guidance

DestinationRecommended lzReceive gas
Base, Arbitrum, Polygon, BNB Chain, Optimism400,000 transfer / 500,000 creation
Tempo1,500,000 for both, until route-specific measurements lower it

Unused executor gas is not refunded to you, so don't massively overshoot - but undershooting causes a destination execution failure that must be retried or restored. When in doubt, round up.

Hook gas

If your transfer carries a hook, the hook's gasLimit executes within the same lzReceive budget. Buy transfer floor + hook gasLimit (or creation floor + hook gasLimit for first transfers); the bridge enforces this combined minimum at send time.

Matching quote and send

The options bytes are part of the priced message. Use byte-identical options in quoteSend* and send* - changing gas between quote and send changes the LayerZero fee and trips the exact-fee check.

Feedback