Lucene search

K
code423n4Code4renaCODE423N4:2022-09-VTVL-FINDINGS-ISSUES-472
HistorySep 23, 2022 - 12:00 a.m.

Limited supply of VariableSupplyERC20Token can be bypassed to mint an infinite amount of tokens

2022-09-2300:00:00
Code4rena
github.com
6
variablesupplyerc20token
bypassed minting
limited supply
inflation
admin power

Lines of code

Vulnerability details

Limited supply of VariableSupplyERC20Token can be bypassed to mint an infinite amount of tokens

VariableSupplyERC20Token is defined as

A ERC20 token contract that allows minting at will, with limited or unlimited supply. No burning possible

In the case of a limited supply, it can be set during deployment with the constructor parameter maxSupply_, which is stored in mintableSupply. It is defined as:

the maximum supply. The contract won't allow minting over this amount.

The issue is that mintableSupply is decremented upon minting. And because of this check, mintableSupply can reach 0. Further mints will bypass the check, meaning it will be possible to mint more tokens that what mintableSupply intended (unlimited supply)

Impact

I consider it Medium because it essentially means a Token supply can be drastically inflated by the admin (with no actual limit), and such dilution would have a direct impact on the token value.
The readme does mention the knowledge of admin power, but this issue falls outside of the acknowledge revoking claim powers, because it impacts the token, not the vesting itself.

Proof Of Concept

  • Admin deploys VariableSupplyERC20Token with initialSupply_ == 0 and maxSupply_ = 1e6.
  • Admin calls mint(address(Vesting), amount == 1e6) to mint the total token supply to the vesting contract.
    - mintableSupply = 1e6, so the condition line 40 is true, and the call enters the block in the if statement.
    - the following check passes, as amount == mintableSupply.
    - then, the following computation is performed: mintableSupply -= amount, meaning mintableSupply is set to 0.
  • The maximum supply has been minted
  • Admin decides to call mint(address(Vesting), amount == 1e8).
    - mintableSupply = 0, so the condition line 40 is false. The call bypasses the if block and calls _mint(Vesting, 1e8), minting the tokens.
  • The token supply is now 1e8, while its maximum supply was supposed to be 1e6

Tools Used

Manual Analysis

Mitigation

1 - You can use an additional variable to prevent minting from happening if the maxSupply has been minted

  • Add a boolean canMint, initialized to true

  • In mint(), add the following:

    36: function mint(address account, uint256 amount) public onlyAdmin {
    37: require(account != address(0), “INVALID_ADDRESS”);

    •       require(canMint, "MAX_SUPPLY ALREADY MINTED")
      

    38: // If we’re using maxSupply, we need to make sure we respect it
    39: // mintableSupply = 0 means mint at will
    40: if(mintableSupply > 0) {
    41: require(amount <= mintableSupply, “INVALID_AMOUNT”);
    42: // We need to reduce the amount only if we’re using the limit, if not just leave it be
    43: mintableSupply -= amount;

    •           // if all the mintable supply has been minted, set canMint to false
      
    •           if (mintableSupply == 0) canMint = false;
      

    44: }
    45: _mint(account, amount);
    46: }


The text was updated successfully, but these errors were encountered:

All reactions