Klaytn Docs Archive
Getting StartedBuild a dAppNode OperationDeveloper Hub
  • Klaytn Docs
  • -
    • Klaytn Overview
      • Why Klaytn
      • Klaytn Design
        • Consensus Mechanism
        • Accounts
        • Transactions
          • Basic
          • Fee Delegation
          • Partial Fee Delegation
          • Ethereum
        • Computation
          • Klaytn Smart Contract
          • Execution Model
          • Computation Cost
            • Computation Cost (Previous docs)
          • Klaytn Virtual Machine
            • Klaytn Virtual Machine (Previous docs)
        • Storage
          • State Migration
          • StateDB Live Pruning
        • Transaction Fees
          • Transaction Fees (Previous docs)
        • Klaytn native coin - KLAY
        • Token Economy
        • Governance
        • Multi-Channel
        • KNI
      • Scaling Solutions
    • Getting Started
      • Deploying Smart Contract Using Foundry
      • Deploying Smart Contract Using Hardhat
      • Deploying Smart Contract Using Thirdweb
      • Deploying Smart Contract Using KEN
        • Launch an Endpoint Node
        • Top up your Account
        • Install Development Tools
        • Deploy a Smart Contract
        • Check the Deployment
        • Account Management
          • Creating Accounts
          • Managing Accounts
      • Development Environment
      • Getting KLAY
    • Smart Contract
      • Solidity - Smart Contract Language
      • Precompiled Contracts
        • Precompiled Contracts (Previous docs)
      • IDE and Tools
        • Truffle
      • Sample Contracts
        • KlaytnGreeter
        • ERC-20
          • 1. Writing ERC-20 Smart Contract
          • 2. Deploying Smart Contract
          • 3. Interacting with ERC-20 token from Klaytn Wallet
        • ERC-721
          • 1. Writing ERC-721 Smart Contract
          • 2. Deploying Smart Contract
      • Testing Guide
      • Deployment Guide
      • Klaytn Compatible Tokens
      • Porting Ethereum Contract
    • Run a Node
      • Deployment
        • Endpoint Node
          • System Requirements
          • Installation Guide
            • Download
            • Installation Guide
            • Configuration
            • Startup the EN
            • Testing the Installation
          • ken CLI commands
          • JSON-RPC APIs
        • Core Cell
          • System Requirements
          • Network Configuration
          • Installation Guide
            • Download
            • Before You Install
            • Consensus Node Setup
              • Installation Guide
              • Configuration
              • Startup the CN
            • Proxy Node Setup
              • Installation Guide
              • Configuration
              • Startup the PN
            • Testing the Core Cell
          • Monitoring Setup
          • H/A Setup
        • Service Chain
          • Getting Started
            • Setting up a 4-node Service Chain
            • Connecting to Baobab
            • Cross-Chain Value Transfer
            • HA(High Availability) for ServiceChain
            • Nested ServiceChain
            • Value Transfer between Sibling ServiceChains
          • Reference Manuals
            • System Requirements
            • Download
            • SCN User Guide
              • Installation
              • Configuration
              • Starting/Stopping SCN
              • Checking Node Status
              • kscn commands
              • homi commands
            • SPN/SEN User Guide
              • Installation
              • Configuration
              • Starting/Stopping Node
              • Checking Node Status
            • Bridge Configuration
            • Anchoring
            • KAS Anchoring
            • Value Transfer
            • Configuration Files
            • Log Files
            • Genesis JSON
            • Upgrade & Hard Fork
          • How-To Guides
        • Download Node Packages
          • v1.12.0
          • v1.11.1
          • v1.11.0
          • v1.10.2
          • v1.10.1
          • v1.10.0
          • v1.9.1
          • v1.9.0
          • v1.8.4
          • v1.8.3
          • v1.8.2
          • v1.8.1
          • v1.8.0
          • v1.7.3
          • v1.7.2
          • v1.7.1
          • v1.7.0
          • v1.6.4
          • v1.6.3
          • v1.6.2
          • v1.6.1
          • v1.6.0
          • v1.5.3
          • v1.5.2
          • v1.5.1
          • v1.5.0
          • v1.4.2
          • v1.4.1
          • v1.4.0
          • v1.3.0
          • v1.2.0
          • v1.1.1
          • v1.0.0
          • v0.9.6
          • v0.8.2
    • Operation Guide
      • Configuration
      • Node Log
      • Log operation
      • Errors & Troubleshooting
      • Klaytn Command
      • Chaindata Change
      • Chaindata Migration
    • dApp Developers
      • JSON-RPC APIs
        • API references
          • eth
            • Caution
            • Account
            • Block
            • Transaction
            • Config
            • Filter
            • Gas
            • Miscellaneous
          • klay
            • Account
            • Block
            • Transaction
              • Working with Klaytn Transaction Types
            • Configuration
            • Filter
            • Gas
            • Miscellaneous
          • net
          • debug
            • Logging
            • Profiling
            • Runtime Tracing
            • Runtime Debugging
            • VM Tracing
            • VM Standard Tracing
            • Blockchain Inspection
          • admin
          • personal
          • txpool
          • governance
        • Service Chain API references
          • mainbridge
          • subbridge
        • Transaction Error Codes
      • RPC Service Providers
        • Public Endpoints
      • SDK & Libraries for interacting with Klaytn Node
        • caver-js
          • Getting Started
          • Sending a sample transaction
          • API references
            • caver.account
            • caver.wallet
              • caver.wallet.keyring
            • caver.transaction
              • Basic
              • Fee Delegation
              • Partial Fee Delegation
            • caver.rpc
              • caver.rpc.klay
              • caver.rpc.net
              • caver.rpc.governance
            • caver.contract
            • caver.abi
            • caver.kct
              • caver.kct.kip7
              • caver.kct.kip17
              • caver.kct.kip37
            • caver.validator
            • caver.utils
            • caver.ipfs
          • caver-js ~v1.4.1
            • Getting Started (~v1.4.1)
            • API references
              • caver.klay
                • Account
                • Block
                • Transaction
                  • Legacy
                  • Value Transfer
                  • Value Transfer Memo
                  • Account Update
                  • Smart Contract Deploy
                  • Smart Contract Execution
                  • Cancel
                • Configuration
                • Filter
                • Miscellaneous
              • caver.klay.net
              • caver.klay.accounts
              • caver.klay.Contract
              • caver.klay.KIP7
              • caver.klay.KIP17
              • caver.klay.abi
              • caver.utils (~v1.4.1)
            • Porting from web3.js
        • caver-java
          • Getting Started
          • API references
          • caver-java ~v1.4.0
            • Getting Started (~v1.4.0)
            • Porting from web3j
        • ethers.js
        • web3.js
      • Tutorials
        • Klaytn Online Toolkit
        • Fee Delegation Example
        • Count DApp
          • 1. Environment Setup
          • 2. Clone Count DApp
          • 3. Directory Structure
          • 4. Write Smart Contract
          • 5. Frontend Code Overview
            • 5-1. Blocknumber Component
            • 5-2. Auth Component
            • 5-3. Count Component
          • 6. Deploy Contract
          • 7. Run App
        • Klaystagram
          • 1. Environment Setup
          • 2. Clone Klaystagram DApp
          • 3. Directory Structure
          • 4. Write Klaystagram Smart Contract
          • 5. Deploy Contract
          • 6. Frontend Code Overview
          • 7. FeedPage
            • 7-1. Connect Contract to Frontend
            • 7-2. UploadPhoto Component
            • 7-3. Feed Component
            • 7-4. TransferOwnership Component
          • 8. Run App
        • Building a Buy Me a Coffee dApp
          • 1. Project Setup
          • 2. Creating a BMC Smart Contract
          • 3. Testing the contract using scripts
          • 4. Deploying BMC Smart contract
          • 5. Building the BMC Frontend with React and Web3Onboard
          • 6. Deploying Frontend code on IPFS using Fleek
          • 7. Conclusion
        • Migrating Ethereum App to Klaytn
        • Connecting MetaMask
        • Connecting Remix
        • Verifying Smart Contracts Using Block Explorers
      • Developer Tools
        • Wallets
          • Kaikas
          • Klaytn Wallet
          • Klaytn Safe
            • Klaytn Safe Design
            • Create a Safe
            • Add assets
            • Send assets
            • Contract Interaction
            • Transaction Builder
            • Points to Note
            • Frequently Asked Questions
          • SafePal S1
          • Wallet Libraries
            • Web3Auth
            • Web3Modal
            • Web3-Onboard
            • Particle Network
        • Oracles
          • Orakl Network
          • Witnet
          • SupraOracles
        • Indexers
          • SubQuery
        • Cross-chain
          • LayerZero
        • Block Explorers
          • Klaytnscope
          • Klaytnfinder
        • Klaytn Contracts Wizard
    • Glossary
  • ---
    • Klaytn Hard Fork History
    • Klaytn 2.0
      • Metaverse Package
      • Finality and Improvements
      • Ethereum Compatibility
      • Decentralizing Governance
      • Massive Eco Fund
    • FAQ
    • Open Source
    • Terms of Use
    • Languages
  • ℹ️Latest Klaytn Docs
Powered by GitBook
On this page
  • Introduction
  • Prerequisites
  • LayerZero OmniChain Contract
  • Getting Started
  • Configuring Your Development Environment
  • Step 1: Configure Variables
  • Step 2: Setup Hardhat Configs
  • Creating OFTV1 Smart Contract
  • Code Walkthrough
  • Deploying the smart contract
  • Setting Trusted remote
  • Running Misc command
  • Executing the sendFrom functionality
  • Conclusion
  1. -
  2. dApp Developers
  3. Developer Tools
  4. Cross-chain

LayerZero

PreviousCross-chainNextBlock Explorers

Last updated 1 year ago

Introduction

Over the past years in the blockchain space, data and tokens transfer between independent blockchain systems stands as a major challenge. However, with the advent of cross-chain messaging protocols like LayerZero, we have seen a major progress in connecting isolated systems together in a secure and decentralized manner. Now, tokens can be transferred from one ecosystem to another seamlessly in one transaction call without having to go through conversion in different exchanges.

By the end of this guide, you will have transferred tokens from one blockchain to another in a single transaction call using LayerZero Omnichain OFTV1 Contract.

Prerequisites

To install both dependencies, you can run:

npm install @openzeppelin/contracts @layerzerolabs/solidity-examples

LayerZero OmniChain Contract

LayerZero (L0) is an open-source protocol for building omini-chain, and interoperable applications. As it is, L0 provides two standard omnichain contracts for seamlessly transferring tokens across different chains, viz.

  1. Omnichain Fungible Tokens (OFT)

  2. Omnichain Non Fungible Tokens

Getting Started

In this guide, we would be focusing on the Omnichain Fungible Tokens (OFT) v1 which allows us to send tokens seamlessly across EVM chains. For that reason, we will be deploying the OFTv1 contract on both Klaytn Baobab (source chain) and Polygon Mumbai (destination chain) using Hardhat smart contract development environment.

Configuring Your Development Environment

Step 1: Configure Variables

A hardhat project can use configuration variables for user-specific values or for data that shouldn't be included in the code repository.

For example, to configure your PRIVATE_KEY do this in your hardhat.config.js file:

const PRIVATE_KEY = vars.get("PRIVATE_KEY");
/** @type import('hardhat/config').HardhatUserConfig */
  networks: {
    baobab: {
      url: `https://klaytn-baobab-rpc.allthatnode.com:8551`,
      accounts: [PRIVATE_KEY]
    },
    mumbai: {
      url: `https://polygon-mumbai-pokt.nodies.app`,
      accounts: [PRIVATE_KEY]
    }
  }
};

And then run the command below in your terminal to set the PRIVATE_KEY:

npx hardhat vars set PRIVATE_KEY

Next Enter the value of your PRIVATE_KEY

Step 2: Setup Hardhat Configs

Paste these configurations in your hardhat.config.js file:

require("@nomicfoundation/hardhat-toolbox");
const PRIVATE_KEY = vars.get("PRIVATE_KEY");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: {
    compilers: [
      {
        version: "0.8.0",
      },
      {
        version: "0.8.9",
      },
      {
        version: "0.8.20",
      },
    ],
  },
  networks: {
    baobab: {
      url: `https://klaytn-baobab-rpc.allthatnode.com:8551`,
      accounts: [PRIVATE_KEY]
    },
    mumbai: {
      url: `https://polygon-mumbai-pokt.nodies.app`,
      accounts: [PRIVATE_KEY]
    }
  }
};

Now that we have our development environment all set, let's get into writing our cross-chain token smart contract.

Creating OFTV1 Smart Contract

In this section, you will use the LayerZero Solidity Example library to bootstrap your cross-chain token smart contract. let's create our cross-chain token smart contracts in the following steps:

Step 1: Select the contracts folder in the Explorer pane and click the New File button and create a new file named crosschain-tokens.sol

Step 2: Open the file and add the following code to it:

// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.0;
/*
    // https://layerzero.gitbook.io/docs/technical-reference/testnet/testnet-addresses
    Klaytn Baobab   lzEndpointAddress = 0x6aB5Ae6822647046626e83ee6dB8187151E1d5ab
    chainId: 10150  deploymentAddress =
 
    Mumbai lzEndpointAddress = 0xf69186dfBa60DdB133E91E9A4B5673624293d8F8
    chainId: 10109  deploymentAddress =
*/

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@layerzerolabs/solidity-examples/contracts/token/oft/v1/OFTCore.sol";
import "@layerzerolabs/solidity-examples/contracts/token/oft/v1/interfaces/IOFT.sol";
contract CrossChainToken is OFTCore, ERC20, IOFT {
    constructor(address _lzEndpointAddress) ERC20("CrossChainTokens", "CCT") OFTCore(_lzEndpointAddress) Ownable(msg.sender) {
        if (block.chainid == 1001) { // Only mint initial supply on Baobab
            _mint(msg.sender, 1_000_000 * 10 ** decimals());
        }
    }
    function supportsInterface(bytes4 interfaceId) public view virtual override(OFTCore, IERC165) returns (bool) {
        return interfaceId == type(IOFT).interfaceId || interfaceId == type(IERC20).interfaceId || super.supportsInterface(interfaceId);
    }
    function token() public view virtual override returns (address) {
        return address(this);
    }
    function circulatingSupply() public view virtual override returns (uint) {
        return totalSupply();
    }
    function _debitFrom(address _from, uint16, bytes memory, uint _amount) internal virtual override returns(uint) {
        address spender = _msgSender();
        if (_from != spender) _spendAllowance(_from, spender, _amount);
        _burn(_from, _amount);
        return _amount;
    }
    function _creditTo(uint16, address _toAddress, uint _amount) internal virtual override returns(uint) {
        _mint(_toAddress, _amount);
        return _amount;
    }
}

Code Walkthrough

This is your cross chain smart contract. On line 2 you tell Hardhat to use the Solidity version 0.8.0 or greater. Other than that, ERC20.sol, Layerzero’s OFTV1 contract was imported. From lines 18-22, you are creating your own smart contract that inherits ERC20, OFTCore contract. You do this by calling the constructor of ERC20 and pass the token name and symbol. Also you will pass the layerzero endpoint address of each chain into OFTCore contract.

As you can see in the code above, the token name and symbol have been set to CrosschainTokens and CCT respectively. You can change the token name and symbol to anything you desire.

The major function that brings the cross-chain functionality to live is the sendFrom function which resides in the OFTCore.sol contract. However, let's do a code walkthrough of function in the order of execution for this tutorial:

  1. approve(): The owner of the Omnichain Fungible Tokens needs to approve the crosschain-tokens.sol contract on the source chain in order to transfer tokens on its behalf across chains by calling the approve() function. For this tutorial, we will be approving 100 CCT tokens (100000000000000000000).

  2. setMinDstGas(): Next is to set your minimum Gas Limit for each chain. This is done by calling setMinDstGas() function with the chainId of the other chain, the packet type ("0" meaning send), and the gas limit amount (200,000).

  3. setUseCustomAdapterParams(): set this to true.

  4. sendFrom(): This function sends the specified token amount to the destination chain. Note that this is a payable function; you have to send the estimated fee with the transaction. This function requires the following arguments:

    • _from: the owner of token

    • _destChainId: 10109

    • _toAddress: insert the recipient address on the dest chain

    • _amount: amount of tokens you want to send in Wei

    • refundAddress: address to receive gas refunds

    • _zroPaymentAddress: specify address zero (0x0000000000000000000000000000000000000000)

    • _adapterParams: 0x00010000000000000000000000000000000000000000000000000000000000030d40

In the next section, we will be exploring the execution of functions in their appropriate order to achieve a successful cross-chain transfer of tokens.

Deploying the smart contract

To deploy the contracts on the respective chains, run the command below:

  1. deploys on baobab (source chain)

npx hardhat run scripts/deploy/src-contract.js --network baobab
  1. deploys on mumbai (destination chain)

npx hardhat run scripts/deploy/dest-contract.js --network mumbai

Setting Trusted remote

  1. sets on source chain To set the contract as trusted on src chain, you need to pass in the destination chain ID (10109) and destination contract address of crosschain-token.sol in the setTrustedRemoteAddress() function.

To see it in action, run the command below:

npx hardhat run scripts/set-remote-address/src.js --network baobab
  1. sets on destination chain To set the contract as trusted on the destination chain, you need to pass in the source chain ID (10150) and source contract address of crosschain-token.sol in the setTrustedRemoteAddress() function.

To see it in action, run the command below:

npx hardhat run scripts/set-remote-address/dest.js --network mumbai

Running Misc command

To execute this script, run the command below:

npx hardhat run scripts/misc.js --network baobab

Executing the sendFrom functionality

To send tokens from one chain to another using the LayerZero OFTV1, you need to execute this script and pass the appropriate parameters as explained in the code Walkthrough section above.

To see this in action, run the command below:

npx hardhat run scripts/send-from.js --network baobab

To see it in action, run the command below:

npx hardhat run scripts/check-balance.js --network mumbai

Conclusion

Before delving into the entire project, it's important to note that its finished form can be found in this repository: . It uses Hardhat, so a prerequisite knowledge will be helpful for understanding how the repository works. Note that this tutorial will not include information on how to use Hardhat and will instead focus solely on the smart contracts. If you would like to follow along, the prerequisites are as follows:

A fresh Hardhat project and

as a dependency

as a dependency

1.1. : OFT standard exclusively supports EVM chains. Note this standard has a ProxyOFT.sol extension. Kindly use the extension when you want to turn an already deployed ERC20 into an OFT.

1.2. : OFT standard supports both EVM and non-EVM chains. Note this standard has a ProxyOFTV2.sol extension. Kindly use the extension when you want to turn an already deployed ERC20 into an OFTV2.

2.1. : ONFT721 standard for cross-chain NFTs. Note this standard has a ProxyONFT721.sol extension. Kindly use the extension when you want to turn an already deployed ERC721 into an ONFT721.

2.2. : ONFT1155 standard for cross-chain multi tokens. Note this standard has a ProxyONFT1155.sol extension. Kindly use the extension when you want to turn an already deployed ERC1155 into an ONFT1155.

For more information on configuring variables, see .

setTrustedRemoteAddress(): A trusted remote is another contract it will accept messages from. Having said that, In order to send and receive messages from known contracts, you need to securely pair them to one another's chain id and address by executing the setTrustedRemoteAddress() function. For more information about setting up trusted remotes, see .

estimateFees(): This function helps get the quantity of native gas tokens to pay to transfer tokens to another chain. To achieve this, LayerZero makes use of an Oracle and Relayer service given the destination chainId, _toAddress, _amount, _useZro, and adapter parameters. For this tutorial, we will be using 10109 as the destination chainId, input your _toAddress, 10 CCT tokens as amount, false for _useZro, and 0x00010000000000000000000000000000000000000000000000000000000000030d40 for the adapter parameters.You can check out on how to encode adapter parameters. To understand in detail how fees are estimated, see .

In this section, you will make use of the here to deploy the OFTV1 contract on Klaytn Baobab (source chain) and Polygon Mumbai (destination chain) respectively. Ensure you have tokens from a faucet for the respective network. You can acquire faucet tokens for the Klaytn Baobab and Polygon Mumbai testnet .

Now you should have the OFTV1 contract deployed on both Baobab and Mumbai. You can verify your deployment by pasting each chain’s contract address in their respective explorer: and .

In this section, you will securely pair the deployed contracts to one another's chain id and address by executing the setTrustedRemoteAddress() function. For this, use this to set each chain’s contract as trusted.

In this section you will collectively execute the approve(), setMinDstGas(), setUseCustomAdapterParams(), and estimateFee() function explained in the codeWalkthrough section using this .

You can verify the cross-chain transaction by pasting the transaction hash in .

Also you can check the balance of the recipient address on the destination chain by executing this .

Congratulations! 🥳 You were able to successfully send tokens from Klaytn Baobab to Polygon Mumbai in a single transaction call using the LayerZero Omnichain Contract OFTV1. You can take it a step further by setting up a simple user interface to make it easy for users to move tokens between chains. Once token contracts are set up, you can use a web3 library such as or to connect the sendFrom() function to a user interface.

Start building with to bootstrap your own projects such as cross-chain decentralized exchanges, cross-chain lending, etc. For more in-depth guides on LayerZero, please refer to the and .

crosschain-oftv1-example
knowledge of how to use Hardhat
OpenZeppelin smart contracts installed
LayerZero smart contracts installed
Omnichain Fungible Tokens (OFT) v1
ProxyOFT.sol
Omnichain Fungible Tokens (OFT) v2
ProxyOFTV2.sol
Omnichain Non Fungible Tokens (ONFT721)
ProxyONFT721.sol
Omnichain Non Fungible Tokens (ONFT1155)
ProxyONFT1155.sol
hardhat configuration variable
Set Trusted Remotes
Relayer Adapter Parameters
Estimating Message Fees
script
here
here
Klaytnscope
Polygonscan
script
script
LayerZero Scan
script
web3klaytn
ethers.js
crosschain-oftv1-example
LayerZero Docs
LayerZero Github Repository