NFT(Non-homogeneous Token), as a new technology, helps us digitally protect the ownership of our creative assets. Many people have heard of NFT, but few have actually used it or developed it. Hopefully, this article will show you how to play NFT as a front-end developer in an easy-to-understand way. I’ll cover important background, third party services, detailed development code, and ultimately deployment of our own minted NFT to the Ropsten test network.

Important: This article is not intended to be a stir-fry tutorial. It does not contain any investment ideas or advice, but rather a study of NFT and related technologies themselves

Background knowledge

Before we really get started, let’s take a look at some technical background and features about NFT

Homogeneity and non-homogeneity

It’s called interchangeability, essentially the ability to exchange one item for another of the same value, so that two bills of the same denomination (say, a $50 bill) are equivalent anywhere and you can safely exchange them with someone else. In other words, if the two are not of equal value, they cannot be exchanged. For example, no fake painting of the Mona Lisa is equivalent to the original because it is unique.

Of course, some items can be homogenous or non-homogenous. For example, an economy seat is generally equivalent, and some people may prefer a window seat, thus reducing the value of the seat in their eyes.

Block chain

A blockchain is a public database, or digital ledger, that tracks and keeps records of transactions. It is copied to multiple computer systems as part of a chain. This article will create NFT on the Ethereum blockchain.

Smart contracts and NFT

Smart contracts are simple programs that are deployed to the blockchain and run as-is, meaning they are not controlled by the user. We can use smart contracts to create and track our tokens

NFT is an ERC-721 compliant digital data store that lives on a public blockchain. NFT contains information or data about the assets they represent, which can be a digital item, such as a Tweet, or a physical item, such as a hoodie.

A smart contract can be considered an NFT if it implements the ERC-721 standard, and NFT is an instance of a smart contract. Every time we cast a new NFT, we use smart contract code that has already been deployed on the blockchain.

Public networks: Mainnet and Testnet

Ethereum uses multiple networks. The network used in production is usually referred to as Mainnet, and other networks used for testing are referred to as Testnet. We will deploy the NFT we created to Ropsten Testnet, Ethereum’s PoW Testnet.

Please note that our transaction history and balance on Ropsten Testnet will not be inherited when we eventually deploy our NFT to production or the main network. Think of Testnet as a public test/development environment and Mainnet as a production environment.

Private network

A network is considered private if all of its nodes are not connected to the public blockchain. You can run the Ethereum blockchain on a private network, like your local machine, or on a group of machines, like a syndicate network, that are not accessible on Mainnet or Testnet.

Running the Ethereum blockchain in a cluster of machines like an Intranet requires verifying transactions with nodes, which are the Ethereum software running on the client that validates blocks and transaction data.

HardHat and Ganache are two examples of ethereum blockchain development environments that you can run on your local machine to compile, test, deploy, and debug your smart contract applications.

This time we will run our application on a public network so that it can be accessed by anyone connected to the network.

Water Faucets

To test our app, we need to get Ether (ETH), the Ethereum cryptocurrency, from the tap. Taps, such as Ropsten Taps, are web apps that allow you to specify and send test Ether to an address that you can then use to complete transactions on the test network.

The price of ether on an exchange is determined by any transaction that takes place on the main network at any time. If you choose to run your Ethereum application on a private network, then you don’t need to test the Ethereum and you don’t need a tap.

Nodes and clients

As mentioned earlier, nodes are used to validate blocks and transaction data. You can create your own nodes using clients like Geth and OpenEthereum and contribute to the Ethereum blockchain by validating transactions and blocks on the blockchain.

You can also skip the process of creating nodes yourself and use nodes hosted on the cloud by a node-as-a-service platform like Alchemy. We can move quickly from development to production and ensure that our applications get important metrics.

We will use the Alchemy API to deploy our application on the Ropsten blockchain. Alchemy is also known as AWS for blockchain and provides developer tools that allow us to see how our applications are running.

Casting ERC721 Token

Casting is the process of creating something for the first time, and here we will publish a unique instance of ERC721 Token on the blockchain. Erc-721 is the standard for creating NFT, and the ERC721 Token is the unique representation of digital content published on the Ethereum blockchain. No two tokens are the same, so every time you cast a new Token with the same code block, a new address is generated.

Create smart contracts

precondition

  • NodeJS and NPM
  • JavaScript Basics

If I am a photography enthusiast, what better way to protect the work than to cast an NFT myself? I can transfer it to anyone who likes my work, and they can then prove their rights to the original work by using the NFT data on Mainnet or Testnet.

Next we will cast the NFT of the dome picture I took in Shanghai Xingye Taikoo Hui

Create an Alchemy account

We’ll use Alchemy to write our NFT, which will allow us to quickly skip the setup of a local Ethereum environment.

First, go to the “Create app” page and use my English name as the team name (you can use any name you like), then I use “Hkri Taikoo Hui NFT” as the app name and use ETH Ropsten network. You will then find the application you just created in the control panel.

Create an Ethereum account

We need to create a wallet to hold an Ethereum account. In order to deploy our application to the network, we had to pay an Ethereum-denominated fee, known as the gas fee. While testing our application, we can do this using the test Ethereum network, which we will later retrieve from the tap.

We will create an Ethereum account using MetaMask, which is a virtual wallet that can be obtained by downloading its Chrome extension.

When you have installed MetaMask and created an account, open MetaMask from the Chrome extension app and select Ropsten Network.

MetaMask will automatically generate an Ethereum-denominated wallet address, which you can copy by clicking On Account 1.

Get test Ether from the tap

Let’s use the Ropsten faucet to send test Ether to our wallet.

You can also get Ropsten test ethereum from other channels. For example, I got 4.15 ETH in total.

Write the NFT Token

Now we are ready to write the NFT Token. First, create a development directory locally, and then perform NPM initialization

$ mkdir hkri-taikoo-hui-nft && cd hkri-taikoo-hui-nft
$ npm init -y
Copy the code

We need to install Hardhat to help us compile the application in our local environment and test its functionality before deploying to Ropsten.

Installing Hardhat in your project is as simple as installing the dependency packages via NPM:

$ npm i -D hardhat
Copy the code

The HARDHat can now be initialized by executing NPX HardHat

Select “Create an Empty hardhat.config.js” and we will use this file later to configure our project.

Now we create two folders in the project, one for the smart contract code and one for some scripts for deploying and interacting with the smart contract:

$ mkdir contracts && mkdir scripts
Copy the code

Create smart contracts

Smart contracts are written using the Solidity language and the smart contract code will be based on the implementation of OpenZeppelin ERC721. ERC721 is the standard for representing NFT ownership, and the OpenZeppelin contract provides some easy ways to use ERC72.

Install the OpenZeppelin package:

I @ $NPM openzeppelin/[email protected]Copy the code

Create the hkritaikoohuinft.sol file under the contracts directory and copy the following:

/ / https://wizard.openzeppelin.com/ can create code through this wizard page template / / SPDX - License - Identifier: MIT pragma solidity ^ 0.8.2; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract HkriTaikooHui is ERC721, ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIdCounter; constructor() ERC721("HkriTaikooHui", "Tor") {} function safeMint(address to, string memory uri) public onlyOwner { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); _safeMint(to, tokenId); _setTokenURI(tokenId, uri); } // The following functions are overrides required by Solidity. function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { super._burn(tokenId); } function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); }}Copy the code

Due to the complexity of contract development and standards, it is difficult for beginners to grasp the changes immediately, so we recommend using OpenZeppilin’s contract generation wizard to generate code

Connect to the MetaMask wallet

We will now connect the MetaMask wallet to the project. Every transaction on a virtual wallet requires a private key, so we need to obtain the private key of our MetaMask wallet.

Open the MetaMask extension on Chrome and select “Account Details” by clicking the three-point symbol in the upper right corner. Click Export Private Key to Export the Private Key.

Important ‼ ️ It is important to secure the private key in case it is accidentally exposed while using Github. To do this, we can install the Dotenv package.

$ npm i dotenv
Copy the code

Create a.env file in the project root directory and add the MetaMask private key to it. You will also need to add the API_URL property to Alchemy. You can find Apps in Alchemy’s control panel and select our app. Then click VIEW KEY to get the HTTP property.

# .env
METAMASK_PRIVATE_KEY="yourprivatekey"
API_URL="yourhttpurl"
Copy the code

Set up Mr. Js

Ether.js is a tool to simplify interaction with the Ethereum blockchain, and we will use the Ether plugin for Hardhat.

$ npm i -D @nomiclabs/hardhat-ethers 'ethers @ ^ 5.0.0'
Copy the code

Going back to the hardhat.config.js header we added earlier, we need to add some dependencies:

/ * * *@type import('hardhat/config').HardhatUserConfig
*/
require('dotenv').config(); // allows us to access environment variables (previously set private key, API_URL)
require("@nomiclabs/hardhat-ethers"); // Run some user-friendly methods provided by Ehter on the deployment script
const { API_URL, METAMASK_PRIVATE_KEY } = process.env;

module.exports = {
   solidity: "0.8.2".defaultNetwork: "ropsten".// Specify which network Hardhat should deploy the application on
   networks: {
      hardhat: {},
      ropsten: {
         url: API_URL, // Specify the back-end NodeJS interface address on Alchemy
         accounts: [`0x${METAMASK_PRIVATE_KEY}`] // MetaMask private key used to complete the transaction}}},Copy the code

We will connect to the Ropsten test network through the URL. More detailed configuration items can be found here

Now, let’s run the compile command provided by Hardhat to check that everything is ok:

$ npx hardhat compile
Copy the code

If all goes well, you will see the following success stories.

Creating a deployment script

Now that we are ready to package our smart contract code, we need to write the following script to deploy our smart contract to the Ethereum blockchain (Ropsten test network) :

In the scripts folder, create the file deploy.js

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deploying contracts with the account:", deployer.address);

  console.log("Account balance:", (await deployer.getBalance()).toString());
  const NFT = await ethers.getContractFactory("HkriTaikooHui");

  // Start deployment, returning a promise that resolves to a contract object
  const nft = await NFT.deploy();
  console.log("Contract deployed to address:", nft.address);
}

main()
  .then(() = > process.exit(0))
  .catch((error) = > {
    console.error(error);
    process.exit(1);
  });
Copy the code

Now let’s execute the deployment command:

$ npx hardhat run scripts/deploy.js --network ropsten
Copy the code

In a few seconds, we will see that our smart contract has been successfully deployed to the Ropsten test network. The console also prints out the address of the new smart contract.

After about 1 minute waiting for the block to come out, let’s reconfirm whether our smart contract has been deployed to the blockchain. We can visit Ropsten Etherscan to paste our contract address into the search bar and you can see the details of the contract immediately.

At this point, if you check your MetaMask wallet again, you will see that your balance has been reduced by deducting the cost of gas needed to deploy the contract. Right now, we’ve successfully deployed smart contracts on Ethereum.

Casting NFT

Our smart contract has two inputs: to and URI. Where TO represents the wallet address of the NFT receiver, and URI is the data of this NFT.

Storing data on a blockchain requires processing, validation, and replication across multiple networks, so data storage on a blockchain is expensive. Uploading the entire image to the blockchain is obviously unwise, so you can store the NFT metadata instead of the image.

Although an NFT URL can be stored on the blockchain, the link is unstable and can be taken offline at any time. In addition, those who have access to the URL’s content may tamper with it. So we need a cheaper, more durable, decentralized and immutable way to store data.

Using IPFS

IPFS, a distributed system for storing and accessing files, uses Content Addressing to address these issues.

Any data uploaded to IPFS is assigned a unique content identification code (CID). Once CID is generated, it will always represent the uploaded data itself, and the data cannot be tampered with.

Here is an example of an IPFS URI:

ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
Copy the code

Some browsers (Chrome 90 and above) support parsing the IPFS protocol directly to https://ipfs.io/ipfs/{CID} to display images.

Read this article for IPFS best practices

Install the Web3. Js

Let’s go ahead and add NFT metadata. We will install the Alchemy Web3 suite

$ npm i @alch/alchemy-web3
Copy the code

According to the documentation, web3.js is a library that lets you interact with local or remote Ethereum code using HTTP, IPC, or WebSocket protocols.

Alchemy has encapsulated the Web3.js library, extending its features with automatic retry and more stable Websocket support.

Create a script to cast the NFT

Create mint-nft.js in the scripts folder. Then add the following code:

require("dotenv").config();
const API_URL = process.env.API_URL;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const alchemyWeb3 = createAlchemyWeb3(API_URL);
const contract = require(".. /artifacts/contracts/HkriTaikooHuiNFT.sol/HkriTaikooHui.json");
Copy the code

Upload NFT metadata to Pinata

Pinata is a platform for storing NFT metadata using the IPFS protocol. We can start by creating an account. Then upload the NFT picture to be cast this time.

Once the image has been uploaded, it can be found in the control panel. Note the CID field, which we will use later.

Create a JSON file in the application root directory, NFT -metadata. JSON, and add the following information. Note that the image here needs to use the CID of the image file:

{
  "description": "A photograph of the dome taken at Xingye Taikoo Hui."."image": "https://ipfs.io/ipfs/QmWEsQXpHLJ5V92tR7VhPhbYBtBMZwAiN2DtTAm6D8vGxj"."photographer": "Block horse @ martintsan"
}
Copy the code

Then we also need to upload the JSON file to Pinata, after which you can see both in the control panel

Create an instance of the contract

For casting NFT, first to find we just deploy contracts address: 0 x026fbbb73fef93a2b27258b1f7b8cd13d2dd8007, then went back to mint – NFT. Js file, add the following code:

const contractAddress = "0x026FBBB73feF93a2b27258b1f7b8cd13D2dd8007";
const nftContract = new alchemyWeb3.eth.Contract(contract.abi, contractAddress);
Copy the code

Then update the.env file to add our own MetaMask wallet address:

METAMASK_PUBLIC_KEY="0x572BB0dd7A400D223E2E83ECfE468842277154D3"
Copy the code

Next, we need to create a transaction and add the following code to mint-nft.js

const METAMASK_PUBLIC_KEY = process.env.METAMASK_PUBLIC_KEY;
const METAMASK_PRIVATE_KEY = process.env.METAMASK_PRIVATE_KEY;

async function mintNFT(uri) {
  // Get nonce - Nonce is used for security purposes to record transaction sequence numbers to prevent replay attacks
  const nonce = await alchemyWeb3.eth.getTransactionCount(
    METAMASK_PUBLIC_KEY,
    "latest"
  );
  const tx = {
    from: METAMASK_PUBLIC_KEY, // Our MetaMask public key
    to: contractAddress, // Smart contract address
    nonce: nonce, // nonce
    gas: 1000000.// Estimated gas cost to complete the transaction
    data: nftContract.methods
      .safeMint("0xEB0EC48d8D5aD7745726B627f4297f5023086f60", uri) // Create a new wallet to receive NFT
      .encodeABI(),
  };
}
Copy the code

I created a new MetaMask wallet to receive NFT, or you can use the current wallet address METAMASK_PUBLIC_KEY. In a production environment, the address here is the wallet address that actually needs to receive the NFT.

Now that the transaction has been created, we need to sign for it using the private key METAMASK_PRIVATE_KEY. Go ahead and add the following code to the mintNFT method of the mint-nft.js file:

  const signPromise = alchemyWeb3.eth.accounts.signTransaction(
    tx,
    METAMASK_PRIVATE_KEY
  );
  signPromise
    .then((signedTx) = > {
      alchemyWeb3.eth.sendSignedTransaction(
        signedTx.rawTransaction,
        function (err, hash) {
          if(! err) {console.log(
              "The hash of our transaction is: ",
              hash,
              "\nCheck Alchemy's Mempool to view the status of our transaction!"
            );
          } else {
            console.log(
              "Something went wrong when submitting our transaction:", err ); }}); }) .catch((err) = > {
      console.log(" Promise failed:", err);
    });
Copy the code

Finally, from the nft-metadata.json file we just uploaded to Pinata, we copy its CID and pass in the mintNFT method:

mintNFT("https://ipfs.io/ipfs/Qmb17cSuFzJ1bNZo8puCHpeWAEX5zTaAsqZcNL1C4spjhZ");
Copy the code

Now we can run Node scripts/mint-nft. Js on the terminal to cast our NFT, and after a few seconds or so, we should receive the message shown below

We can then view all transaction information and status by accessing Alchemy Mempool.

We can also look up the transaction information on Etherscan and, most importantly, the nFT-metadata. json file on the blockchain

Scroll down to find Input Data and click the Decode Input Data button. You can see the URL of the NFT metadata JSON file we passed in.

If you search Etherscan for the contract’s address, you’ll find a list of all NFT records minted by the contract and all trades that have been made through the contract.

Add NFT to MetaMask wallet

  1. Copy contract address
  2. Open the MetaMask Wallet extension in Chrome
  3. Select Ropsten Test Network
  4. Click the import token
  5. Paste the contract address into it and MetaMask automatically generates the NFT symbol.
  6. Click Next to add NFT to the wallet

conclusion

So far, we have learned the following:

  • Create and deploy smart contracts on Ropsten Testnet
  • NFT is forged by deploying smart contracts to the blockchain
  • Use ipFs-based content addresses to create metadata for our NFT
  • Browse NFT in MetaMask wallet

In a production environment, all steps are the same as described in this article, with the only difference being that the interacting network is Mainnet. NFT is a fascinating technology through which we can really protect our own creative assets. Hope it can get better and smoother development.

The source code for all of the above is available on GitHub.