Upgradeability of ERC20 token contract with a minting function

I am upgrading a simple ERC20 Upgradable token contract.

However, I am trying to upgrade it to a new version and all I want to do in the version 2 is simply mint 10000 more tokens.

Here are my doubts:

  1. What’s the effective procedure to do it? Can I include the mint function in the initialize(constructor) of the version 2 contract? But will it up upgrade safe then?

  2. Will the new version, on deployment, increase the total supply of the token actual token since I am trying to mint some more tokens in vesrion 2?

  3. Since I am using the truffle upgrades package to do this whole thing, should I simply use the upgradeProxy package from truffle upgrades? Or how exactly should the migration files be written in order to achieve the desired execution.

My Token V1

pragma solidity 0.6.2;
// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

contract PlayTokenV1 is Initializable,OwnableUpgradeable,ERC20PausableUpgradeable{
    function initialize(address _PublicSaleAddress) initializer public{
        _mint(owner(),50600000 ether);
        _mint(_PublicSaleAddress,1000000 ether);

My TokenV2

pragma solidity 0.6.2;
// SPDX-License-Identifier: MIT

import "./PlayTokenV1.sol";

contract PlayTokenV2 is PlayToken{
    function initialize() initializer public{
        _mint(owner(),999 ether);

Migration file of TokenV2

const { upgradeProxy } = require('@openzeppelin/truffle-upgrades');

const tokenContract = artifacts.require('PlayToken');
const tokenV2 = artifacts.require('PlayTokenV2');

module.exports = async function (deployer,network,accounts) {
	const tokenv1 = await tokenContract.deployed();
  	const newInstance = await upgradeProxy(tokenv1.address, tokenV2, { deployer, initializer: 'initialize' });
  	console.log("Upgraded to", newInstance.address);

Would really appreciate your help @abcoathup

1 Like

Hi @Sam0000,

We protect our initialize function so that it can only be called once with the initializer modifier. When we upgrade we can’t use the initializer modifier again as we have already initialized.

Instead we create a function with a new name v2Upgrade or initializeV2 or additionalMint or whatever best communicates the functionality.

We need to protect this new function so that it can only be called by us (if required) and it can only be called once.

This could be as simple as checking a boolean such as v2Upgrade hasn’t been set before doing the upgrade initialization.

Currently we can’t call an upgrade initialization function during the upgrade, so you can’t include this in upgradeProxy. Instead once we have upgraded, we can call the upgrade initialization function.

Yes. The _mint function increases the totalSupply as well as the balance of the account.

You should call upgradeProxy in a migration script to do the upgrade. If you deployed with 2_deploy.js then the upgrade could be in 3_upgrade.js.

You also need to call the upgrade initialization function in this migration script.

You can create higher level tests to check this upgrade.

To test an upgrade, you can do a deployProxy and then an upgradeProxy. See: https://docs.openzeppelin.com/upgrades-plugins/1.x/truffle-upgrades#test-usage

For an example test, see BoxV2.proxy.test.js in: OpenZeppelin Upgrades: Step by Step Tutorial for Truffle

As an aside, if you are upgrading to mint additional tokens to the owner of the token, then you should discuss with your community before hand to let them know why you are doing this.

Hi @Sam0000,

There is an open issue to support calling an upgrade function: