VariableSupplyERC20Token allows to set a "maxSupply_" during construction which should set the maximum amount that an admin can mint.
@param maxSupply_ - What's the maximum supply. The contract won't allow minting over this amount. Set to 0 for no limit.
This variable is later used in the mint()
function to check if there's enough amount left to mint more tokens. However, if the minted amount(s) (ie one or more calls to mint) reduce this amount to 0, then the behavior changes to the "no limit" mode which will allow any amount to be minted later on.
Giving this a medium risk since this function is admin restricted.
- Create a token with
maxSupply > 0
. - Call mint so that this amount gets reduced to exactly 0.
- After this, any amount can be minted.
Here's a small test to reproduce the issue:
describe("VariableSupplyERC20Token", async function () {
it("should not mint more than max supply", async () => {
const [admin, bob, alice] = await ethers.getSigners();
const maxSupply = 100;
const initialSupply = 0;
const VariableSupplyERC20Token = await ethers.getContractFactory("VariableSupplyERC20Token", admin);
const token = await VariableSupplyERC20Token.deploy("Broken", "BRO", initialSupply, maxSupply);
await token.deployed();
expect(await token.isAdmin(admin.address)).to.be.true;
// we mint so that mintableSupply is reduced to exactly 0, which resets the
// "max supply" behaviour and allows to mint any amount
await (await token.mint(bob.address, maxSupply / 2)).wait();
await (await token.mint(bob.address, maxSupply / 2)).wait();
await expect(token.mint(alice.address, 999)).to.be.revertedWith("INVALID_AMOUNT");
});
});
Keep track of the "no limit" mode in a separate variable instead of using the logic of mintableSupply == 0
.