Back to How-To Guides
HOW-TO8 min read2025-06-23

How to Implement Multi-Chain NFT Collections — Deploy Once, Exist Everywhere

Multi-chain NFT collections allow the same NFT to live natively on multiple blockchains — enabling cross-chain gaming items, identity tokens, and collectibles.

ClickMasters Team
Step-by-step implementation
Expert Assistance

Ready to Build Multi-Chain NFTs?

Get expert guidance on implementing cross-chain NFT collections.

Complete Guide

Quick Answer

Multi-chain NFT collections use either lock-and-mint (NFT locked on source chain, bridged version minted on destination) or burn-and-mint/ONFT (NFT burned on source, minted on destination). LayerZero ONFT provides a turnkey solution for cross-chain NFTs. With lock-and-mint, the source chain holds the canonical NFT; with ONFT, the NFT exists on exactly one chain at any time — both approaches maintain 1 NFT = 1 token across all chains.

Approach 1: Lock-and-Mint Bridge

Example
// Source chain: lock NFT
// Destination chain: mint a "bridged" version

contract NFTBridge {
    
    mapping(uint256 => address) public lockedTokenOwner; // tokenId => original owner
    
    // Lock NFT to bridge to another chain
    function lockAndBridge(uint256 tokenId, uint256 destinationChainId) external {
        require(nft.ownerOf(tokenId) == msg.sender, "Not owner");
        
        nft.transferFrom(msg.sender, address(this), tokenId);
        lockedTokenOwner[tokenId] = msg.sender;
        
        // Send message to destination chain via LayerZero
        bytes memory payload = abi.encode(msg.sender, tokenId);
        endpoint.send(
            destinationChainId,
            remoteAddress,
            payload,
            msg.sender,  // Refund address
            address(0),  // ZRO payment
            bytes("")    // Adapter params
        );
        
        emit NFTBridged(tokenId, msg.sender, destinationChainId);
    }
    
    // Release when bridged back
    function release(uint256 tokenId, address recipient) external onlyEndpoint {
        require(lockedTokenOwner[tokenId] != address(0), "Not locked");
        
        delete lockedTokenOwner[tokenId];
        nft.transferFrom(address(this), recipient, tokenId);
        
        emit NFTReleased(tokenId, recipient);
    }
    
    event NFTBridged(uint256 tokenId, address owner, uint256 destinationChain);
    event NFTReleased(uint256 tokenId, address recipient);
}

Approach 2: Cross-Chain NFT (LayerZero ONFT)

Example
// ONFT: same NFT exists on multiple chains
// When transferred cross-chain: burned on source, minted on destination

import {ONFT721} from "@layerzerolabs/solidity-examples/contracts/token/onft/ONFT721.sol";

contract MyCrossChainNFT is ONFT721 {
    
    uint256 public nextTokenId = 1;
    
    constructor(address _lzEndpoint)
        ONFT721("MyCrossChainNFT", "MCCNFT", 200, _lzEndpoint)
    {}
    
    function mint(address to) external onlyOwner {
        _safeMint(to, nextTokenId++);
    }
    
    // Inherited from ONFT721: sendFrom() handles cross-chain transfer
    // When sendFrom() is called: NFT burned on this chain, minted on destination
}

// Frontend: send NFT from Ethereum to Polygon
async function bridgeNFT(tokenId, destinationChainId) {
    const nft = new ethers.Contract(NFT_ADDRESS, ONFT_ABI, signer);
    
    // Estimate fee for cross-chain transfer
    const [nativeFee] = await nft.estimateSendFee(
        destinationChainId,
        ethers.zeroPadValue(recipientAddress, 32),
        tokenId,
        false,
        "0x"
    );
    
    await nft.sendFrom(
        ownerAddress,
        destinationChainId,
        ethers.zeroPadValue(recipientAddress, 32),
        tokenId,
        ownerAddress,  // Refund address
        ethers.ZeroAddress,
        "0x",
        { value: nativeFee }
    );
    
    // NFT now exists on Polygon, not Ethereum
}

Frequently Asked Questions

Common questions before following this guide

Clear answers to the most common practical, technical, and implementation questions.

1

Answers

If an NFT is bridged cross-chain, which chain shows it as the 'real' one?

With lock-and-mint: the source chain holds the "canonical" NFT (it's locked); the bridged version is a representation. With burn-and-mint (ONFT): the NFT exists on exactly one chain at any time — wherever it currently lives is the "real" one. Both approaches maintain scarcity (1 NFT = 1 token across all chains).

Expert Assistance

Ready to Build Multi-Chain NFTs?

Get expert guidance on implementing cross-chain NFT collections.