OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: low
Valid

Integer Overflow in buyOrder() Fee Calculation

Root + Impact

Description

The buyOrder() function is designed to allow users to purchase active sell orders by paying the specified USDC price and receiving the tokens. Under normal operation, the function calculates protocol fees by multiplying the order price by the fee percentage.

The specific issue is that the fee calculation performs unchecked arithmetic multiplication that can overflow when dealing with very large prices, causing legitimate transactions to revert unexpectedly and potentially creating denial-of-service conditions for high-value orders.

This multiplication is done without overflow checks. If order.priceInUSDC is close to type(uint256).max, and FEE is nonzero, the result can exceed uint256.max, causing the transaction to revert unexpectedly.

solidity
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
// ... validation checks ...
order.isActive = false;
uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;// @> Unchecked multiplication can overflow
uint256 sellerReceives = order.priceInUSDC - protocolFee;
// ... token transfers ...
}

Risk

Likelihood:

  • Large institutional orders or high-value token sales can trigger overflow conditions

  • Attackers can deliberately create orders with maximum uint256 values to cause reverts

  • The probability increases as token values and order sizes grow over time


Impact:

  • Transaction reverts prevent legitimate high-value orders from being executed

  • Denial-of-service condition where the contract becomes unusable for large orders

  • Loss of protocol functionality for institutional users or high-value trades

  • Potential economic impact if large orders cannot be processed during critical market conditions

Proof of Concept

function test_integerOverflowOnBuyOrder() public {
uint256 hugeAmount = type(uint256).max; // maximum token amount
uint256 hugePrice = type(uint256).max; // maximum price
// Mint max WETH to Alice
weth.mint(alice, hugeAmount);
// Alice creates an intentionally malicious sell order
vm.startPrank(alice);
weth.approve(address(book), hugeAmount);
uint256 orderId = book.createSellOrder(address(weth), hugeAmount, hugePrice, 1 days);
vm.stopPrank();
// Dan tries to buy the malicious order
vm.startPrank(dan);
usdc.mint(dan, type(uint256).max);
usdc.approve(address(book), type(uint256).max);
vm.expectRevert(); // Overflow expected when computing fee or transfer
book.buyOrder(orderId);
vm.stopPrank();
}
//Test output
[FAIL: panic: arithmetic underflow or overflow (0x11)] test_integerOverflowOnBuyOrder()
The failure (panic 0x11) confirms that the unchecked math is unsafe.

Recommended Mitigation

diff
+ import "@openzeppelin/contracts/utils/math/SafeMath.sol";
+ using SafeMath for uint256;
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
// ... validation checks ...
order.isActive = false;
+ // Check for overflow before multiplication
+ require(order.priceInUSDC <= type(uint256).max / FEE, "Price too large");
- uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;
+ uint256 protocolFee = order.priceInUSDC.mul(FEE).div(PRECISION);
uint256 sellerReceives = order.priceInUSDC - protocolFee;
// ... rest of function
}
Updates

Lead Judging Commences

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

Fee can be bypassed

Protocol Suffers Potential Revenue Leakage due to Precision Loss in Fee Calculation

Support

FAQs

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