Normal behavior: Each new bid must increase the previous highest bid by at least the configured minimum increment percentage (here S_MIN_BID_INCREMENT_PERCENTAGE = 5). The expected calculation is “new required = previous * (100 + increment) / 100” so that bids always increase by at least 5%.
Issue: The implementation computes the required next bid as (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE). Because Solidity does integer division that truncates toward zero, performing division before multiplication loses precision. That truncation results in a required bid that can be smaller than the mathematically correct required amount. An adversary can place a bid that is lower than the intended minimum increment and still be accepted.
Likelihood:
Many real bids are not exact multiples of 100; as soon as previousBidAmount is not divisible by 100 the expression previousBidAmount / 100 truncates fractional wei portions. This truncation always occurs whenever previousBidAmount % 100 != 0.
Auction minimums (e.g., seller minPrice) do not eliminate this case — typical min prices (even 0.01 ether or 1 ether) can produce non-divisible numbers after user-added wei (user may bid with arbitrary wei granularity).
Impact:
Bidders can outbid the previous bid with an amount smaller than the intended 5% increment and still become highest bidder. This lets attackers slightly undercut required increments and save ETH on each outbid.
Over many auctions or high volume bidding this allows marginal economic advantage and undermines the integrity of the minimum increment rule. It also complicates off-chain analytics that assume the increment is enforced exactly.
In extreme, if other controls were smaller (e.g., if S_MIN_NFT_PRICE could be very small), the same bug could allow accepting trivially small bids; here it’s a moderate degrading of enforcement .
The following Foundry-style test demonstrates the issue. It places a first bid with a value that is not divisible by 100 (previousBid = MIN_PRICE + 1 wei), computes the required next bid according to the contract's buggy formula, and shows the contract accepts that smaller-than-mathematically-correct bid.
Result: The marketplace accepts buggyRequired even though the correct required amount is correctRequired (> buggyRequired). The difference delta is the amount by which the enforced minimum is violated (often small — a few wei).
Compute the required next bid by multiplying first, then dividing to avoid integer truncation loss.
Optionally, to be stricter and always round up so the bidder must exceed the exact percentage (i.e., no rounding benefit to bidder), compute with rounding-up for the increment.
Minimal safe fix (multiply first):
Integer division in requiredAmount truncates fractions, allowing bids slightly lower than intended.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.