Bid Beasts

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

Test Suite Bug: Tests Assume First Bid Can Equal Minimum Price

Medium: Tests Assume First Bid Can Equal Minimum Price

Description

  • The tests test_placeFirstBid() and test_placeSubsequentBid_RefundsPrevious() attempt to place first bids at exactly the minimum price.

  • These tests fail because the marketplace contract incorrectly requires first bids to be strictly greater than the minimum price (a known bug documented as L-1 in the contract vulnerabilities).

function test_placeFirstBid() public {
_mintNFT();
_listNFT();
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE}(TOKEN_ID); // @> Fails: contract requires > MIN_PRICE, not >=
// Test expectations that never execute...
}

Risk

Likelihood:

  • Tests fail consistently due to contract bug

  • Affects multiple test cases

Impact:

  • Cannot test normal bidding flow

  • Unable to verify refund mechanisms

  • Test suite appears broken when contract has the actual bug

  • May lead developers to "fix" tests instead of the contract

Proof of Concept

Test execution shows the contract rejects bids at exactly minimum price:

[FAIL: First bid must be > min price] test_placeFirstBid()
├─ [8709] BidBeastsNFTMarket::placeBid{value: 1000000000000000000}(0)
│ └─ ← [Revert] First bid must be > min price // Contract bug: should accept >=

The contract code causing this (line 151 of BidBeastsNFTMarketPlace.sol):

require(msg.value > requiredAmount, "First bid must be > min price"); // Bug: should be >=

Recommended Mitigation

Two options exist:

Option 1: Fix the contract bug (Recommended)
The contract should accept bids >= minimum price. This is tracked as vulnerability L-1 in exploits_formatted.md.

Option 2: Update tests to match current (buggy) behavior
If the contract cannot be changed immediately, update tests to bid above minimum:

function test_placeFirstBid() public {
_mintNFT();
_listNFT();
vm.prank(BIDDER_1);
- market.placeBid{value: MIN_PRICE}(TOKEN_ID);
+ market.placeBid{value: MIN_PRICE + 1 wei}(TOKEN_ID); // Bid above minimum
BidBeastsNFTMarket.Bid memory highestBid = market.getHighestBid(TOKEN_ID);
assertEq(highestBid.bidder, BIDDER_1);
- assertEq(highestBid.amount, MIN_PRICE);
+ assertEq(highestBid.amount, MIN_PRICE + 1 wei);
}
function test_placeSubsequentBid_RefundsPrevious() public {
_mintNFT();
_listNFT();
vm.prank(BIDDER_1);
- market.placeBid{value: MIN_PRICE}(TOKEN_ID);
+ market.placeBid{value: MIN_PRICE + 1 wei}(TOKEN_ID);
uint256 bidder1BalanceBefore = BIDDER_1.balance;
- uint256 secondBidAmount = MIN_PRICE * 120 / 100;
+ uint256 secondBidAmount = (MIN_PRICE + 1 wei) * 120 / 100;
vm.prank(BIDDER_2);
market.placeBid{value: secondBidAmount}(TOKEN_ID);
- assertEq(BIDDER_1.balance, bidder1BalanceBefore + MIN_PRICE, "Bidder 1 was not refunded");
+ assertEq(BIDDER_1.balance, bidder1BalanceBefore + MIN_PRICE + 1 wei, "Bidder 1 was not refunded");
// Rest of test...
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 23 days ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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