As per @abcoathup’s suggestion to use OpenZeppelin ERC20 implementation, am creating a very simple upgradable ERC20 token as below:
// contracts/MyToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/access/AccessControl.sol";
contract MyToken is Initializable, ERC20UpgradeSafe, AccessControlUpgradeSafe {
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
function initialize(address admin, uint256 initialSupply) public initializer {
__ERC20_init("MyToken", "MYT");
__AccessControl_init_unchained();
_mint(admin, initialSupply * (10 ** uint256(decimals())));
_setupRole(BURNER_ROLE, admin);
_setupRole(DEFAULT_ADMIN_ROLE, admin);
}
function burn(address from, uint256 amount) public {
require(hasRole(BURNER_ROLE, msg.sender), "Caller is not a burner");
_burn(from, amount);
}
function revokeRole(bytes32 role, address account) public override {
require(
role != DEFAULT_ADMIN_ROLE,
"ModifiedAccessControl: cannot revoke default admin role"
);
super.revokeRole(role, account);
}
}
and deployed as below:
// migrations/3_deploy_mytoken.js
const MyToken = artifacts.require('MyToken');
const { deployProxy } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer, network, accounts) {
//await deployProxy(MyToken, ['0x63e4C1725fEB9EDc83d7951cFeD6e0fC3132A26f', 1000], { deployer, unsafeAllowCustomTypes: true, initializer: 'initialize' });
await deployProxy(MyToken, ['0x63e4C1725fEB9EDc83d7951cFeD6e0fC3132A26f', 1000], { deployer, initializer: 'initialize' });
};
Note that I’ve commented the deployProxy
line with unsafeAllowCustomTypes: true
. The compile fails:
name@name-MBP:~/projects/folder$ npx truffle test
Using network 'development'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Error: Contract `MyToken` is not upgrade safe
../@openzeppelin/contracts-ethereum-package/contracts/access/AccessControl.sol:53: Defining structs like `RoleData` is not yet supported
If you have manually checked for storage layout compatibility, you can skip this check with the `unsafeAllowCustomTypes` flag
https://zpl.in/upgrades/error-007
I understand I need to use unsafeAllowCustomTypes: true
in migration script as per this https://docs.openzeppelin.com/upgrades-plugins/1.x/api-truffle-upgrades
But all I want is for MyToken’s initialize
function to setup DEFAULT_ADMIN_ROLE
to be the address passed in the function function initialize(address admin, ...)
.
How do I set that without using unsafeAllowCustomTypes: true
in the migration script?