Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

State Change Without Event

Description

  • State changes in smart contracts should emit events to enable proper monitoring and indexing by external systems.

  • The BidBeastsNFTMarketPlace::withdrawAllFailedCredits() function resets the failedTransferCredits mapping without emitting any event to track this state change.

@> function withdrawAllFailedCredits(address _receiver) external {

Risk

Likelihood:

  • Occurs every time someone withdraws failed transfer credits

  • State changes are not tracked by event indexers

Impact:

  • Difficult to monitor and audit credit withdrawals

  • Poor user experience due to lack of transparency

Proof of Concept

function test_LOW_L6_StateChangeWithoutEvent() public {
uint256 tokenId = _mintAndListNFT(ALICE, MIN_PRICE, BUY_NOW_PRICE);
// Create scenario with failed transfer credits
vm.prank(BOB);
market.placeBid{value: MIN_PRICE + 0.1 ether}(tokenId);
vm.etch(BOB, type(RevertingContract).runtimeCode);
vm.prank(CHARLIE);
market.placeBid{value: MIN_PRICE + 0.2 ether}(tokenId);
uint256 bobCredits = market.failedTransferCredits(BOB);
assertGt(bobCredits, 0, "Bob should have failed credits");
// withdrawAllFailedCredits changes failedTransferCredits[msg.sender] = 0
// but emits no event for this state change
uint256 attackerBalanceBefore = MALICIOUS.balance;
vm.prank(MALICIOUS);
market.withdrawAllFailedCredits(BOB);
// State was changed but no event emitted
assertEq(market.failedTransferCredits(MALICIOUS), 0, "Credits should be reset");
assertGt(MALICIOUS.balance, attackerBalanceBefore, "Should have received funds");
}

Recommended Mitigation

+ event FailedCreditsWithdrawn(address indexed recipient, uint256 amount);
function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
+ emit FailedCreditsWithdrawn(msg.sender, amount);
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!