Skip to main content
Cross-Chain Messaging
Deploy an Omnichain NFT

Deploy an Omnichain NFT


ZetaChain offers two types of contracts: Cross Chain Messaging Contracts (CCM) and zEVM Contracts (Omnichain Smart Contracts).

This tutorial specifically focuses on deploying a CCM-based Omnichain NFT. This NFT may be transferred between different chains seamlessly by passing messages between blockchains.


This tutorial will use the zetachain public repository as a starting point. This repository contains examples and references for development with ZetaChain. You have two options for configuring your local system

Option 1: Use Docker

  1. Make sure your machine has docker installed: Install Docker Engine
  2. Download the zetachain docker image: docker pull
  3. Open a shell using this image: docker run -it zetachain
  4. Create your wallet and .env files with this command: yarn setup-tutorial
  5. Proceed to the Deploying an Omnichain Smart Contract on zEVM section below

Option 2: Configure Your Local System Manually

  1. Make sure your machine has git installed: Getting-Started-Installing-Git

  2. Install Node.js 16.30 LTS (other versions may, but are not guaranteed to work).

  3. Install yarn (make sure NPM has the right permissions to add global packages): npm i -g yarn

  4. Clone the zetachain repository to your machine

    git clone
    cd zetachain
  5. Install the dependencies:


  6. From the root folder, compile the contracts:

    yarn compile

    This will compile all the contracts in the repository for you so that you can try deploying them. You can compile these later if you need to edit anything.

  7. You should have an EVM-compatible wallet (not necessarily for this tutorial, but in general). We recommend Metamask as an easy default, but also XDEFI if you're planning on developing dApps that incorporate Bitcoin.

Deploying a Cross Chain NFT (Cross-Chain Messaging)

To understand how cross chain messaging works, we will deploy a cross chain NFT on Goerli and BSC (also called BNB Chain). The NFT uses ZetaChain's cross-chain messaging to “burn” and “mint” the NFT in order to transfer it across chains while still remaining unique. While normal NFTs are bound to the chain they're minted on, these NFTs can move and interact with data/assets on any blockchain.

  1. First, we need to set up our local environment by running yarn install in the project's root directory.
  2. Next, we need to set up our environment variables by updating, or creating if doesn't exists, the .env file in zetachain/packages/example-contracts. You can do this manually if you have a development wallet you want to use but the easiest option is to use our built in script yarn setup-tutorial to create a new wallet and configure the .env files. Your .env file should look like this.

Let's go over each variable in this file:

`ZETA_NETWORK=athens` refers to the version of the ZetaChain you will use, which determines the connector address used to communicate with ZetaChain. Athens is our public testnet.

`EXECUTE_PROGRAMMATICALLY=true` is used to call other scripts while only executing the caller and importing the other.

`PRIVATE_KEY` is the private key of the wallet you want to use to deploy the contract.
  1. When deploying a CCM contract, there are two steps involved. First, we need to deploy the contracts on each chain we want to use. Second, we need to set up each contract so they can recognize each other's addresses.

    By the end of this tutorial you will have:

    • Deployed the contract on Goerli
    • Deployed the contract on BSC
    • Set up each contract to communicate with each other
  2. We have a logic in place that writes the deployed address to a JSON file in the addresses package. You will find the file at packages/addresses/src/addresses.athens.json and it is indexed by chain, with each attribute being a contract name. In this example, the contract name is crossChainNft. To deploy to Goerli, go to the packages/example-contracts/ directory and you will find several scripts. Take a look at packages/example-contracts/scripts/cross-chain-warriors/deploy.ts. This script deploys a new instance of CrossChainWarriors (a demo NFT) and mints the first one to the deployer. We will use Hardhat, a powerful tool for working with smart contracts, to run this script. The command to run the script is as follows:

    npx hardhat run scripts/cross-chain-warriors/deploy.ts --network goerli

    The --network goerli flag specifies the blockchain network where the deployment will take place. It is important to note that this command will be executed using the private key previously set up, so make sure there are sufficient funds in the chosen network to perform the deployment.

  3. To deploy the contract, run the following command: npx hardhat run scripts/cross-chain-warriors/deploy.ts. This Hardhat command will execute the script and add the deployer information, etc. Once the command is executed, you can verify that the address file has been updated in your Git changes. Repeat the command using the --network "bsc-testnet" flag.

  4. Next, update the data to allow the contract to communicate with each other by using the following command:

    npx hardhat run scripts/cross-chain-warriors/set-cross-chain-data.ts --network goerli

    The script will perform the following steps:

    1. Retrieve the contract address on the current chain.
    2. Retrieve the contract address on the opposite chain (for testing purposes, we have defined this concept in our repository and Goerli is opposite to BSC, but you can choose any chain you desire).
    3. Call the method crossChainWarriorsContract.setInteractorByChainId with two parameters: the first is the destination chain, and the second is the address of the contract on that chain. Please note that you will need to run this script twice, once on each chain. If you are on a non-unix command line (Windows), please add ZETA_NETWORK=athens and EXECUTE_PROGRAMMATICALLY=true to your environment (e. g. set ZETA_NETWORK=athens), and rerun the commands.

Congratulations, you have successfully deployed your first cross-chain NFT! This NFT can be transferred between chains using ZetaChain's cross-chain messaging functionality. This way, a unique asset like this NFT can span and be used across all blockchains. You can read the actual contract you've deployed in the packages/example-contracts/contracts/cross-chain-warriors/CrossChainWarriors.sol file. If you're building on top of this, you can edit the file and redeploy using the same steps as above.