A holder of Snow tokens is supposed to claim Snowman NFTs proportional to their stake, with the NFT count derived from how much Snow they hold.
claimSnowman sets amount to i_snow.balanceOf(receiver) — a raw 18-decimal token amount in wei — and passes it straight to mintSnowman, which loops amount times calling _safeMint. For any realistic balance (1 Snow == 1e18), the loop must run ~1e18 iterations, which always exceeds the block gas limit, so the claim reverts out-of-gas.
```solidity
// src/SnowmanAirdrop.sol
@> uint256 amount = i_snow.balanceOf(receiver); // 1 Snow == 1e18 (wei-scale)
i_snow.safeTransferFrom(receiver, address(this), amount);
@> i_snowman.mintSnowman(receiver, amount); // loops ~1e18 times -> out of gas
```
The NFT count is wrongly equated to the token's wei balance instead of a whole-token count, so the mint loop size is multiplied by 1e18.
Likelihood:
Triggers on every claim by any holder with a normal (non-dust) Snow balance, because 1e18 loop iterations always exceed the block gas limit.
Only sub-block-gas-limit dust balances (such as the 1-wei earnSnow mint) could ever complete a claim, so the feature is unusable for real holders.
Impact:
The core airdrop functionality is permanently broken for all legitimate holders — every real claim reverts.
The intended NFT distribution can never be performed, freezing the protocol's central feature.
A receiver is given 1 full Snow token (1e18 wei) and a valid Merkle proof + signature. The claim reverts because mintSnowman attempts ~1e18 _safeMint iterations:
```solidity
function test_real_claim_reverts_out_of_gas() public {
// receiver holds exactly 1 Snow and approves the airdrop
deal(address(snow), receiver, 1e18);
vm.prank(receiver);
snow.approve(address(airdrop), 1e18);
}
```
Because the gas cost grows linearly with the wei balance, no honest holder of 1 or more whole Snow tokens can ever claim.
Decouple the NFT count from token wei — mint a bounded count (for example, one NFT per whole Snow token) instead of one NFT per wei:
```diff
uint256 amount = i_snow.balanceOf(receiver);
i_snow.safeTransferFrom(receiver, address(this), amount);
i_snowman.mintSnowman(receiver, amount);
uint256 snowBalance = i_snow.balanceOf(receiver);
i_snow.safeTransferFrom(receiver, address(this), snowBalance);
// mint a bounded NFT count, decoupled from token wei (e.g. 1 NFT per whole Snow)
uint256 nftCount = snowBalance / 1e18;
i_snowman.mintSnowman(receiver, nftCount);
```
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.