OpenZeppelin OpenZeppelin Contracts – Troubleshoot totalSupply() Count Issue in OpenZeppelin Contracts

openzeppelinopenzeppelin-contracts

I'm writing an NFT minting contract with openZeppelin and have 2 functions that can mint tokens. mint and reserveMint. Each function can be invoked independent of each other in various order at various time until either the totalSupply runs out. The reserveMint can be invoked until _reserve runs out.

The issue I'm having is that after all is minted the totalSupply is shown as 29 instead of 30. There are 30 tokens minted. First tokenID starts at 0 and last tokenID ends at 29. This is fine. What can I do to make sure the totalSupply in the contract is 30. I don't want to confuse users who look at the contract thinking that only 29 were minted.

Thank you!

uint256 private _reserve = 10; 
uint256 public constant totalSupply = 20;

function mint(uint256 numberOfTokens) public payable {
    uint256 supply = totalSupply();
    require( numberOfTokens <= 20, "You can mint 20 at a time." );
    require( supply + numberOfTokens < (totalSupply - _reserve), "Exceeds total supply" );
    require( msg.value >= Price * numberOfTokens,  "Ether sent is not correct" );

    for(uint256 i; i < numberOfTokens; i++){
        _safeMint( msg.sender, supply + i );
    }
}
function reserveMint(address _to, uint256 _amount) external onlyOwner() {
    require( _amount <= _reserve, "Exceeds reserved supply" );
    uint256 supply = totalSupply();
    for(uint256 i; i < _amount; i++){
        _safeMint( _to, supply + i );
    }
    _reserve -= _amount;
}

Best Answer

Let's take a look at your code for a sec:

uint256 public constant totalSupply = 20;

...

function reserveMint(address _to, uint256 _amount) external onlyOwner() {
    require( _amount <= _reserve, "Exceeds reserved supply" );
    uint256 supply = totalSupply();
    for(uint256 i; i < _amount; i++){
        _safeMint( _to, supply + i );
    }
    _reserve -= _amount;
}

You start out with a totalSupply of 20. The for loop then initializes a variable i. This will be initialized to zero (all variables in Solidity are initialized to their zero-ish representation: 0, address(0), false, etc.). As a result, on the first iteration of the for loop, when _safeMint is called, it will be called with _to and supply + 0 as the arguments, meaning that it's minting to the 20th slot, which was already counted.

You might want to initialize the for loop with:

for(uint256 i=1; i <= _amount; i++){

Instead of initializing i at zero. (There are plenty of other solutions, but that's the one we'd recommend.) Other than that, the code looks like it should work as expected. Happy coding!

Related Topic