Building collectible tokens using QuikNode

In a recent article, we have built ‘_Botics (BTS)_’ token using OpenZeppelin library. We looked at the different methods of ERC-721 standards and how they work. If need an introduction to ERC-721 tokens, I recommend you check out the previous article first.

In this article, I will discuss ERC-721 tokenomics, including features such as ‘burning’ and ‘pausing’, and show you how to deploy your collectible token using QuikNode.io (Ethereum node as service).

Scaffold your own ERC-20 token in 30 seconds, without writing a line of code, using the Crowdbotics App Builder

Burnable Token Contracts

Token burning is an instrument in tokenomics to decrease the supply of the asset. In our case — as every token is different — we will destroy a token (collectible asset) to decrease total supply.

Who Can Burn an ERC-721 Token?

There are three actors who can burn tokens in our contract:

**Owner **— Of course the owner of the token can burn his/her tokens.

Approved account — An approved account by owner can burn the token.

Operator — An operator is similar to the approved account but, in this case, the owner approves access to his/her all tokens from another account. This is a typical arrangement of wallets or exchange.

While designing your contract, you should be careful who is able to burn tokens. As blockchains are immutable, destroyed tokens can’t be recovered.

How to build a Burnable ERC-721 token?

Now, let’s add burnable functionality on the Botics token which we built in the last tutorial. We will inherit ERC721Burnable.sol contract from open-zeppelin library. Let’s look at this contract first.

This file inherits ERC721.sol and checks the ownership of the token and call the _burn method of ERC721.sol.

pragma solidity ^0.4.24;
import "./ERC721.sol";
contract ERC721Burnable is ERC721 {
  function burn(uint256 tokenId)
    public
  {
    require(_isApprovedOrOwner(msg.sender, tokenId));
    _burn(ownerOf(tokenId), tokenId);
  }
}

Below is the _burn function from ERC721.sol file. It removes the ownership and gives ownership to address(0) (No one has access to this address) and then emits the transfer event.

function _burn(address owner, uint256 tokenId) internal {
    _clearApproval(owner, tokenId);
    _removeTokenFrom(owner, tokenId);
    emit Transfer(owner, address(0), tokenId);
  }

Now, let’s see changes to our contract. We will add a small burn method which will internally call ERC721Burnable.sol.

function _burn(uint256 tokenId) public{
   burn(tokenId);
}

**Full code of BoticsToken.sol**

pragma solidity ^0.4.24;
import "/openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol";
import "/openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "/openzeppelin-solidity/contracts/token/ERC721/ERC721Burnable.sol";
contract BoticsToken is ERC721Full, Ownable, ERC721Burnable{
  
  constructor() 
  ERC721Full("Botics", "BTS")
  public {}
function mint(address to, uint256 tokenId) public onlyOwner {
   _mint(to, tokenId);
  }
function _mint(address to) public onlyOwner{
   mint(to, totalSupply().add(1));
  }
function _burn(uint256 tokenId) public{
   burn(tokenId);
  }
}

Testing the Burnable Token

Now, let’s test our burnable token for each of the three actors we discussed above.

Token Burning by Token Owner

A token owner can burn it’s token. Let’s see how this will work.

We will be using truffle console to test our contract. You can invoke truffle console using.

truffle develop

Now, let's mint some tokens and burn them.

// deploy contract
truffle migrate --reset
//Get token instance
BoticsToken.deployed().then((botics) => {token = botics;})
//mint a token (id : 1) to account 1
token.mint(web.eth.account[1] , 1 );
// Now burn the token (id : 1)
token._burn(1 , {from: web3.eth.accounts[1]})

Token Burning by an Approved Account

Let’s see how a token can be burn from an approved account.

//mint another token (id : 2) to account 1
token.mint(web.eth.account[1] , 1 );
//approve account-2 of token(id:2)
token.approve(web3.eth.accounts[2], 2,{from:web3.eth.accounts[1]})
// Now burn the token (id : 2) from account-2
token._burn(2 , {from: web3.eth.accounts[2]})

Similarly, an owner can approve all tokens to another account and that account will be able to burn all the tokens.

Pausable Token

Let’s give our contract a pause feature.

A pausable contract has mechanisms to stop smart contract functionalities such as transfer or approval.

Every asset contract should have this functionality. There are several benefits of a pausable contract. The primary benefit of the pausable token contract is safety. In case of any contract vulnerability which may be needed to update the contract, pausing can stop transfers and other core functionalities which reduces overall risk.

How to Build A Pausable ERC-721 token?

Building a pausable contract is very easy with the OpenZeppelin library. Open-zeppelin provides ERC721Pausable.sol contract using which you can provide pausable functionality to our ERC-721 contract.

We just need to inherit ERC721Pausable.sol to provide the pausable feature to our contract.

Let's look at ERC721Pausable.sol, It covers three functions approve, setApprovalForAll and transferFrom. It also inherits Pausable.sol which internally controls the Pausing functionality.

pragma solidity ^0.4.24;
import "./ERC721.sol";
import "../../lifecycle/Pausable.sol";
contract ERC721Pausable is ERC721, Pausable {
  function approve(
    address to,
    uint256 tokenId
  )
    public
    whenNotPaused
  {
    super.approve(to, tokenId);
  }
function setApprovalForAll(
    address to,
    bool approved
  )
    public
    whenNotPaused
  {
    super.setApprovalForAll(to, approved);
  }
function transferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
    whenNotPaused
  {
    super.transferFrom(from, to, tokenId);
  }
}

Let’s look at the Pausable.sol contract inherited by the ERC721Pausable.sol. This pausable contract also inherits PauserRole.sol by using which you can control who can pause the contract.

pragma solidity ^0.4.24;
import "../access/roles/PauserRole.sol";

contract Pausable is PauserRole {
  event Paused(address account);
  event Unpaused(address account);
bool private _paused;
constructor() internal {
    _paused = false;
  }

  function paused() public view returns(bool) {
    return _paused;
  }
  modifier whenNotPaused() {
    require(!_paused);
    _;
  }

  modifier whenPaused() {
    require(_paused);
    _;
  }

  function pause() public onlyPauser whenNotPaused {
    _paused = true;
    emit Paused(msg.sender);
  }

  function unpause() public onlyPauser whenPaused {
    _paused = false;
    emit Unpaused(msg.sender);
  }
}

Testing A Pausable Token

Let’s test our pausable token. Before that, compile and redeploy the Botics Token.

//Get token instance and mint a new token and assign it to account-1
token.mint(web3.eth.accounts[1], 1);
//Let's transfer this token to account-2
token.safeTransferFrom(web3.eth.accounts[1], web3.eth.accounts[2], 1, {from:web3.eth.accounts[1]})
//Now let's pause the contract
token.pause();
//Let's check if token is paused or not?
token.paused();
//Now let's try to transfer the token again, It should give an error
token.safeTransferFrom(web3.eth.accounts[2], web3.eth.accounts[3], 1, {from:web3.eth.accounts[2]})

You can test other methods like ‘approve’, they should be giving you an error when the contract is paused.

Deploy token using QuikNode

Let’s Deploy our Crowdbotics token (Botics) using QuikNode.

QuikNode provides Ethereum node as a service and partner of Crowdbotics platform.

For this purpose, We will use truffle-HD-wallet, so let’s install it.

npm install truffle-hdwallet-provider

We need to sign up and get an HttpProvider URL, For that check out this post. Below is truffle config for QuikNode using kovan network.

var HDWalletProvider = require("truffle-hdwallet-provider");
var mnemonic = "YOUR_MEMONICS"; // use a funded wallet
module.exports = {
    networks: {
        development: {
            host: "127.0.0.1",
            port: 7545,
            network_id: "*" // Match any network id
        },
        kovan: {
            provider: function() {
                return new HDWalletProvider(mnemonic, "https://mistakenly-smart-jay.quiknode.io/86d9e35e-8cdb-47ad-80a4-84f9e9537afa/C0_tKUunhUc0rM_i1HMxHA==/")
            },
            network_id: 42
        }
    }
};

Conclusion

We have learned how to make your ERC-721 token burnable and Pausable. We will Explore some more features in the next article. Let us know if you want to learn about anything about ERC-721 token in the comment section.

If you are building anything, you can look into DotLicense which is an Ethereum ERC721-based software licensing framework. See you can create a software license using ERC-721 token.

There are so many awesome use cases around ERC-721 token. What are you working on?