Snowman Merkle Airdrop

AI First Flight #10
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Contract function fail

Root + Impact

Description

  • Minting Snowman NFT seamlessly

  • A looping error could cause contract failure if thousands of NFTs are mininted simultaniously

// Root cause in the codebase with @> marks to highlight the relevant section
//Snowman.sol
@>function mintSnowman(address receiver, uint256 amount) external {
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
//SnowmanAirdrop.sol
function claimSnowman(
address receiver,
bytes32[] calldata merkleProof,
uint8 v,
bytes32 r,
bytes32 s
) external nonReentrant {
if (receiver == address(0)) {
revert SA__ZeroAddress();
}
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
if (!_isValidSignature(receiver, getMessageHash(receiver), v, r, s)) {
revert SA__InvalidSignature();
}
@> uint256 amount = i_snow.balanceOf(receiver);
bytes32 leaf = keccak256(
bytes.concat(keccak256(abi.encode(receiver, amount)))
);

Risk

Likelihood:

  • Within mintSnowman function the for loop will run out of gas if minting 10,000+ NFTs because the SnowmanAirDrop contract uses a claimSnowman function that uses (uint256 amount = i_snow.balanceOf(receiver);) it causes the loop to fail


Impact:

  • Will break the contract


Proof of Concept

Snowman.sol
// >>> EXTERNAL FUNCTIONS
function mintSnowman(address receiver, uint256 amount) external {
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}
Problems
1. Looping _safeMint in a for loop is expensive
A.claimSnowman function bc loop will fail if thousands of tokens SnowmanMinted
//uint256 amount = i_snow.balanceOf(receiver);//
2. _safeMint triggers ERC721 receiver checks every iteration

Recommended Mitigation

- remove this code
function mintSnowman(address receiver, uint256 amount) external {
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
+ add this code
//Create error log: TooManyToMint
function mintSnowman(address receiver, uint256 amount) external {
if (amount > 100) revert TooManyToMint();
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!