- ONFT Contract: Uses a burn-and-mint mechanism. For a fluid NFT that can move directly between chains (e.g. Chain A and Chain B), you must deploy an ONFT contract on every chain. This creates a “mesh” of interconnected contracts.
- ONFT Adapter: Uses a lock-and-mint mechanism. If you already have an NFT collection on one chain and want to extend it omnichain, you deploy a single ONFT Adapter on the source chain. Then, you deploy ONFT contracts on any new chains where the collection will be transferred. Note that only one ONFT Adapter is allowed in the entire mesh.
ONFT (Burn & Mint)

- Default pattern for new NFT collections.
ONFT721extendsERC721(OpenZeppelin) and adds crosschain logic.- Unified supply across chains is maintained by burning on source, minting on destination.
ONFT Adapter (Lock & Mint)
- Suitable for existing NFT collections.
- The adapter contract is effectively a “lockbox” for your existing ERC721 tokens.
- No changes to your original NFT contract are required. Instead, the adapter implements the crosschain logic.
Installation
To start using theONFT721 and ONFT721Adapter contracts, you can either create a new project via the LayerZero CLI or add the contract package to an existing project:
New project
If you’re creating a new contract, LayerZero providescreate-lz-oapp, an npx package that allows developers to create any omnichain application in less than 4 minutes. Get started by running the following from your command line and choose ONFT721 when asked about a starting point. It will create both ONFT721 and ONFT721Adapter contracts for your project.
Existing project
To use ONFT in your existing project, install the @layerzerolabs/onft-evm package. This library provides bothONFT721 (burn-and-mint) and ONFT721Adapter (lock-and-mint) variants.
- npm
- yarn
- pnpm
- forge
- Use
ONFT721when you’re creating a new NFT collection that will exist on multiple chains. - Use
ONFT721Adapterwhen you need to make an existing NFT collection crosschain compatible.
ONFT721 Implementation
Deploy an ONFT that inherits fromONFT721, which combines ERC721 with the crosschain functionality needed for omnichain transfers. The contract automatically handles token burning on the source chain and minting on the destination chain.
You can pass in your chosen contract name, symbol, the LayerZero Endpoint address, and the contract’s delegate (owner or governance address). This contract becomes the “canonical” NFT on every chain.
ONFT721Adapter Implementation
Deploy an ONFT Adapter that references your existing NFT contract address. TheONFT721Adapter constructor takes an additional parameter _token, which is the address of the existing ERC721 token that you want to make crosschain compatible.
Deployment Workflow
The deployment process for ONFT contracts involves several steps, which we’ll cover in detail:- Deploy the ONFT or ONFT Adapter contracts to all the chains you want to connect.
- Configure peer relationships between contracts on different chains.
- Set security parameters including Decentralized Validator Networks (DVNs).
- Configure message execution options.
1. Deploy ONFT Contracts
First, deploy your ONFT contracts to all the chains you want to connect: For new NFT collections:- Deploy
MyONFT721on all chains.
- Deploy
MyONFT721Adapteron the chain where the original NFT exists. - Deploy
MyONFT721on all other chains you want to connect.
2. Configure Security Parameters
Set the DVN configuration, including block confirmations, security thresholds, executor settings, and messaging libraries:EndpointV2 contract and control how messages are verified and executed. If you don’t set custom configurations, the system will use default configurations set by LayerZero Labs.
We strongly recommend reviewing these settings carefully and configuring your security stack according to your needs and preferences.
You can find example scripts to make these calls in Security and Executor Configuration.
3. Configure Peer Relationships
After deployment, you need to callsetPeer on each contract to establish trust between ONFT contracts on different chains.
Set peers by calling setPeer(dstEid, addressToBytes32(remoteONFT)) on every chain. This whitelists each destination as the trusted contract to receive your message.
4. Configure Message Execution Options
[Optional but recommended] ONFT inheritsOAppOptionsType3 from the OApp standard. This means you can define:
- enforcedOptions: A contract-wide default that every
sendmust abide by (e.g. minimum gas forlzReceive, or a maximum message size). - extraOptions: A call-specific set of execution settings or advanced features, such as adding a “composed” message on the remote side.
myONFT.send(...) must pay at least 100_000 gas on the remote chain for the bridging operation. This is useful for ensuring there’s enough gas on the destination chain to execute the bridging operation and to receive the bridged tokens.
enforcedOptions should only be set for msgType: SEND, to make sure there’s enough gas on the destination chain to execute the bridging operation and to receive the bridged tokens.
See Message Execution Options for more details.
Using ONFT Contracts
Estimating Gas Fees
Before callingsend, you’ll typically want to estimate the fee using quoteSend.
Similar to OFT, you can call quoteSend(...) to get an estimate of how much msg.value you need to pass when bridging an NFT crosschain. This function takes in the same parameters as send but does not actually initiate the transfer. Instead, it queries the Endpoint for an estimated cost in nativeFee.
Arguments of the estimate function:
SendParam(struct): which parameters should be used for thesendoperation?
payInLzToken(bool): which token (native or LZ token) will be used to pay for the transaction?truefor LZ token andfalsefor native token.
quoteSend function:
SendParamstruct with all the parameters needed to send the NFT crosschainquoteSendfunction to estimate the fee before sending the NFT crosschainrefundAddressparameter to specify the address to refund if the transaction fails on the source chain (default is the sender’s address)
Sending NFTs Across Chains
To transfer an NFT to another chain, users call thesend function with appropriate parameters:
_debit function with any additional logic you want to execute before the message is sent via the protocol, for example, taking custom fees.
Example Client Code
Here’s how thesend function can be called, as a Hardhat task for an ONFT Adapter contract:
- Hardhat Task
sendNFT.ts in the tasks directory and run the command below to send the NFT.This assumes that you have already deployed the adapter contract on Sepolia (testnet) and are sending the NFT to a recipient on Polygon Amoy (testnet).send:
- ONFT will
_burnin the source chain contract,_mintin the destination chain contract. - ONFT Adapter will
transferFrom(...)tokens into itself on the source chain (locking them), then_mintor_unlockon the destination.
Receiving the NFT (_lzReceive)
A successful send call will be delivered to the destination chain, invoking the _lzReceive method during execution on that chain:
Advanced Features
Composed Messages
ONFT supports composed messages, allowing you to execute additional logic on the destination chain as part of the NFT transfer. When thecomposeMsg parameter is not empty, after the NFT is minted on the destination chain, the composed message will be executed in a separate transaction.
For advanced use cases, you can leverage this feature to:
- Trigger additional actions when an NFT arrives
- Integrate with other protocols on the destination chain
- Implement crosschain NFT marketplace functionality
ONFT721Enumerable
For collections that need enumeration capabilities, LayerZero provides anONFT721Enumerable contract that extends ONFT721 with the ERC721Enumerable functionality:
Example: Complete End-to-End Deployment Flow
Here’s a complete example showing how to deploy and configure an ONFT system with an existing NFT collection on Ethereum and bridging to Polygon:- Create a new OApp with CLI
ONFT721 as the starting point.
- Configure OApp
- Modify
layerzero.config.tsto configure the OApp and add all the chains you want your ONFT to be available on. - Add private key to
.envfile - Modify
hardhat.config.tsto add the networks you want to deploy to
- Deploy Contracts:
- Configure Peers:
- Verify Setup
- Custom OApp config: what you customized in your OApp
- Default OApp config: the defaults that are applied if you don’t customize anything
- Active OApp config: the config that is currently active (essentially, default + your applied customizations)
Security Considerations
When deploying ONFT contracts, consider the following security aspects:- Peer Configuration: Only set trusted contract addresses as peers to prevent unauthorized minting.
- DVN Settings: Use multiple DVNs in production to ensure message verification is robust.
- Gas Limits: Set appropriate gas limits in
enforceOptionsto prevent out-of-gas errors. - Ownership Controls: Implement proper access controls for administrative functions.
- Timeouts and Recovery: Understand how message timeouts work and prepare recovery procedures.
Next Steps
The ONFT standard provides a powerful way to create truly crosschain NFT collections. By understanding the core concepts and following the deployment guidelines outlined in this document, you can build robust omnichain NFT applications that leverage LayerZero’s secure messaging protocol. For more information, explore these related resources:- OApp Contract Standard
- Security and Executor Configuration
- Message Execution Options
- LayerZero Endpoint Addresses
