Write & Deploy an NFT

With NFTs bringing blockchain into the public eye, now is an excellent opportunity to understand the hype yourself by publishing your own NFT contract (ERC-721 Token) on the Asset Chain blockchain!.

In this tutorial, we will walk through creating and deploying an ERC-721 smart contract on the Asset Chain test network using MetaMask, Solidity, and Hardhat,

STEP 1: CREATE AN ASSET CHAIN ACCOUNT (ADDRESS)

We need an Asset Chain account to send and receive transactions. For this tutorial, we’ll use MetaMask, a virtual wallet in the browser used to manage your Asset chain account address.

You can download and create a MetaMask account for free here. When you are creating an account, or if you already have an account, make sure to switch over to the “Asset Chain Testnet

STEP 2: ADD RWA FROM A FAUCET

In order to deploy our smart contract to the test network, we’ll need some fake RWA. To get RWA you can go to the $RWA Faucet, enter your account address, click “start mining”. You should see RWA in your MetaMask account soon after!

STEP 3: FORK AND CLONE THIS STARTER KITS

go to your terminal , navigate to the folder and install neccssary dependencies using yarn install.

STEP 4: WRITE OUR CONTRACT

Now that our environment is set up, on to more exciting stuff: writing our smart contract code!

Open up the my-nft project in your favorite editor (we like VSCode). Smart contracts are written in a language called Solidity which is what we will use to write our NFT.sol smart contract.‌

  1. Navigate to the contracts folder and create a new file called NFT.sol

  2. Below is our NFT smart contract code, which we based on the OpenZeppelin library’s ERC-721 implementation. Copy and paste the contents below into your NFT.sol file.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract NFT is ERC721URIStorage {
	uint256 private _nextTokenId;

    constructor() ERC721("MyNFT", "ATM") {}
     function mintNft(address  recipient, string memory tokenURI)
        public
        returns (uint256)
    {
        uint256 tokenId = _nextTokenId++;
        _mint(recipient, tokenId);
        _setTokenURI(tokenId, tokenURI);

        return tokenId;
    }
}

So, what does this code do exactly? Let’s break it down, line-by-line.

At the top of our smart contract, we import three OpenZeppelin smart contract classes:

  • The ERC721URIStorage contract is an implementation of ERC721 that includes the metadata standard extensions (IERC721Metadata) as well as a mechanism for per-token metadata. That’s where the _setTokenURI method comes from: we use it to store an item’s metadata.

  • @openzeppelin/contracts/access/Ownable.sol sets up access control on our smart contract, so only the owner of the smart contract (you) can mint NFTs. (Note, including access control is entirely a preference. If you'd like anyone to be able to mint an NFT using your smart contract, remove the word Ownable on line 10 and onlyOwner on line 17.)

After our import statements, we have our custom NFT smart contract, which is surprisingly short — it only contains a counter, a constructor, and single function! This is thanks to our inherited OpenZeppelin contracts, which implement most of the methods we need to create an NFT, such as ownerOf which returns the owner of the NFT, and transferFrom, which transfers ownership of the NFT from one account to another.

In our ERC-721 constructor, you’ll notice we pass 2 strings, “MyNFT” and “NFT.” The first variable is the smart contract’s name, and the second is its symbol. You can name each of these variables whatever you wish!

Finally, we have our function mintNFT(address recipient, string memory tokenURI) that allows us to mint an NFT! You'll notice this function takes in two variables:

  • address recipient specifies the address that will receive your freshly minted NFT

  • string memory tokenURI is a string that should resolve to a JSON document that describes the NFT's metadata. An NFT's metadata is really what brings it to life, allowing it to have configurable properties, such as a name, description, image, and other attributes. In part 2 of this tutorial, we will describe how to configure this metadata.

mintNFT calls some methods from the inherited ERC-721 library, and ultimately returns a number that represents the ID of the freshly minted NFT.

STEP 5: CONNECT METAMASK TO YOUR PROJECT

Now that we’ve created a MetaMask wallet and written our smart contract, it’s time to connect the two.

Every transaction sent from your virtual wallet requires a signature using your unique private key. To provide our program with this permission, we can safely store our private key in an environment file.

create a .env file in the root directory of our project, and add your MetaMask private key

Your .env should now look like this:

DEPLOYER_PRIVATE_KEY="your-metamask-private-key"

STEP 6: UPDATE OUR DEPLOYMENT SCRIPTS

Now that our contract is written and our configuration file is good to go, it’s time to write our contract deploy script.

Navigate to the deploy/00_deploy_your_contract.ts folder , adding the following contents to it:


import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";

/**
 * Deploys a contract named "YourContract" using the deployer account and
 * constructor arguments set to the deployer address
 *
 * @param hre HardhatRuntimeEnvironment object.
 */
const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
  /*

    When deploying to live networks (e.g `yarn deploy --network assetchain_testnet`), the deployer account
    should have sufficient balance to pay for the gas fees for contract creation.

    You can generate a random account with `yarn generate` which will fill DEPLOYER_PRIVATE_KEY
    with a random private key in the .env file (then used on hardhat.config.ts)
    You can run the `yarn account` command to check your balance in every network.
  */
  const { deployer } = await hre.getNamedAccounts();
  const { deploy } = hre.deployments;

  const myNft = await deploy("NFT", {
    from: deployer,
    log: true,
    // autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
    // automatically mining the contract deployment transaction. There is no effect on live networks.
    autoMine: true,
  });


  console.log("👋 NFT Contract Address:", myNft.address);
};

export default deployYourContract;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags NFT
deployYourContract.tags = ["NFT"];

STEP 16: DEPLOY OUR CONTRACT

We’re finally ready to deploy our smart contract! Navigate back to the root of your project directory, and in the command line run:

yarn deploy --network assetchain_testnet

You should then see something like:

👋 NFT Contract Address: 0x342E4f63a50D2328fe127fbC5cfdFD5a16e047eA

Congratulations! Your contract is successfully depolyed on Asset Chain Blockchain.

If we go to the Asset Chain explorer and search for our contract address we should be able to see that it has been deployed successfully.

See the Completed Code Below 👇

If you have questions, join our Telegram and say hello 👋. We're Active!

Last updated