Skip to main content
The Omnichain Fungible Token (OFT) standard enables crosschain token transfers on Starknet. OFTs extend the OApp pattern with built-in token handling, allowing seamless movement of fungible tokens between chains.

What is an OFT on Starknet?

An OFT on Starknet is a Cairo contract that extends the OApp functionality to enable crosschain token transfers. It integrates with Starknet’s native ERC20 system (token contracts, approvals, and metadata) while providing LayerZero’s omnichain capabilities. This guide will walk you through OFT concepts on Starknet; currently OFTAdapter and OFTMintBurnAdapter are available for deployment. To understand how OFTs integrate with Starknet’s ERC20 system and the differences between mint/burn and lock/unlock token management strategies, see Integration with Starknet ERC20 System.

Integration with Starknet ERC20 System

OFT Types

Starknet provides three OFT variants for different use cases:
AvailabilityAt the moment, OFTAdapter and OFTMintBurnAdapter are available on Starknet. OFT is not yet supported for deployment.

Decision Matrix


OFT Adapter

Use when bridging an existing token where you cannot grant mint/burn permissions to the adapter.

How It Works

  • Send: Locks tokens in the adapter contract
  • Receive: Unlocks tokens from the adapter contract
  • Liquidity Required: Adapter must hold sufficient token balance
OFTAdapter class hash: 0x07085790a9702314791b55d7ac1e1202abf152174cc61d8fc3cab36ac4750171 (View on explorer)

OFT Mint/Burn Adapter

Use when bridging an existing token where you can grant mint/burn permissions to the adapter.

How It Works

  • Send: Burns tokens via minter contract
  • Receive: Mints tokens via minter contract
  • No Liquidity Required: Mint/burn eliminates liquidity constraints

Additional Features

The OFTMintBurnAdapter includes:
  • Rate Limiting: Control transfer volume per chain
  • Fee Collection: Charge fees on transfers
  • Pausability: Emergency pause functionality
  • Role-Based Access: Granular permission control
  • Upgradeability: Contract upgrade support
OFTMintBurnAdapter class hash: 0x07c02E3797d2c7B848FA94820FfB335617820d2c44D82d6B8Cf71c71fbE7dd6E (View on explorer)

Role Management

The OFTMintBurnAdapter uses OpenZeppelin’s AccessControl with the following roles:
Role ConstantsRoles are defined as short strings (felt252). To grant a role via sncast, use the string’s felt252 encoding. For example, 'FEE_MANAGER_ROLE' encodes to 0x4645455f4d414e414745525f524f4c45.

Deployment

Before building an OFT, install the required dependencies.
New to Starknet?If you haven’t used Starknet before, start with Getting Started on Starknet to understand the account model, tooling, and development basics.
Prerequisites:
  • Scarb and Starknet Foundry installed (see Getting Started)
  • Node.js and npm for installing LayerZero packages
  • A funded Starknet account and RPC URL for deployment (see Getting Started)
Deployment workflow for OFTMintBurnAdapter:
  1. Deploy ERC20MintBurnUpgradeable as your token
  2. Deploy OFTMintBurnAdapter with the token address as both erc20_token and minter_burner
  3. Grant the adapter’s address permission to mint/burn on the token contract

Step 1: Deploy ERC20MintBurnUpgradeable

For OFTMintBurnAdapter deployments, LayerZero provides a reference ERC20 token implementation with built-in mint/burn permissions: This contract:
  • Implements the IMintableToken interface
  • Supports role-based access for mint/burn permissions
  • Is upgradeable via OpenZeppelin’s UpgradeableComponent
The ERC20MintBurnUpgradeable class has been declared and has been verified - view on explorer.
Constructor parameters:
  • name (ByteArray) - Token name (use quoted string)
  • symbol (ByteArray) - Token symbol (use quoted string)
  • decimals (u8) - Token decimals (e.g., 18)
  • default_admin (ContractAddress) - Address granted DEFAULT_ADMIN_ROLE. You can set this to your address.
Running the above successfully would return an output like:
Copy the Contract Address and set it aside for use in the next step.

Step 2: Deploy OFTMintBurnAdapter

Constructor parameters:
  • erc20_token: ERC20 token contract address
  • minter_burner: Minter/burner contract address (use the token address)
  • lz_endpoint: LayerZero Endpoint address (0x0316d70a6e0445a58c486215fac8ead48d3db985acde27efca9130da4c675878 for Sepolia, 0x524e065abff21d225fb7b28f26ec2f48314ace6094bc085f0a7cf1dc2660f68 for Mainnet)
  • owner: Contract owner address (your deployer account)
  • native_token: Fee payment token (STRK token address shown above)
  • shared_decimals: Shared decimals across chains (u8, e.g., 6)
STRK Token AddressThe address 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d is the STRK token contract on Starknet (same on both Sepolia testnet and Mainnet). This is used to pay LayerZero messaging fees.
Network addressesFor endpoint IDs and LayerZero contract addresses, see Deployed Contracts.

Deployment for Custom OFT

If you need to build a custom OFT contract (e.g., with additional logic or modifications), follow these steps to set up your project before declaring and deploying. You can use the OFTMintBurnAdapter as a starting point.

Step 1: Install LayerZero Cairo Contracts

The LayerZero Cairo packages are currently published on NPM.

Step 2: Copy the contracts

Copy the contracts into your project’s directory:

Step 3: Modify dependency paths

In the Scarb.toml, remove the parent directory references in the path fields:

Step 4: Make your customizations

Modify the contract as necessary.

Step 5: Build, Declare, and Deploy


Core Operations

Sending Tokens

Step 1: Quote

Step 2: Get Messaging Fee

Step 3: Send


Decimal Precision

Token Amounts and u256

All token amounts in Starknet OFT contracts use u256, matching Solidity’s uint256 and OpenZeppelin’s Cairo ERC20 interface for crosschain compatibility.

Local vs Shared Decimals

OFTs use two decimal representations:

Dust Removal

When converting from local to shared decimals, precision is lost (“dust”):
Always use quote_oft before sending to see the exact amounts after dust removal and fees.

Configuration

After deployment, configure your OFT to enable crosschain transfers. Use the SDK for DVN/executor config and set peers last.
Critical orderConfigure security settings before setting peers. Setting peers opens the pathway.
Endpoint IDsFor endpoint IDs and LayerZero contract addresses, see Deployed Contracts.

SDK Setup

Install the SDK dependencies:
Create config.ts (or equivalent) and load your compiled artifact from target/release/*.contract_class.json:
Run the script:

Prerequisite: Set Delegate (required if configuring via external account)

Endpoint configuration calls (set_send_library, set_receive_library, set_send_configs, set_receive_configs) require the caller to be the OApp itself or an authorized delegate. If you’re configuring from an external account, set a delegate first (owner-only):
Use the address of the account that will submit the endpoint configuration transactions.

Step 1: Set Message Libraries (optional)

Use custom send/receive libraries when defaults are unavailable for your EID.
Configure ULN settings for both send and receive. DVN addresses must be sorted ascending.
Executor settings apply to send direction.

Step 4: Set Enforced Options (optional)

All OFT variants include the OAppOptionsType3Component for managing execution options. Use it to set minimum gas requirements per destination chain. If getOAppContract does not expose set_enforced_options, load your compiled artifact from target/dev/*.contract_class.json as shown in the SDK setup.
If you prefer sncast, you can call the entrypoint directly:
For <OPTIONS_BYTEARRAY>, pass a ByteArray expression (see the Starknet Foundry calldata transformation docs). With --arguments, use a raw ByteArray struct literal for arbitrary bytes, e.g. core::byte_array::ByteArray { data: array![0x..., 0x...], pending_word: 0x..., pending_word_len: 0 } (data are 31-byte chunks; pending_word_len is 0-30). Example: lzReceive gas = 120000, value = 0:

Step 5: Set Peer (required, last)

Set the remote peer after security configuration. EVM addresses must be left-padded to 32 bytes.
Configuration order:
  1. Set delegate (required if configuring via external account)
  2. Set message libraries (optional)
  3. Configure DVNs (recommended)
  4. Configure executor (recommended)
  5. Set enforced options (optional)
  6. Set peer (required, last)
See the Configuration Guide for detailed options encoding, DVN ordering, and gas recommendations.

Events

OFT-Specific Events


Best Practices & Deployment Checklist

  1. Install dependencies - npm install LayerZero packages
  2. Choose OFT variant based on your token situation
  3. Build contract via scarb build
  4. Declare contract via sncast declare
  5. Deploy contract via sncast deploy with --arguments
  6. Verify contract via sncast verify using Voyager or Walnut
  7. Configure DVNs and executor for security (see Configuration Guide)
  8. Set enforced options for minimum gas
  9. Set peers last on both chains (bidirectional)
  10. Test on testnet before mainnet deployment

Next Steps