Skip to main content
Below is comprehensive documentation for Aptos Move OFT modules, explaining both the OFT and OFT Adapter, mirroring the LayerZero V2 OFT Standard you might see on EVM or Solana. The Omnichain Fungible Token (OFT) Standard allows fungible tokens to be transferred across multiple blockchains without asset wrapping or middlechains. This standard works by either debiting (burn / lock) tokens on the source chain, sending a message via LayerZero, and delivering a function call to credit (mint / unlock) the same number of tokens on the destination chain. This creates a unified supply across all networks that the OFT supports.

What is OFT?

An Omnichain Fungible Token (OFT) is a LayerZero-based token that can be sent across chains without wrapping or middle-chains. It supports:
  • Burn + Mint (OFT): Remove supply from the source chain, re-create it on the destination.
Diagram showing OFT burn-and-mint mechanism: tokens are burned (subtracted) on the source chain and minted (added) on the destination chain, connected by an arrow representing the crosschain transfer
  • Lock + Unlock (OFT Adapter): Move supply into an escrow on the source, release it on the destination.
Diagram showing OFT Adapter lock-and-unlock mechanism: tokens are locked in an escrow on the source chain and released on the destination chain On EVM, you see this logic embedded in an OFT.sol or OFTAdapter.sol contract. In Aptos Move, we achieve the same through specialized modules:
  1. oft::oft_fa – OFT “mint/burn” approach.
  2. oft::oft_adapter_fa – OFT Adapter “lock/unlock” approach.
  3. oft::oft – Unified interface for user-level send, quote, and receive entry points.
  4. oft::oft_core – Core bridging logic shared by both OFT and OFT Adapter.
  5. oft::oft_impl_config – Central config for fees, blocklisting, rate limits (used by both).
  6. oft::oft_store – Tracks shared vs. local decimals so each chain can represent the token with different local decimals if needed.
  7. oft::oapp_core / oft::oapp_store – The OApp plumbing for bridging messages crosschain, handling admin/delegate roles, peer configuration, etc.
The EVM/Solana OFT relies on ERC20/SPL logic for mint/burn or lock/unlock. The Aptos OFT relies on Move’s Fungible Asset standard. oft::oft_fa does actual mint/burn, while oft::oft_adapter_fa locks/unlocks an existing Fungible Asset in an escrow.

2. Relating the OApp and OFT Modules

The OApp Standard gives your contract the ability to:
  • Send crosschain messages (lz_send)
  • Receive crosschain messages (via lz_receive)
  • Quote crosschain fees
  • Enforce admin- or delegate-level controls
The OFT Standard then builds on top of that to specifically handle:
  • Fungible Asset bridging
  • Local token manipulations (burn/mint or lock/unlock)
  • Additional rate-limiting, blocklists, bridging fees, etc.
All crosschain calls still flow through lz_send and lz_receive in oft_core, which rely on the OApp’s ability to call the LayerZero Endpoint. This is exactly how the EVM OFT extends OApp to unify crosschain token operations.

OFT: oft::oft_fa

When tokens are sent crosschain, the module burns tokens from the sender’s local supply. On the receiving chain, it mints newly created tokens for the recipient. In EVM, you might see this with an ERC20 implementation that calls _burn in send() and _mint in lzReceive(). On Aptos, oft_fa.move uses Move’s FungibleAsset:
You will want to use the oft::oft_fa implementation when you want:
  • a brand new token on Aptos representing the crosschain supply.
  • each chain to independently mint/burn.
  • to bridge a new “canonical” supply for an existing non-Aptos asset on an Aptos chain.

Adapter OFT: oft::oft_adapter_fa

Instead of burning/minting tokens, the module locks tokens into an escrow on send and unlocks them from escrow on receive. This can be used if you already have an existing token on an Aptos Move chain that can’t share its mint/burn capabilities. On EVM, you might see an OFT that uses a “lockbox” to hold user tokens, sending representations of that held asset crosschain. The approach is the same on Aptos:
You will want to use the oft::oft_adapter_fa implementation when you:
  • have a pre-existing token on Aptos and cannot or do not want to grant mint/burn to the bridging contract.
The adapter approach “locks” user tokens, so be mindful of ensuring adequate liquidity in the adapter if bridging in from other chains.
Typically, only one chain uses the adapter approach (since the “escrow” is meant to represent the supply on that chain). Other chains should use full mint/burn logic.

Common Interface: oft::oft

Both oft_fa and oft_adapter_fa feed into the same top-level interface (oft::oft). This module:
  • Exposes user-facing functions like send_withdraw(...), send(...), quote_oft(...), etc.
  • Delegates the actual bridging logic to either “OFT” or “OFT Adapter” code (by depending on whichever you’ve chosen).
  • Implements the final lz_receive_impl(...) function so that crosschain messages from oft_core eventually call your credit(...).
Example from oft.move:

Core Logic: oft::oft_core

Regardless of whether it’s an OFT or OFT Adapter, the crosschain bridging sequence is the same:
  1. send(...) – Encodes the message, calls your debit function, and dispatches it over the LayerZero Endpoint.
  2. receive(...) – Decodes the message, calls your credit function, and optionally calls “compose” logic if there is a follow-up message.
In an EVM environment, OFT variants do something similar with _burn, _mint, or _transfer. The separation is conceptually the same.

Implementation Config: oft::oft_impl_config

Both OFT and OFT Adapter share the same configuration for:
  • Fees: fee_bps, fee_deposit_address.
  • Blocklist: Addresses can be disallowed from sending. Inbound tokens to them are re-routed to the admin.
  • Rate Limits: Each endpoint (chain) can be rate-limited to prevent large surges of bridging.
Example for setting fees:

Internal Store: oft::oft_store

Holds two critical values:
  1. shared_decimals: The universal decimals used across all chains.
  2. decimal_conversion_rate: The factor bridging from local decimals to shared decimals.
This matches the approach on EVM-based OFT, where you might define a consistent “decimals” across all chains, and each chain adapts locally if it wants a different local representation.

Comparison Between OFT and OFT Adapter

Putting It All Together

  1. Deploy & Initialize
    • Deploy the modules (oft_adapter_fa, oft_fa, oft, etc.).
    • Call init_module or init_module_for_test.
    • For the chosen path (native vs. adapter), run the relevant initialize(...) function (e.g., oft_fa.initialize or oft_adapter_fa.initialize).
  2. Configure
    • Adjust fees, blocklists, or rate-limits using oft::oft_impl_config.
    • For the adapter approach, ensure the escrow has enough tokens to handle inbound bridging from other chains.
  3. Sending
    • A user calls send_withdraw(...) from oft::oft.
    • This performs the local “debit” logic (burn or lock) and constructs a crosschain message.
    • Then calls the underlying lz_send(...) from the OApp layer.
  4. Receiving
    • The LayerZero Executor calls your OApp’s lz_receive_impl(...).
    • This triggers oft_core::receive(...), which decodes the message and calls your credit(...) logic (mint or unlock).
  5. Monitor
    • Check events: OftSent and OftReceived in oft_core.
    • Track blocklist changes, fee deposit addresses, and rate limit usage in oft_impl_config.

Conclusion

Whether you choose an OFT (mint/burn) or an OFT Adapter (lock/unlock):
  • The core bridging is consistent with the LayerZero V2 OFT Standard on EVM/Solana.
  • Fee, blocklist, and rate-limit logic is shared in oft_impl_config.
  • Message encoding/decoding and compose features align with oft_core.
  • Shared decimals plus local decimals ensure consistent crosschain supply.
OFT are perfect for new tokens that do not exist outside of the bridging context, while OFT Adapter allow you to adopt bridging on an existing, fully deployed token. Both approaches integrate seamlessly with LayerZero’s crosschain messaging on Aptos, providing a robust, modular framework for omnichain fungible tokens.