Root + Impact
Description
@>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++;
}
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:
Impact:
Proof of Concept
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++;
}
}
Problems
1. Looping _safeMint in a for loop is expensive
A.claimSnowman function bc loop will fail if thousands of tokens SnowmanMinted
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++;
}