ERC20Capped: Immutable Variables cannot be read during contract creation time

When using ERC20Capped, in a contract, and compiling with truffle. Threw an error saying that immutable variables cant be used in constructors, inside ERC20Capped.

:computer: Environment
Truffle v5.2.3
Node v14.15.1
ERC20Capped
ERC20Burnable
Ownable

:memo:Details
image
Tried compiling a contract using ERC20Capped with Truffle, to get an error about immutable variables, not being able to be used in a constructor.

:1234: Code to reproduce

    contract CommonERC20 is ERC20Capped{

    constructor(
        string memory name,
        string memory symbol,
        uint256 supplyCap
    )
     ERC20(name, symbol)
     ERC20Capped(supplyCap)
    {
        
    }
}
1 Like

Hi @grimmdev,

Welcome to the community :wave:

I can reproduce using OpenZeppelin Contracts 4 Release Candidate when attempting to mint in the constructor. This would only happen when minting in the constructor.

// contracts/GLDToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract GLDToken is ERC20Capped {
    constructor(uint256 initialSupply) ERC20("Gold", "GLD") ERC20Capped(1000*10**18) {
        _mint(msg.sender, initialSupply);
    }
}
$ npx truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/GLDToken.sol

TypeError: Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
  --> @openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol:26:16:
   |
26 |         return _cap;
   |                ^^^^

Compilation failed. See above.
Truffle v5.2.3 (core: 5.2.3)
Node v10.23.2

So as long as I mint post creation, I can use a cap in my token? If I’m understanding correctly

2 Likes

Hi @grimmdev,

Minting outside the constructor should be fine. You should create appropriate unit tests.

OpenZeppelin Contracts 4 is still a release candidate, so I want to check if it is possible to enable capped minting in the constructor.

1 Like

Hello @grimmdev, and thanks for your message.

We should have anticipated this issue :cry:
The thing is, ERC20Capped adds an extra check in the _mint function that verifies you are not exceeding the cap. For efficiency reasons, we made the cap immutable. This removes a load operation when doing the check, and thus reduces the gas cost of minting. The downside, as you show, is that this immutable variable cannot be read from during construction, which means you cannot use ERC20Capped’s _mint protection during the construction.

The good news is that the “non protected” ERC20._mint remains available!

contract GLDToken is ERC20Capped {
    constructor(uint256 initialSupply) ERC20("Gold", "GLD") ERC20Capped(1000*10**18) {
        ERC20._mint(msg.sender, initialSupply);
    }
}

Note that, while this works well, it doesn’t verify that initialSupply <= 1000*10**18 so you might want to add this check in the constructor.

2 Likes

Thank you both for your response, sorry for the late reply. Very informative and helpful, thank you :slight_smile:

1 Like

Hi @grimmdev,

Thanks @Amxx. I have created an issue for this: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2580