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

How to Implement Cross-Chain Token Transfer — LayerZero OFT vs Custom Bridge

Cross-chain token transfer requires either an existing messaging protocol (LayerZero, Axelar) or a custom bridge. For most applications: use LayerZero OFT. For regulated or specialized requirements: custom bridge. Here is the implementation for both.

ClickMasters Team
Step-by-step implementation
Expert Assistance

Ready to Implement Cross-Chain Transfers?

Get expert guidance on building cross-chain token bridges.

Complete Guide

Quick Answer

Cross-chain token transfer offers 2 approaches: LayerZero OFT (burn-and-mint cross-chain transfers — $15,000–$30,000, 10-20 minutes transfer time) and Custom Lock-and-Mint Bridge (specialized requirements, KYC on both sides — requires authorized relayers, centralized trust assumption). For most applications: LayerZero OFT is recommended for its decentralized security.

Option 1: LayerZero OFT (Recommended for Standard Tokens)

LayerZero's Omnichain Fungible Token (OFT) standard enables burn-and-mint cross-chain transfers. The token contract exists on multiple chains; transferring from Chain A to Chain B burns on A and mints on B.

Example
// Token contract using LayerZero OFT standard
import { OFT } from "@layerzerolabs/oft-evm/contracts/OFT.sol";

contract MyOmniToken is OFT {
    constructor(
        string memory _name,
        string memory _symbol,
        address _lzEndpoint,     // LayerZero endpoint on this chain
        address _delegate        // Owner/governance address
    ) OFT(_name, _symbol, _lzEndpoint, _delegate) {}
    
    // No custom code needed for basic cross-chain transfers
    // LayerZero handles the messaging and burn/mint automatically
}
Example
// Frontend: Cross-chain transfer using LayerZero
const { createOFTHelper } = require('@layerzerolabs/ui-bridge-oft');

async function bridgeToken(fromChainId, toChainId, amount, recipient) {
    const oft = new ethers.Contract(
        TOKEN_ADDRESS[fromChainId],
        OFT_ABI,
        signer
    );
    
    // Get fee estimate
    const fee = await oft.quoteSend({
        dstEid: CHAIN_EID[toChainId],
        to: ethers.zeroPadValue(recipient, 32),
        amountLD: ethers.parseEther(amount.toString()),
        minAmountLD: ethers.parseEther((amount * 0.995).toString()), // 0.5% slippage
        extraOptions: '0x',
        composeMsg: '0x',
        oftCmd: '0x'
    }, false);
    
    // Execute bridge
    const tx = await oft.send(
        {
            dstEid: CHAIN_EID[toChainId],
            to: ethers.zeroPadValue(recipient, 32),
            amountLD: ethers.parseEther(amount.toString()),
            minAmountLD: ethers.parseEther((amount * 0.995).toString()),
            extraOptions: '0x',
            composeMsg: '0x',
            oftCmd: '0x'
        },
        { refundAddress: await signer.getAddress(), lzTokenFee: 0 },
        { value: fee.nativeFee }
    );
    
    return tx.hash;
}

Cost to implement: $15,000–$30,000. Deploy the same OFT contract on each target chain; register with LayerZero; done.

Time to first cross-chain transfer: 10–20 minutes (LayerZero messaging time).

Option 2: Custom Lock-and-Mint Bridge

For specialized requirements (regulated tokens with KYC on both sides, custom validation logic):

Example
// Lock contract on Chain A (Ethereum)
contract TokenLock is ReentrancyGuard, Ownable {
    IERC20 public token;
    
    mapping(bytes32 => bool) public processedMessages;
    mapping(address => bool) public authorizedRelayers;
    
    event TokensLocked(address indexed sender, uint256 amount, address recipient, uint256 destChainId);
    
    function lockAndSend(
        uint256 amount,
        address recipient,
        uint256 destChainId
    ) external nonReentrant {
        require(amount > 0, "Amount must be positive");
        
        // Transfer tokens to lock contract
        token.transferFrom(msg.sender, address(this), amount);
        
        emit TokensLocked(msg.sender, amount, recipient, destChainId);
        // Off-chain relayer listens for this event and mints on destination chain
    }
    
    // Called by authorized relayer when tokens need to be unlocked (bridge back)
    function unlockTokens(
        address recipient,
        uint256 amount,
        bytes32 messageId
    ) external onlyRelayer {
        require(!processedMessages[messageId], "Already processed");
        processedMessages[messageId] = true;
        
        token.transfer(recipient, amount);
    }
    
    modifier onlyRelayer() {
        require(authorizedRelayers[msg.sender], "Not authorized relayer");
        _;
    }
}

Frequently Asked Questions

Common questions before following this guide

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

1

Answers

What is the security difference between LayerZero OFT and a custom bridge?

LayerZero uses a decentralized oracle network for message verification. A custom lock-and-mint bridge with authorized relayers creates a centralized trust assumption — if the relayer is compromised, the bridge is compromised. The advantage of a custom bridge: full control over validation logic (can add KYC checks, rate limits, etc.). For most applications: LayerZero's security is superior to a custom bridge.

Expert Assistance

Ready to Implement Cross-Chain Transfers?

Get expert guidance on building cross-chain token bridges.