code-423n4 / 2023-10-nextgen-findings

5 stars 3 forks source link

mint with sales option 3 doesn't work as expected #1981

Closed c4-submissions closed 7 months ago

c4-submissions commented 7 months ago

Lines of code

https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L249-L252

Vulnerability details

Summary

lastMintDate[col] is set to be higher than expected, which can lead to the minting process being blocked for some time.

Vulnerability Details

In the mint function in the MintContract if the salesOption of the collection is set to 3 then we can only mint 1 token per period. This is the expression used to calculate when the lastMintDate[col] was:

lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * 
(gencore.viewCirSupply(col) - 1))

However if we airdrop tokens the circulatingSupply increases and so does the lastMintDate. So now if 1 time period has passed and someone tries to mint, he won't be able to do it.

Proof of Concept

Add this test to nextGen.test.js and run npx hardhat test, also at the top of the test file add: (const { loadFixture, time } = require("@nomicfoundation/hardhat-toolbox/network-helpers"))

context("Custom tests", () => {

  it("#DoS salesoption 3 with airdrop", async function () {
    await contracts.hhCore.createCollection(
      "Test Collection 5",
      "Artist 5",
      "For testing",
      "www.test.com",
      "CCO",
      "https://ipfs.io/ipfs/hash/",
      "",
      ["desc"],
    )

    await contracts.hhCore.setCollectionData(
      5, // _collectionID
      signers.addr1.address, // _collectionArtistAddress
      2, // _maxCollectionPurchases
      10000000, // _collectionTotalSupply 10 mil
      1000, // _setFinalSupplyTimeAfterMint
    )

    await contracts.hhCore.addRandomizer(
      5, contracts.hhRandomizer,
    )

    await contracts.hhMinter.setCollectionCosts(
      5, // _collectionID
      0, // _collectionMintCost
      0, // _collectionEndMintCost 0
      0, // _rate
      200, // _timePeriod
      3, // _salesOptions
      '0xD7ACd2a9FD159E69Bb102A1ca21C9a3e3A5F771B', // delAddress
    )

    await contracts.hhMinter.setCollectionPhases(
      5, // _collectionID
      1699993193, // _allowlistStartTime
      1699993193, // _allowlistEndTime
      1699993193, // _publicStartTime
      1796931278, // _publicEndTime
      "0x8e3c1713145650ce646f7eccd42c4541ecee8f07040fc1ac36fe071bbfebb870", // _merkleRoot
    )

    // airdrop some tokens
    await contracts.hhMinter.airDropTokens([signers.addr3.address], ["someTokenData"], [28], 5, [100]);

    await time.setNextBlockTimestamp(1699993193 + 1);

    //random user trying to mint
    await contracts.hhMinter.mint(5, 1, 1, '{"tdh": "100"}', signers.addr2.address,
       ["0x0000000000000000000000000000000000000000000000000000000000000000"], 
         "0x0000000000000000000000000000000000000000", 235);

    // 1 time period passess 
    // Should allow mint but it doesn't and because of the airdrop the function will be blocked
    await time.setNextBlockTimestamp(1699993193 + 202);

    await expect(contracts.hhMinter.mint(5, 1, 1, '{"tdh": "100"}', signers.addr3.address,
       ["0x0000000000000000000000000000000000000000000000000000000000000000"], 
       "0x0000000000000000000000000000000000000000", 236))
       .to.be.reverted;
  })

})

In this test we see that after we airdrop some tokens we were able to mint the first time because of the check:

if (lastMintDate[col] == 0) {
            // for public sale set the allowlist the same time as publicsale
            timeOfLastMint = collectionPhases[col].allowlistStartTime - collectionPhases[col].timePeriod;
}

However when we try to mint the second time, we weren't able to since the circulating supply now is 101 tokens and lastMintDate is calculated as followed:

1699993193 + 200 * 101 (102 tokens since the supply first increases - 1 from the formula) = 1 700 013 393 but we try to mint at time 1699993193 + 202 = 1 699 993 395(this is expected time and should be able to mint)

Impact

Blocks the mint function and users are not able to mint tokens as expected

Tools Used

VS Code, Hardhat, Manual Review

Recommended Mitigation Steps

I would recommend changing the way lastMintDate variable is calculated. The first time we mint it needs to be the collectionPhases[col].allowlistStartTime + collectionPhases[col].timePeriod and after that just add timePeriod every time a new mint happens.

Assessed type

Math

c4-pre-sort commented 7 months ago

141345 marked the issue as duplicate of #632

c4-judge commented 7 months ago

alex-ppg marked the issue as duplicate of #881

c4-judge commented 7 months ago

alex-ppg marked the issue as duplicate of #2012

c4-judge commented 7 months ago

alex-ppg changed the severity to 3 (High Risk)

c4-judge commented 7 months ago

alex-ppg marked the issue as partial-50