OFT V1.2 (legacy)

Omnichain Fungible Token that supports both EVMs and non EVMs


OFT V1.2 is NOT built on LayerZero V2. Looking for LayerZero V2's OFT Standard? Head to the LayerZero V2 OFT Docs!


npm i @layerzerolabs/solidity-examples
Breaking changes were introduced with OpenZeppelin V5. You should only use OpenZeppelin contract versions lower than 5.x.x to maintain compatibility with broader contract libraries.


Most of the LayerZero contracts are expected to be used via inheritance: you will inherit from them when writing your own contracts.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@layerzerolabs/solidity-examples/contracts/token/oft/v2/OFTV2.sol";
contract MyOFTV2 is OFTV2 {
string memory _name,
string memory _symbol,
uint8 _sharedDecimals,
address _lzEndpoint) OFTV2(_name, _symbol, _sharedDecimals, _lzEndpoint) {}
// ... your contract logic here



Use this extension when you want to turn an already deployed ERC20 into an OFTV2. You can then deploy OFTV2 contracts on the LayerZero-supported chains of your choosing. When you want to transfer your OFT from the source chain the OFT will lock in the ProxyOFTV2 and mint on the destination chain. When you come back to the ProxyOFTV2 chain the OFT burns on the source chain and unlocks on the destination chain.

How to deploy ProxyOFT and OFT Contracts

  1. 1.
    Deploy your ProxyOFT contract using your ERC-20 address, and specify the shared decimals (ie. where your ERC-20 decimals > shared-decimals).
  2. 2.
    Deploy your OFT contract on the other connected chain(s) and specify the shared decimals in relation to your ERC-20 & ProxyOFT.
  3. 3.
    Set your contracts to trust one another using setTrustedRemoteAddress. Pair them to one another's chain and address.
  4. 4.
    Next, we're going to set our minimum Gas Limit for each chain. (Recommended 200k for all EVM chains except Arbitrum, 2M for Arbitrum). Call setMinDstGas with the chainId of the other chain, the packet type ("0" meaning send, "1" meaning send and call), and the gas limit amount.
  5. 5.
    Required only for ProxyOFT: Finally, approve your ProxyOFT as a spender of your ERC20 token by calling your deployed ERC20's approve function. This comes standard in the ERC20 interface, and is required when using an intermediary contract to spend token amounts on behalf of the caller.
(Make sure that your AdapterParams gas limit > setMinDstGas)
If providedGasLimit >= minGasLimit, it'd fail: "LZApp: gas limit is too low", where providedGasLimit is _getGasLimit( provided in _adapterParams) and minGasLimit is minDstGasLimit


If I only have tokens on EVM chains, can I use V2?
Yes, you can, just make sure to set shared decimals as <= 10 if your token decimals are 18.
What is shared decimals?
Shared Decimals is used to normalize the data type difference across EVM chain and non-Evm. Non-evm chains often has a Uint64 data type which limits the decimals of the token to a lower amount. Shared Decimals accounts for this and translates the higher decimals of EVM to lower decimals of non-evm.
What should I set as shared decimals?
If your token is deployed on non-evm chains, it should be set as the lowest decimals across all chains. For example, if your token is deployed on Aptos as decimal 6 and your Ethereum token is deployed as decimal 18. Shared Decimals should be set as 6.
If your tokens are only deployed on EVM chains and all have decimals larger than 8, it should be set as 8. For example, your tokens on all EVM chains have decimals of 18, the shared decimals on all chains should be set as 8.
shared decimals should be set lower than 8 if you want a larger maximum send amount. Check below.
How does shared decimals affect my OFT?
It affects the minimum and maximum tokens you can send cross-chain.
The minimum tokens you can send: 10 * ( 10^( decimals - _sharedDecimals))
The maximum tokens you can send: 18,446,744,073,709,551,615 * ( 10^( decimals - _sharedDecimals))