Viction
  • Getting Started
  • General
    • Overview
    • Viction Blockchain
      • PoSV Consensus
      • Comparison
    • Staking
      • Staking Requirements
      • Staking Rewards
      • How to stake on Viction Wallet
    • Network Information
      • Viction Mainnet
      • Viction Testnet
    • Viction RPC API
  • Smart Contract Development
    • Solidity
      • A Simple Smart Contract
      • Solidity by Example
    • Standards & Specification
      • VRC25 Specification
      • VRC725 Specification
    • IDEs and Tools
      • Remix
      • Ethers.js
      • web3.js
      • thirdweb CLI
    • Deployment & Verification
      • Hardhat
      • Foundry
  • DApp Development
    • Integration
      • Exchange/Wallet integration
      • VRC25 Exchange/Wallet integration
      • Viction Staking Governance
      • VIC ZeroGas
      • VRRF
    • Data and analytics
    • Embedded Wallet (MPC)
    • Walkthrough: Build a Dapp on Viction
      • Setup Environment
      • Write the Smart Contract
      • Interacting with the Dapp in a browser
  • Masternode
    • Requirements
    • Run a Full Node
      • Binary
      • Create a Viction Masternode
      • Tmn
      • Docker
    • Apply Your Node
    • Slashing Mechanism
    • Chain Data Snapshots
    • Troubleshooting
  • Viction Wallet
    • User Guide
      • Authentication
      • How to create a new wallet
      • How to restore a wallet?
      • Wallet settings
      • Send & Receive Tokens
      • Add custom token
      • Manage Tokens
      • Send NFT
      • General settings
    • Developer Guide
    • Privacy Policy
    • Term and Services
  • Viction Bridge
    • Spacegate
    • Arken Bridge
    • Hyperlane
  • Viction Data Availability
    • Viction DA RPC API
    • DA Integration Use cases
      • Simple Guide for Integrating OP Stack Rollup with Viction DA Layer
  • How to
    • How to Connect to Viction Blockchain
      • Coin98 Super Wallet
      • Metamask
      • Ledger
    • How to troubleshoot when the node is up but couldn't begin to sync block
    • How to Vote for Viction Saigon Network Upgrade Proposal
    • How to issue a token via VICIssuer
    • How to verify if a contract has been issued via VICIssuer
    • How to deploy the VRC725 contract
    • How to apply ZeroGas for VRC725 contract
    • How to Migrate Dapps from Ethereum
    • How to register Token or NFT logo on Vicscan
    • How to verify a contract on Vicscan
    • How to confirm a project on Vicscan
    • How to check if a token is gas sponsored on Viction
    • How to verify gas sponsored transactions
    • How to create Telegram Mini Apps
    • How to use VictionSafe (Multisig)
  • FAQ
    • APIs
    • General
      • Viction
      • Ecosystem
      • VIC - Economics
      • Contact & Support
    • Masternodes and Voting
      • Masternodes
      • Voter
    • Products
      • VicScan (Explorer)
      • VicMaster
      • VicStats
      • VicIssuer
        • How to Verify & Publish Contract Source Code on VicScan
      • Viction Wallet
      • Viction Data Availability Network
  • Legal
    • Terms of Use
    • Privacy Policy
  • Whitepaper and Research
  • Archive
    • TOMOE
    • How to Deploy a VRC25 Token on Viction
    • How to deploy an ICO smart contract on Viction
    • How to deploy an NFT token
    • An Example of Building a Dapp on Viction
    • Migrate Ethereum Dapp to Viction
    • TomoMasterDAO
      • Introduction
      • Governance model
        • On-Chain vs Off-Chain Voting
        • Board
        • Proposals
        • Voting and Outcome
      • Tokenomics
      • How to utilize and trade tDAO
      • Proposal guidelines for TomoMasterDAO
    • Old Viction Testnet
    • Deploy on Viction
      • CLI Commands
      • Viction Private Testnet Setup
Powered by GitBook
On this page
  • CryptoKitties
  • Crypto Item Standard (ERC-1155)
  • Use-cases of Non-Fungible Tokens (NFT)
  • How to deploy a NFT token on Viction
  • Let’s Start the NFT Tutorial
  • 0. Prerequisites
  • 1. Creating a new project
  • 2. Preparing your VIC wallet
  • 3. Writing the Smart Contract
  • 3.1 GradientToken.sol
  • 4. Config Migrations
  • 4.1 Create the migration scripts
  • 4.2 Configure truffle.js
  • 4.3 Ganache
  • 5. Adding Tests
  • Adding more tests
  • 6. Deploying
  • 6.1 Start the migration
  • *** Troubleshooting ***
  • 7. Interacting with the smart contract
  • 7.1 Minting new Tokens
  • What’s next?
  • Source Code
  1. Archive

How to deploy an NFT token

Create a unique ERC721-equivalent token (ie: CryptoKitties) on Viction!

PreviousHow to deploy an ICO smart contract on VictionNextAn Example of Building a Dapp on Viction

Last updated 1 year ago

This article will explain:

  • What is a Non-Fungible Token (NFT)

  • Use-cases of NFT

  • How-to step-by-step deploy a NFT token on Viction

What is a Non-Fungible Token (NFT)?

Fungible tokens are all equal and interchangeable. For instance, dollars or Bitcoins or 1 kilogram of pure gold or ERC20 tokens. All VIC are equivalent too, they are the same and have the same value. They are interchangeable 1:1. This is a fungible token.

Non-fungible tokens (NFTs) are all distinct and special. Every token is rare, with unique atributes and different value. For instance: CryptoKitty tokens, collectible cards, airplane tickets or real art paintings. Every item has its own characteristics and specifics and is clearly differentiable to another one. They are not interchangeable 1:1. They are distinguishable.

Think of Non-Fungible Tokens (NFT) as a rare collectible on the Viction network. Every token has unique characteristics, its own metadata and special attributes

Non-Fungible Tokens (NFT) are used to create verifiable digital scarcity. NFTs are unique and distinctive tokens that you can mainly find on EVM blockchains.

ERC721 is a free, open standard that describes how to build non-fungible or unique tokens on EVM compatible blockchains. While most tokens are fungible (not distinguishable), ERC721 tokens are all unique, with individual identities and properties. Think of them like rare, one-of-a-kind collectables — each unit is a unique item with its own serial number.

ERC20: identical tokens. ERC721: unique tokens

CryptoKitties

The strength of NFTs resides in the fact that each token is unique and cannot be mistaken for another one– unlike bitcoins, for example, which are interchangeable with one another.

Crypto Item Standard (ERC-1155)

Online games can have up to 100,000 different digital items. The current problem with ERC-721 is that if we would like to tokenize all those 100,000 items, then we would need to deploy 100,000 separate smart contracts.

Use-cases of Non-Fungible Tokens (NFT)

  • Betting in real time on the outcome of a video game being live-streamed

  • Gaming in general is an important field of experimentation and development for the uses of NFT in the future.

  • Concert tickets and sports match tickets can be tokenized and name-bound, preventing fraud and at the same time offering fans an option to have a single place where to collect all their past event experiences

  • Real Estate assets, to carry out transfers of houses, land and other ‘tokenized’ properties through smart contracts

  • Financial instruments like loans, burdens and other responsibilities, or a futures contract to buy 1,000 barrels of oil for $60k on May 1

  • and more…

How to deploy a NFT token on Viction

The assets that your ERC721 tokens (NFT) represent will influence some of the design choices for how your contract works, most notably how new tokens are created.

  • You can have an initial supply of tokens defined during token creation

  • You can have a function, which is only callable by the contract creator (or others — if you allow this) that will issue new tokens when called

Let’s Start the NFT Tutorial

We will now implement an NFT collectible token, like CryptoKitties but with simpler logic.

You’ll learn how to create non fungible tokens, how to write tests for your smart contracts and how to interact with them once deployed.

0. Prerequisites

The first prerequisites you should have:

  • Install Truffle

npm install -g truffle

1. Creating a new project

Create a new directory and move inside it. Then start a new Truffleproject:

mkdir nft-tutorial 
cd nft-tutorial
truffle init
npm install openzeppelin-solidity

2. Preparing your VIC wallet

  • Viction (mainnet): You will need real VIC from exchanges

Go to Settings menu, select Backup wallet and then Continue. Here you can see your wallet’s private key and the 12-word recovery phrase.

Write down your 12-word recovery phrase.

3. Writing the Smart Contract

3.1 GradientToken.sol

We’ll be extending the OpenZeppelin ERC721 token contracts to create our Gradient Token.

  1. Go to contracts/ folder and create a new file called GradientToken.sol

  2. Copy the following code

pragma solidity ^0.5.4;import 'openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol';
import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';// NFT Gradient token
// Stores two values for every token: outer color and inner colorcontract GradientToken is ERC721Full, Ownable {
  
  using Counters for Counters.Counter;
  Counters.Counter private tokenId;
 
  struct Gradient {
    string outer;
    string inner;
  }
  
  Gradient[] public gradients;  constructor(
    string memory name,
    string memory symbol
  )
    ERC721Full(name, symbol)
    public
  {}
 
 
  // Returns the outer and inner colors of a token 
  function getGradient( uint256 gradientTokenId ) public view returns(string memory outer, string memory inner){
    Gradient memory _gradient = gradients[gradientTokenId];    outer = _gradient.outer;
    inner = _gradient.inner;
  }  // Create a new Gradient token with params: outer and inner
  function mint(string memory _outer, string memory _inner) public payable onlyOwner {
    uint256 gradientTokenId = tokenId.current();
    
    Gradient memory _gradient = Gradient({ outer: _outer, inner: _inner });
    gradients.push(_gradient);
   _mint(msg.sender, gradientTokenId);
    tokenId.increment();
  }
 
}

We inherited from two contracts: ERC721Full to make it represent a non-fungible token, and from the Ownable contract.

Every token will have a unique tokenId, like a serial number. We also added two attributes: inner and outer to save CSS colors.

Ownable allows managing authorization. It assigns ownership to the deployer (when the contract is deployed) and adds modifier onlyOwner that allows restrictions to certain methods only to the contract owner. Also, ownership can be transferred. Additionally, third parties can be approved to spend tokens, burn tokens, etc.

Our solidity code is simple and I would recommend a deeper dive into the ERC-721 standard and the OpenZeppelin implementation.

4. Config Migrations

4.1 Create the migration scripts

In the migrations/ directory, create a new file called 2_deploy_contracts.js and copy the following:

const GradientToken = artifacts.require("GradientToken");module.exports = function(deployer) {
 
  const _name = "Gradient Token";
  const _symbol = "GRAD";
  
  return deployer
    .then(() => deployer.deploy(GradientToken, _name, _symbol));
};

This code will deploy or migrate our contract to Viction, with the name Gradient Token and the symbol GRAD.

4.2 Configure truffle.js

Now we set up the migrations: the blockchain where we want to deploy our smart contract, specify the wallet address to deploy, gas, price, etc.

1. Install Truffle’s HDWalletProvider, a separate npm package to find and sign transactions for addresses derived from a 12-word mnemonic.

npm install truffle-hdwallet-provider

2. Open truffle.js file (truffle-config.js on Windows). Here the migration settings can be edited: networks, chain IDs, gas... You have multiple networks to migrate your ICO, you can deploy: locally, ganache, public Ropsten (ETH) testnet, Viction (testnet), Viction (Mainnet), etc…

Replace the truffle.js file with this new content:

const HDWalletProvider = require('truffle-hdwallet-provider');
const infuraKey = "a93ffc...<PUT YOUR INFURA-KEY HERE>";// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
const mnemonic = '<PUT YOUR WALLET 12-WORD RECOVERY PHRASE HERE>';module.exports = {  networks: {
    // Useful for testing. The `development` name is special - truffle uses it by default
    development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8545,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
    },    // Useful for deploying to a public network.
    // NB: It's important to wrap the provider as a function.
    ropsten: {
      //provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/${infuraKey}`),
      provider: () => new HDWalletProvider(
        mnemonic,
        `https://ropsten.infura.io/${infuraKey}`,
        0,
        1,
        true,
        "m/44'/889'/0'/0/", // Connect with HDPath same as VIC
      ),
      network_id: 3,       // Ropsten's id
      gas: 5500000,        // Ropsten has a lower block limit than mainnet
      // confirmations: 2,    // # of confs to wait between deployments. (default: 0)
      // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
      // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
    },    // Useful for deploying to Viction testnet
    tomotestnet: {
      provider: () => new HDWalletProvider(
        mnemonic,
        "https://testnet.tomochain.com",
        0,
        1,
        true,
        "m/44'/889'/0'/0/",
      ),
      network_id: "89",
      gas: 3000000,
      gasPrice: 10000000000000,  // Viction requires min 10 VIC to deploy, to fight spamming attacks
    },    // Useful for deploying to Viction mainnet
    tomomainnet: {
      provider: () => new HDWalletProvider(
        mnemonic,
        "https://rpc.viction.xyz",
        0,
        1,
        true,
        "m/44'/889'/0'/0/",
      ),
      network_id: "88",
      gas: 3000000,
      gasPrice: 10000000000000,  // Viction requires min 10 VIC to deploy, to fight spamming attacks
    },    // Useful for private networks
    // private: {
      // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
      // network_id: 2111,   // This network is yours, in the cloud.
      // production: true    // Treats this network as if it was a public net. (default: false)
    // }
  },  // Set default mocha options here, use special reporters etc.
  mocha: {
    // timeout: 100000
  },  // Configure your compilers
  compilers: {
    solc: {
      version: "0.5.4",    // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      // settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
      //  evmVersion: "byzantium"
      // }
    }
  }
}

3. Remember to update the truffle.js file using your own wallet recovery phrase. Copy the 12 words previously obtained from your wallet and paste it as the value of the mnemonic variable.

const mnemonic = '<PUT YOUR WALLET 12-WORD RECOVERY PHRASE HERE>';

⚠️ Warning: In production, it is highly recommend storing the mnemonic in another secret file (loaded from environment variables or a secure secret management system)...

4.3 Ganache

You can use Ganache blockchain to test your smart contracts locally, before migrating to a public blockchain like Ethereum (Ropsten) or Viction.

On a separate console window, install Ganache and run it:

npm install -g ganache-cli
ganache-cli -p 8545

Ganache will start running, listening on port 8545. Automatically you will have 10 available wallets with their private keys and 100 ETH each. You can use them to test your smart contracts.

5. Adding Tests

We will add now tests to check our smart contracts.

When deploying contracts the first contract will usually be the deployer. This test will check that.

Create GradientTokenTest.js in /test directory and write the following test:

const GradientToken = artifacts.require("GradientToken");contract("Gradient token", accounts => {
  it("Should make first account an owner", async () => {
    let instance = await GradientToken.deployed();
    let owner = await instance.owner();
    assert.equal(owner, accounts[0]);
  });
});

Here we run the contract block, that deploys our contract. We wait for the contract to be deployed and request owner() which returns owner’s address. Then we assert that the owner address is the same as account[0].

Note: Make sure that Ganache is running (on a different console).

Run the test:

truffle test

The test should pass. This means that the smart contract works correctly and it did successfully what it was expected to do.

Adding more tests

Every NFT token will have a unique ID. The first minted token has ID: 0, the second one has ID: 1, and on and on…

Now we’ll test the mint function. Add the following test:

describe("mint", () => {
  it("creates token with specified outer and inner colors", async () => {
    let instance = await GradientToken.deployed();
    let owner = await instance.owner();    let token0 = await instance.mint("#ff00dd", "#ddddff");
    let token1 = await instance.mint("#111111", "#ffff22");
    let token2 = await instance.mint("#00ff00", "#ffff00");    let gradients1 = await instance.getGradient( 1 );
    assert.equal(gradients1.outer, "#111111");
    assert.equal(gradients1.inner, "#ffff22");
  });
});

This test is simple. First we check that we can mint new tokens. We mint 3 tokens. Then we expect that the unique attributes outer and inner of token with tokenId = 1 are saved correctly and we assert it by using the getGradient function that we created before.

The test passed.

6. Deploying

6.1 Start the migration

You should have your smart contract already compiled. Otherwise, now it’s a good time to do it with truffle compile.

Note: Check that you have enough VIC tokens in your wallet!! I recommend at least 60 VIC to deploy this smart contract

Back in our terminal, migrate the contract to Viction testnet network:

truffle migrate --network tomotestnet

To deploy to the Viction mainnet is very similar:

truffle migrate --network tomomainnet

The migrations start…

Starting migrations...
======================
> Network name:    'tomotestnet'
> Network id:      89
> Block gas limit: 840000001_initial_migration.js
======================Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x67c0f12247d0bb0add43e81e8ad534df9cd7d3473ef76f5b60cee3e3d34bae1a
   > Blocks: 2            Seconds: 5
   > contract address:    0x6056dC38715C7d2703a8aA94ee68A964eaE86fdc
   > account:             0x169397F515Af9E93539e0F483f8A6FC115de660C
   > balance:             90.05683
   > gas used:            273162
   > gas price:           10000 gwei
   > value sent:          0 ETH
   > total cost:          2.73162 ETH> Saving artifacts
   -------------------------------------
   > Total cost:             2.73162 ETH2_deploy_contracts.js
=====================Deploying 'GradientToken'
   -------------------------
   > transaction hash:    0xca09a87ad8f834644dcb85f8ea89beff74b818eff11d355e0774e6b60c51718c
   > Blocks: 2            Seconds: 5
   > contract address:    0x8B830F38b798B7b39808A059179f2c228209514C
   > account:             0x169397F515Af9E93539e0F483f8A6FC115de660C
   > balance:             60.64511
   > gas used:            2941172
   > gas price:           10000 gwei
   > value sent:          0 ETH
   > total cost:          29.41172 ETH> Saving artifacts
   -------------------------------------
   > Total cost:            29.41172 ETHSummary
=======
> Total deployments:   2
> Final cost:          32.14334 ETH

Congratulations! You have already deployed your non-fungible token (NFT) to Viction! The deployment fees were 32.14 VIC.

Read the output text on the screen. The NFT token [contract address](https://scan-ui-testnet.viction.xyz /address/0x8B830F38b798B7b39808A059179f2c228209514C) is (yours will be different):

0x8B830F38b798B7b39808A059179f2c228209514C

*** Troubleshooting ***

  • Error: smart contract creation cost is under allowance. **Why?**Increasing transaction fees for smart contract creation is one of the ways Viction offers to defend against spamming attacks. Solution: edit truffle.js and add more gas/gasPrice to deploy.

7. Interacting with the smart contract

7.1 Minting new Tokens

Now to create a new Gradient Token you can call:

GradientToken(gradientTokenAddress).mint("#001111", "#002222")

In MyEtherWallet, under menu Contract > Interact with Contract two things are required:

  • Contract Address: you got this address when you deployed

  • ABI: file build/contracts/GradientToken.json, search "abi": [ … ]and copy everything inside brackets, including brackets. Then paste on MEW

On the right you will see a dropdown list with the functions. Select mint. MEW will show two fields: outer and inner. Input two colors, like #ff0000or #0000ff and click the button Write. Confirm with MetaMask.

Here is [our contract address](https://scan-ui-testnet.viction.xyz /address/0x8B830F38b798B7b39808A059179f2c228209514C), and the new mint transaction:

You can use MEW to Write and to Read functions, like getGradient! This way you can check if values are correct, totalSupply, transfer tokens...

What’s next?

A few suggestions to continue from here:

  • You could add a lot of different attributes to your unique NFT tokens

  • You can have some buttons to interact with the tokens (buy, sell, change, transfer, change attributes/colors, etc…)

  • You can iterate on this basic code and create a new CryptoKitties game :)

Congratulations! You have learned about non-fungible tokens, use-cases of NFTs and how to deploy NFT tokens on Viction.

Source Code

The is the standard interface for Non-Fungible Tokens (but there are also other NFTs, like ERC1155). ERC721 is a set of rules to make your NFT easy for other people / apps / contracts to interface with.

Some high demand non-fungible tokens are applications like , , , and many .

At the end of 2017, NFTs made a remarkable entrance in the blockchain world with the success of CryptoKitties. Each one is a unique collectible item, with its own serial number, which can be compared to its DNA card. This unleashed an unprecedented interest for NFTs, that went so far as to clog the Ethereum network. The CryptoKitties market alone generated $12 million dollars in two weeks after its launch, and over $25 million in total. Some rare cryptokitties were even .

One step further in the non-fungible token space is the ERC-1155 Standard proposed by the , also known as the “Crypto Item Standard”. This is an improved version of ERC-721 which will actually be suitable for platforms where there are tens of thousands of digital items and goods.

combines ERC-20 and ERC-721 tokens in its smart contract. Each token is saved in the contract with a minimal set of data that distinguishes it from others. This allows for the creation of bigger collections which contain multiple different items.

Most of the time when people think about ERC-721 or NFT, they refer to the most notably successful . But there are many other usability applications for NFT contracts:

Software titles or to guarantee anti-piracy, privacy and transferability — like

Digital Art (or physical art!) has already entered the game and showed an important usage of ERC721. Digital art auctions were the first application and still are the first thought of non-fungible token standards. The revealed the appeal of the public for crypto-collectibles. Several digital art assets were sold during this event, the high point being the sale of the ‘Celestial Cyber Dimension’, an ERC721 CryptoKitty piece of art, for

KYC compliance check to verify users. Receiving a specific NFT token in your wallet similar to the blue checkmark ☑️ on Twitter — like

. It is easy to see the reason why, especially when you look at the potential of the crypto-collectible technology, including: securing digital ownership, protecting intellectual property, tracking digital assets and overall creating real world value.

This article will create a basic ERC721 token using the implementation of the . Look at the links in order to familiarize yourself with the requirements as they can sometimes be hidden in the excellent .

For example, in , players are able to “breed” their Kitties, which creates new Kitties (tokens). However, if your ERC721 token represents something more tangible, like concert tickets, you may not want token holders to be able to create more tokens. In some cases, you may even want token holders to be able to “burn” their tokens, effectively destroying them.

We’ll build non-fungible collectibles: . Every token will be represented as a unique gradient and will look somewhat like this:

Install & npm (“Node.js Package Manager”)

We will use , which is quick and easy and broadly used. Install OpenZeppelin in the current folder.

. Then grab a few tokens:

Viction (testnet): Get (grab ~60 VIC)

You can see the functions to use in OpenZeppelin ERC721 and .

You can find another .

Both Testnet and Mainnet network configurations are described in We need the RPC endpoint, the Chain id and the HD derivation path.

⚠️ Note: Viction’s smart contract: gas price 10000 Gwei, gas limit >= 1000000

Error: insufficient funds for gas * price + value. Why? You don’t have enough tokens in your wallet for gas fees. Solution: you need more funds in your wallet to deploy, go to and get more tokens.

You can call this function ... In a Dapp or game this would probably be called from a button click in a UI.

Let’s use (MEW) to interact with the contract. We use to connect to the GradientToken owner wallet in Viction (testnet), then we will call function mint() to mint the first token.

In Ethereum (Ropsten), the Etherscan page with will change after the first token is minted. A new link will be displayed now to track the ERC721 token GRAD.

You can and show your tokens

The source code for this tutorial is available on .

ERC-721
CryptoKitties
Decentraland
CryptoPunks
others
sold for 600 ETH ($170,000)
Enjin team
ERC-1155 standard
CryptoKitties
software licences
Collabs.io
auctions organized by Christie’s
$140,000
Wyre
Crypto-Collectibles are more than a passing craze
OpenZeppelin
ERC721 standard
OpenZeppelin ERC721 implementations
CryptoKitties
gradient tokens
CSS
Node.js
OpenZeppelin ERC721 implementation
Create a VIC wallet
free tokens from faucet
here
here
ERC721 smart contract example by OpenZeppelin here
the official Viction documentation — Networks.
creation fee
faucet
via MyEtherWallet/Metamask or Web3
MyEtherWallet
MetaMask
our migrated contract
connect to a JS front end
Github