Create an ERC20 using Truffle, without writing Solidity

In this tutorial we will use a Preset ERC20 contract in OpenZeppelin Contracts v3.x to create an ERC20 using Truffle, without having to write any Solidity code.

Setting up the Environment

We begin by creating a new project.

$ mkdir mytoken && cd mytoken
$ npm init -y

Then we install OpenZeppelin Contracts

$ npm i --save-dev @openzeppelin/contracts

Next we install a development tool for deployment, for this tutorial we will use Truffle but we could use any other tools such as OpenZeppelin CLI.

$ npm i truffle

Getting the contract artifacts

We will setup our Solidity project using truffle init to create a contracts directory and configuration to connect to a network.

$ npx truffle init

Starting init...
================

> Copying project files to /home/abcoathup/projects/mytoken

Init successful, sweet!

We are going to use Preset ERC20PresetMinterPauser which is an ERC20 that is preset so it can be minted, paused and burned.

The Preset contracts have already been compiled, so we only need to copy the artifacts to the build/contracts directory.

$ mkdir -p build/contracts/
$ cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/

Deploy the contract

We will use truffle develop to open a Truffle console with a development blockchain

$ npx truffle develop
Truffle Develop started at http://127.0.0.1:9545/

Accounts:
(0) 0x0445c33bdce670d57189158b88c0034b579f37ce
(1) 0x46b68a577f95d02d2732cbe93c1809e9ca25b443
(2) 0xff8ddfd4ae8ed56c4b94738fef931b732f3aaeb5
(3) 0xc28aaeb2c63c3617e6733d786a6d7273871b805f
...

Private Keys:
(0) 11e8321617611610d7561dfdf1fdbf87cee4cc99b97cc73c68f0eb5715fff7cc
(1) b28ee7deb262fbb6cccabb43179406e97bf7ff4c20b66feac3321019373531bd
(2) 44e5ce1f204a63e50faf2f202af1d5653aace83805dd9bc7062033f0625aaaa7
(3) 168e28ad21ede684f8fd3ddc8b88e9474c740884f43bda1d567e968544b53a6e
...

Mnemonic: ridge drop soon clutch empty north car drum maximum obey clinic coin

⚠️  Important ⚠️  : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.

truffle(develop)>

We can deploy our new token to our development blockchain. Providing a name and a symbol as parameters to the constructor to create a new ERC20PresetMinterPauser.

truffle(develop)> token = await ERC20PresetMinterPauser.new("My Token", "TKN")
undefined

Interact with our Token

The accounts that we can use were displayed when we started truffle develop

Token metadata

We can call the contract to read token metadata such as name, symbol and decimals

truffle(develop)> await token.name()
'My Token'
truffle(develop)> await token.symbol()
'TKN'
truffle(develop)> (await token.decimals()).toString()
'18'

Mint

We can send a transaction to mint tokens to a given account, from an account with the minter role.
In our case we are minting from the account which deployed the token, which is given the minter role.

We will mint 1000 tokens (the token has 18 decimals).

truffle(develop)> await token.mint('0x46b68a577f95d02d2732cbe93c1809e9ca25b443','1000000000000000000000')
{
  tx: '0xf04c4342eadd64e81ba631d7340ca1bec4f402f2775e8a9087c8af06ff34e7c7',
  receipt: {
    transactionHash: '0xf04c4342eadd64e81ba631d7340ca1bec4f402f2775e8a9087c8af06ff34e7c7',
    transactionIndex: 0,
    blockHash: '0x907fc78d3973dc1b3081148c2ab3172857f32ffc73d6102b756033f60431c850',
    blockNumber: 2,
    from: '0x0445c33bdce670d57189158b88c0034b579f37ce',
    to: '0x3797c825cac4a1fa765f6d8cd7787fb195849555',
    gasUsed: 68253,
...

We can check the balance

truffle(develop)> (await token.balanceOf('0x46b68a577f95d02d2732cbe93c1809e9ca25b443')).toString()
'1000000000000000000000'

Burn

We can send a transaction to burn tokens (from the account holder)

truffle(develop)> await token.burn('10000000000000000000', {from: '0x46b68a577f95d02d2732cbe93c1809e9ca25b443'})
{
  tx: '0x626b3c012f8edb66cbb45b279554c8f0ac9f5db35097e1364a45e9df5e96027e',
  receipt: {
    transactionHash: '0x626b3c012f8edb66cbb45b279554c8f0ac9f5db35097e1364a45e9df5e96027e',
    transactionIndex: 0,
    blockHash: '0x73ec9a1245d2d28cf08aaefb63975542c8c23ee221ef3479a26e00f5fbc7b949',
    blockNumber: 3,
    from: '0x46b68a577f95d02d2732cbe93c1809e9ca25b443',
    to: '0x3797c825cac4a1fa765f6d8cd7787fb195849555',
    gasUsed: 36797,
...

We can check the balance after burning

truffle(develop)> (await token.balanceOf('0x46b68a577f95d02d2732cbe93c1809e9ca25b443')).toString()
'990000000000000000000'

Pause

We can pause our Token by sending a transaction calling the pause function, from an account with the pauser role.
In our case we are pausing from the account which deployed the token, which is given the pauser role.

truffle(develop)> await token.pause()
{
  tx: '0x93385cbb2d893658878db962cce2fcc520e211cfdc1a9d49660489b8d20b6768',
  receipt: {
    transactionHash: '0x93385cbb2d893658878db962cce2fcc520e211cfdc1a9d49660489b8d20b6768',
    transactionIndex: 0,
    blockHash: '0x84529e46656d47dd642b10ed3606b7306de8020060d7711dc5a963d6cb4f142a',
    blockNumber: 4,
    from: '0x0445c33bdce670d57189158b88c0034b579f37ce',
    to: '0x3797c825cac4a1fa765f6d8cd7787fb195849555',
    gasUsed: 30548,
...

Transactions which attempt to transfer (such as mint) will revert whilst paused.

truffle(develop)> await token.mint('0x46b68a577f95d02d2732cbe93c1809e9ca25b443','1000000000000000000000')
Thrown:
Error: Returned error: VM Exception while processing transaction: revert ERC20Pausable: token transfer while paused -- Reason given: ERC20Pausable: token transfer while paused.    
...

Video

I made an asciinema going through all the steps in the tutorial:
https://asciinema.org/a/364291

Next steps

  • We could deploy using truffle migrate and the following migration script
// migrations/2_deploy.js

const Token = artifacts.require('@openzeppelin/contracts/ERC20PresetMinterPauser');

module.exports = function(deployer) {
  deployer.deploy(Token, 'My Token', 'MYT');
};
4 Likes

A post was split to a new topic: Are there any DAO based ERC20s?

3 posts were split to a new topic: Test ERC20 with Truffle

Cannot get this to work any longer.

npx truffle init

Running the command above now ends with 94 packages needing funding, 54 vulnerabilities(1 low, 35 moderate, 16 high, 2 critical). Trying to ignore this and move forward regardless.

npx truffle development

The command above doesn't work and provides the following error

Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:67:19)
    at Object.createHash (node:crypto:135:10)
    at hash160 (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\node_modules\ethereum-cryptography\vendor\hdkey-without-crypto.js:249:1)
    at HDKey.set (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\node_modules\ethereum-cryptography\vendor\hdkey-without-crypto.js:50:1)
    at Function.HDKey.fromMasterSeed (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\node_modules\ethereum-cryptography\vendor\hdkey-without-crypto.js:194:1)
    at Function.EthereumHDKey.fromMasterSeed (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\node_modules\ethereumjs-wallet\dist\hdkey.js:16:1)
    at Object.getAccountsInfo (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\packages\core\lib\mnemonics\mnemonic.js:45:1)
    at Object.module.exports [as run] (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\packages\core\lib\commands\develop\run.js:30:44)
    at Command.run (C:\Users\SGK\Documents\Ethereum\Token\node_modules\truffle\build\webpack:\packages\core\lib\command.js:189:1)
Truffle v5.4.33 (core: 5.4.33)
Node v17.4.0