ERC20Mintable contract application returns a strange wrong number

Based on OpenZeppilin ERC20Mintable contract, I add a function to limit maximum minterable token amount. I add a static variable uint256 MaxSupply to record and want to make MaxSupply accessiable to contract owner only.

But when I use onlyMinter modifier, It retruns a long strange number,like below:

Token Balance : 1000000000000000000000
Token current supply : 1000000000000000000000
Token MaxSupply: 3963877391197344453575983046348115674221700746820753546331534351508065746944

However, when remove onlyMinter modifier, the result is correct as expectation:

Token Balance : 1000000000000000000000
Token current supply : 1000000000000000000000
Token MaxSupply: 1100000000000000000000

:computer: Environment
The OpenZeppelin version should be latest. I got it by run:
git clone https://github.com/OpenZeppelin/openzeppelin-contracts.git
and copy all the used .sol file to a folder.

the solidity version is solc@0.5.9, higer than declared version in solidity source code.

:memo:Details
I call the contract using the following code:

var tokenContractAddress = "0x*****************";
var myAddress = "0x******************";
var async = require('asyncawait/async');
var await = require('asyncawait/await');
const Web3 = require('web3');
const web3 = new Web3('http://localhost:8545');
const main = async () => {
    var abi = JSON.parse(fs.readFileSync('/root/Mintable/abi.json', 'utf-8'));
    const contract = new web3.eth.Contract(abi, tokenContractAddress);
    await web3.eth.personal.unlockAccount(myAddress, "******", 600);

    var balance_from = await contract.methods.balanceOf(myAddress).call();
    var totalsupply = await contract.methods.totalSupply().call();
    var MaxSupply = await contract.methods.ViewMaxSupply().call();

    console.log(`Token Balance : ${balance_from}`);
    console.log(`Token current supply : ${totalsupply}`);
    console.log(`Token MaxSupply: ${MaxSupply}`);
};
main();

:1234: Code to reproduce

pragma solidity ^0.5.0;
import "./ERC20.sol";
import "./MinterRole.sol";
contract ERC20MintableMaxSupply is ERC20, MinterRole {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 MaxMintAmount;//max minerable amount after first issue
    uint256 MaxSupply;//initial issue amount plus MaxMintAmount

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        uint256  _initSupply,
        uint256  _MaxMintAmount
        ) public {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        MaxMintAmount = _MaxMintAmount;
        MaxSupply = _initSupply + _MaxMintAmount;
        _mint(msg.sender, _initSupply  * (10 ** uint256(decimals)));
    }
    function mint(address account,uint256 MintAmount) public onlyMinter returns (bool) {
      uint256 curSupply;
      curSupply = totalSupply() + MintAmount * (10 ** uint256(decimals));
      require( curSupply <= ( MaxSupply * (10 ** uint256(decimals)) ), "error: not permitted to exceed maximun supply.");
      _mint(account, MintAmount * (10 ** uint256(decimals)));
      return true;
    }
    function ViewMaxSupply() public view returns (uint256) {
     return ( MaxSupply * (10 ** uint256(decimals)) );
    }
}

Please help. Thanks.

1 Like

Hi @Ntydrm welcome to the community :wave:

To have a mintable token with a capped (maximum) supply you can use OpenZeppelin ERC20Capped https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Capped

A simple token example using ERC20Capped is as follows:

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/ERC20Capped.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";

contract MyToken is ERC20Capped, ERC20Detailed {
    constructor ()
    public
    ERC20Capped(1000000*10**18)
    ERC20Detailed("My Token", "TKN", 18)
    {
        // solhint-disable-previous-line no-empty-blocks
    }
}

I assume that you meant that the error was occurring when calling from a non-minter address with the onlyMinter modifier added to the view function:

    function ViewMaxSupply() public view onlyMinter returns (uint256) {
     return ( MaxSupply * (10 ** uint256(decimals)) );
    }

This is an issue with web3:


Adding a modifier to view the MaxSupply only prevents other contracts from reading the value, but it is visible externally. What are you attempting to do by restricting access?

https://solidity.readthedocs.io/en/latest/contracts.html?highlight=private#visibility-and-getters
Everything that is inside a contract is visible to all observers external to the blockchain. Making something private only prevents other contracts from reading or modifying the information, but it will still be visible to the whole world outside of the blockchain.

Thanks for your detailed reply.
I just want to make some experiment about how to control the access right to contract info.
I got new info from the example and your answer.

I changed the compiler version number in .sol file to 0.5.9, same as my complier installed, then the error disappeared.
as you mentioned above, even onlyMinter modifier used to the viewMaxSupply() function, non-minter account still can get the value MaxSupply.

onlyMinter modifier is used only to prevent non-minter account from modifying any info of contract, right?

Thanks for your nice help.

1 Like

Hi @Ntydrm

MaxSupply state variable doesn’t have explicit visibility declared, the default for state variables is internal which means it isn’t readable by other contracts (except those that inherit from it).

onlyMinter modifier restricts access to functions to only accounts with a MinterRole. Though this is typically for functions modifying state rather than reading state as all data in a contract can be accessed externally.

To read up on OpenZeppelin access control please see the documentation:
https://docs.openzeppelin.com/contracts/2.x/access-control