OrderBook

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

Loss of protocol fee due to integer truncation when priceInUSDC is low

Root + Impact

Description

  • When a user buys an order, the protocol is expected to take a 3% fee based on priceInUSDC. This fee is deducted from the buyer's payment and added to totalFees.

  • The fee is calculated using integer division:

    uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;

    This formula rounds down any value below 1 to 0 . Thus, if priceInUSDC < 34, protocolFee will be zero, and no fee is collected.

    This allows users to bypass fees entirely by setting very low-priced orders, leading to lost protocol revenue and inconsistent behavior.

uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;

Risk

Likelihood: Medium

  • Common in low-value trades or intentionally used by attackers but not much likely becuse of the limited potential of gain

Impact: Low

  • Fee is entirely skipped however Impact is low because only very small orders can executed without fees.

  • However, an attacker can dissect a large order into multiple micro-orders to avoid protocol fees. The feasibility and the final impact would depend on gas fees.

  • Protocol earns zero revenue from such trades.

Proof of Concept

This PoC demonstrates that when an order is created with a priceInUSDC below 33, the protocol fee calculation results in zero due to integer truncation. As a result, no fee is collected when the order is filled, allowing users to bypass fees entirely on low-value trades. The test verifies this by asserting that the totalFees remain unchanged before and after the purchase.

function test_buy_Without_fees() public {
vm.startPrank(alice);
wbtc.approve(address(book), 2e8);
uint256 aliceId = book.createSellOrder(address(wbtc), 2e8, 33, 2 days);
vm.stopPrank();
uint _tempTotalFees=book.totalFees();
vm.startPrank(dan);
usdc.approve(address(book), 200_000e6);
book.buyOrder(aliceId);
vm.stopPrank();
assertEq(_tempTotalFees, book.totalFees());
}

Recommended Mitigation

To prevent fee bypass via small priceInUSDC values, the contract can check if fee is nonzero inside createSellOrders and amendOrders. This ensures that the 3% fee calculation always results in a non-zero value.Since FEE is constant we can also define a constant variable 34.

// createSellOrder()
+ if (_priceInUSDC < 34) revert InvalidPrice(); // enforce minimum price
// amendOrders
+ if (_newpPrceInUSDC < 34) revert InvalidPrice(); // enforce minimum price
Updates

Lead Judging Commences

yeahchibyke Lead Judge
10 days ago
yeahchibyke Lead Judge 7 days 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.