Creating Upgradable ERC20 token using OpenZeppelin and Buidler plugin

I am trying to create upgradable Erc20 token using openzeppelin and buidler plugin… suggest me some docs regarding upgradable Erc20 token .

1 Like

Hi, how about this doc: https://docs.openzeppelin.com/learn/upgrading-smart-contracts#upgrading-a-contract-via-plugins

2 Likes

Hi @Skyge thanks for Your suggestion and https://docs.openzeppelin.com/learn/upgrading-smart-contracts#upgrading-a-contract-via-plugins this doc is fine. i can able to deploy upgradable smart contract using buidler plugin and i already did that…
Now i am trying to develop ERC20 token using openzeppelin and buidler plugin for that i need some doc.

1 Like

Hi @Prabhakaran,

I would suggest using the Learn guides (as suggested by @Skyge). Please note Buidler is now Hardhat. The Learn guides have been updated to use Hardhat.

If you want to create an upgradeable mintable ERC20 token then you could look at the preset as an example to create your own extending from the upgrade safe ERC20 implementation:

Thanks @abcoathup then I will try this one : OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/v3.0.0/contracts/presets/ERC20PresetMinterPauser.sol

1 Like

Hi sir @abcoathup i tried this one : OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/v3.0.0/contracts/presets/ERC20PresetMinterPauser.sol. and i able to deploy the code and get contract address.herewith i am attaching the screenshot .


But i am still struggling to initialize Token name,Token symbol and Total supply value…
can you help me with some code that use to initialize token name,symbol,decimal,and total supply…

1 Like

Hi @Prabhakaran,

I used the steps from OpenZeppelin Upgrades: Step by Step Tutorial for Buidler to setup an environment.

:exclamation: Buidler is now Hardhat. There will be an Upgrades Plugin for Hardhat soon.

I also used Create an ERC20 using buidler, without writing Solidity for interacting.

I created an upgradeable ERC20 token and then interacted with it using the console.

MyToken.sol

(Based on https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/v3.0.0/contracts/presets/ERC20PresetMinterPauser.sol#L35)

// contracts/MyToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts-ethereum-package/contracts/Initializable.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Burnable.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Pausable.sol";

contract MyToken is Initializable, ContextUpgradeSafe, AccessControlUpgradeSafe, ERC20BurnableUpgradeSafe, ERC20PausableUpgradeSafe {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
     * account that deploys the contract.
     *
     */

    function initialize(string memory name, string memory symbol) public {
        __Context_init_unchained();
        __AccessControl_init_unchained();
        __ERC20_init_unchained(name, symbol);
        __ERC20Burnable_init_unchained();
        __Pausable_init_unchained();
        __ERC20Pausable_init_unchained();

        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());

        _setupRole(MINTER_ROLE, _msgSender());
        _setupRole(PAUSER_ROLE, _msgSender());
    }

    /**
     * @dev Creates `amount` new tokens for `to`.
     *
     * Requirements:
     *
     * - the caller must have the `MINTER_ROLE`.
     */
    function mint(address to, uint256 amount) public {
        require(hasRole(MINTER_ROLE, _msgSender()), "MyToken: must have minter role to mint");
        _mint(to, amount);
    }

    /**
     * @dev Pauses all token transfers.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function pause() public {
        require(hasRole(PAUSER_ROLE, _msgSender()), "MyToken: must have pauser role to pause");
        _pause();
    }

    /**
     * @dev Unpauses all token transfers.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function unpause() public {
        require(hasRole(PAUSER_ROLE, _msgSender()), "MyToken: must have pauser role to unpause");
        _unpause();
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(ERC20UpgradeSafe, ERC20PausableUpgradeSafe) {
        super._beforeTokenTransfer(from, to, amount);
    }
}

deploy.js

// scripts/deploy.js
const { ethers, upgrades } = require("@nomiclabs/buidler");

async function main() {
  const MyToken = await ethers.getContractFactory("MyToken");
  console.log("Deploying token...");
  const token = await upgrades.deployProxy(MyToken, ["My Token", "TKN"], { unsafeAllowCustomTypes: true  });
  console.log("Token deployed to:", token.address);
}

main();

buidler.config.js

// buidler.config.js
usePlugin('@nomiclabs/buidler-ethers');
usePlugin('@openzeppelin/buidler-upgrades');
 
module.exports = {
    solc: {
        version: '0.6.12',
    },
};

Local network

npx buidler node

Deploy

$ npx buidler run scripts/deploy.js --network localhost
Compiling...

...

Compiled 12 contracts successfully
Deploying token...

Warning: Potentially unsafe deployment of MyToken

    You are using the `unsafeAllowCustomTypes` flag to skip storage checks for structs and enums.
    Make sure you have manually checked the storage layout for incompatibilities.

Token deployed to: 0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7

Interact

$ npx buidler console --network localhost
All contracts have already been compiled, skipping compilation.
> const Token = await ethers.getContractFactory("MyToken")
undefined
> const token = await Token.attach("0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7")
undefined
> await token.name()
'My Token'
> accounts = await ethers.provider.listAccounts()
[ '0xc783df8a850f42e7F7e57013759C285caa701eB6',
  '0xeAD9C93b79Ae7C1591b1FB5323BD777E86e150d4',
...
> await token.mint(accounts[1], "100000000000000000000")
{ hash:
...
> (await token.balanceOf(accounts[1])).toString()
'100000000000000000000'

Thank you @abcoathup sir… I will try it out

1 Like

Hi @Prabhakaran,

There is now an Upgrades Plugin for Hardhat: https://docs.openzeppelin.com/upgrades-plugins/1.x/hardhat-upgrades

I updated the OpenZeppelin Upgrades: Step by Step Tutorial for Hardhat

1 Like

A post was split to a new topic: Is it possible to write 3 level smart contract for any token?

Hi @Prabhakaran,

We have found an error in Upgrades Plugins for Truffle and Hardhat. Users of the flag unsafeAllowCustomTypes should update their dependencies to the latest version.

See post for more details: Problem in Upgrades Plugins for users of unsafeAllowCustomTypes.

A post was split to a new topic: How to deploy Clones