Skip to main content
Frequently asked questions about developing LayerZero applications on IOTA L1.

General Questions

IOTA Move lacks native dynamic dispatch (unlike EVM’s delegatecall). The Call<Param, Result> pattern provides an alternative by creating structs without drop or store abilities that must be consumed, using capability-based authorization, and enforcing call sequences through lifecycle states while ensuring atomicity within Programmable Transaction Blocks.For a detailed explanation of the Call pattern and IOTA’s architecture, see the IOTA documentation on PTBs.
The key difference is that IOTA uses Call objects and PTBs instead of delegatecall. In EVM, the relayer calls Endpoint.lzReceive() which delegates to the OApp. In IOTA, the Executor calls Endpoint.lz_receive() which creates a Call<LzReceiveParam, Void> object that the OApp destroys and processes via explicit PTB routing. Both execution models are permissionless.For architectural details, see Technical Overview and Protocol Overview.

Development Questions

No. LayerZero deploys and maintains the EndpointV2 shared object on IOTA L1. You only need to:
  1. Publish your OApp or OFT package
  2. Register your OApp with the Endpoint (creates a MessagingChannel)
  3. Configure pathways to other chains
OFTs use shared decimals to handle precision differences:
When sending:
  1. Amount is divided by conversion rate (removes dust)
  2. Truncated amount is sent crosschain
  3. Destination multiplies by its conversion rate
See OFT Overview for examples.
Yes, use an OFT Adapter (lock/unlock model):
For new tokens, use mint/burn OFT for better efficiency.

Gas and Fees

IOTA uses a dual gas model:Storage Gas:
  • Charged for creating objects
  • Refunded when objects are deleted
  • Can result in negative net gas
Computation Gas:
  • Charged for execution
  • Not refunded
For LayerZero:
  • Minimum 1000 base gas units
  • Budget 5-20M for typical operations
  • Source chain pays destination execution
Negative gas is normal when storage is freed:
Key Points:
  • This is not an error
  • Still need minimum 1000 base budget
  • Net cost can be negative
  • Rebate goes to transaction sender
See Technical Overview for details.
Recommended gas budgets:Start higher and reduce based on actual usage.

Configuration Questions

No, defaults are available:
Custom configuration is optional for:
  • Specific security requirements
  • Custom DVN sets
  • Private executors
Use the TypeScript SDK:
The IOTA CLI cannot easily parse complex return values.
Yes, if you retain the AdminCap:
Without AdminCap, configuration is immutable.

SDKs and Tooling

LayerZero provides two TypeScript SDKs:
  1. @layerzerolabs/lz-iotal1-sdk-v2
    • Core Endpoint interactions
    • OApp functionality
    • Configuration management
  2. @layerzerolabs/lz-iotal1-oft-sdk-v2
    • OFT-specific operations
    • Token transfers
    • Balance queries
See OFT SDK for usage examples.
The IOTA CLI can read simple fields but has limitations for complex queries:
  • Doesn’t easily parse return values from view functions
  • Manual decoding needed for bytes arrays and nested structs
  • No built-in formatting for complex types
Solution: Use TypeScript SDK for complex state queries:
Not currently. Package publication and configuration require:
  1. Publish packages: Using iota client publish
  2. Call entry functions: Invoke configuration functions via iota client call or SDK
  3. Custom scripts: Write TypeScript scripts for automated workflows
See Configuration Guide for manual setup instructions.

Troubleshooting

This error means a Call object wasn’t properly consumed in your PTB:
Solution: Every Call returned must be confirmed/destroyed before the transaction completes.
You’re trying to send to a destination chain without a MessagingChannel:
The Endpoint creates a dedicated MessagingChannel shared object for each OApp.
Use recovery entry functions on the Endpoint (requires AdminCap):Skip a message (increment nonce without execution):
Clear a message (mark as delivered without execution):
See Common Errors for more recovery options.

Security Questions

Follow these capability-based security practices:
  1. Validate CallCap in All Functions:
  1. Validate Call Objects:
  1. Secure Capability Objects:
  • Store CallCap in package module storage (not transferred)
  • Use multisig or hardware wallet for AdminCap
  • Never expose capabilities publicly
  • Transfer AdminCap carefully (use transfer::public_transfer)
  1. Protect UpgradeCap:
  • Keep upgrade authority secure
  • Consider freezing upgrades after deployment (package::make_immutable)
  • Use multisig for mainnet upgrade authority
    • Missing CallCap validation in functions
    • Not validating Call object source (callee address)
    • Skipping peer validation in lz_receive
    • Losing capability objects (no recovery possible)
    • Wrong peer addresses configured
    • Exposing AdminCap or CallCap publicly
See OApp Best Practices for details.

Next Steps