NFT Contracts

NFT Contract Tutorial


Non-Fungible Tokens (NFTs) are unique digital assets, each possessing distinct identities and attributes. Unlike fungible tokens created by the Token Factory, NFTs cannot be exchanged on a like-for-like basis.

Colony NFT

Colony NFT

Seiyan NFT

Seiyan NFT

This tutorial guides you through the creation and deployment of an NFT contract on Sei. By the end, you'll have deployed your own NFT contract. Select one of the tabs below to get started!

In this section, we'll use Foundry to deploy an ERC-721 contract to the Ethereum network. ERC-721 is a standard for NFT contracts on Ethereum. Learm more about ERC-721 here (opens in a new tab).


Before we start, ensure you have:

You can obtain devnet tokens from one of the faucets listed here.

Setting Up Your Project

  1. Initialize a new Foundry project:

    forge init my-nft-project
    cd my-nft-project
  2. Install OpenZeppelin, a library for secure smart contract development.

    forge install OpenZeppelin/openzeppelin-contracts
  3. Create a new Solidity file under src/ for your NFT contract, e.g., MyNFT.sol.

Writing the ERC-721 Contract

  1. In src/MyNFT.sol, start by importing OpenZeppelin's ERC-721 implementation:

     // contracts/MyNFT.sol
     // SPDX-License-Identifier: MIT
     pragma solidity ^0.8.20;
     import {ERC721} from "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
     contract MyNFT is ERC721 {
         constructor() ERC721("MyNFT", "MNFT") {

You may see an error in your IDE about importing openzeppelin-contracts. To resolve this, run this command to create remapping.txt in the root of your project:

forge remappings > remappings.txt
  1. Add any additional functions or overrides necessary for your NFT.

Testing Your Contract

  1. Write tests for your contract in the test/ directory.

  2. Run your tests with:

    forge test

Deploying Your Contract

  1. Compile your contract:

    forge build
  2. Deploy your contract to a local testnet (e.g., using Anvil, Foundry's local Ethereum node):

    anvil -a 1


    • -a: flag specifies the number of test accounts to create. This command will start a local Ethereum node and create one account. In the command output you will see created account and its private key. Use this private key to deploy your contract.

    In a new terminal, deploy your contract:

    forge create --rpc-url http://localhost:8545 --private-key <test_account_private_key> src/MyNFT.sol:MyNFT --legacy


    • --rpc-url: flag to specify the URL of the Ethereum node. In this case, it's the URL of the local Anvil node.
    • --private-key: flag to specify the private key of the account that will deploy the contract. Anvil generated test account's private key is used in this case.
  3. Deploy contract to the Sei devnet (EVM endpoint):

    forge create --rpc-url https://evm-rpc.arctic-1.seinetwork.io/ --private-key <your_private_key> src/MyNFT.sol:MyNFT --legacy


    • --rpc-url: flag to specify the URL of the Ethereum node. In this case, it's the Sei EVM devnet URL.
    • --private-key: flag to specify the private key of the account that will deploy the contract. The private key of your account on the Sei devnet is used in this case.

Make sure to have SEI in your account to cover the gas fees for contract deployment.

Interacting With Your NFT

  • You can interact with your deployed NFT contract using Foundry's cast tool or through other tools like Ethers.js in a script or web application.

Create Pointer Contract

To enable seamless use of this NFT contract in CosmWasm environments, you can create a pointer contract. This process results in an CW721 token that can be imported and used in Sei wallets and applications.

seid tx evm register-cw-pointer ERC721 $ERC721_TOKEN_ADDRESS --from $ACCOUNT --chain-id=arctic-1 --fees=25000usei --node=https://rpc-arctic-1.sei-apis.com/


  • ERC721_TOKEN_ADDRESS: The contract address of the ERC721 token you want to create an CW721 pointer for.


  • --from: The Sei address from which the deployment transaction is sent. This address must have enough balance to cover transaction fees.
  • --label: A name for the contract instance used to identify the contract.
  • --chain-id: Identifies the specific chain of the Sei network you're interacting with. arctic-1 refers to the Sei devnet.
  • --broadcast-mode: Determines how the transaction is broadcasted. Setting this to block means the transaction will wait to be included in a block before returning a response.
  • --gas: Specifies the maximum amount of gas that can be consumed by the transaction.
  • --fees: Indicates the transaction fee.
  • --node: Points to the specific Sei node RPC URL you're connecting to for transaction submission.
  • --no-admin: Specifies that the contract should not have an admin. This flag is used to indicate that the contract, once deployed, cannot be upgraded or migrated.

Executing this command creates an CW721 NFT contract and outputs the contract address. This NFT contract is linked to the ERC721 NFT contract, meaning any activities involving CW721 NFTs will also reflect on the state of the ERC721 NFTs and vice versa.

Learn more about EVM interoperability and pointer contracts here.


🎉 Congratulations! You've successfully created and deployed an NFT contract on Sei.

If you encounter a bug while using the devnet, please submit it via the form here.