OrderBook

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

Lack of Token Decimal Normalization May Lead to Mispriced Orders and Incorrect Valuations

Allowing ERC20 tokens with varying decimals without normalization leads to mispriced orders and silent value loss

Description

The protocol supports multiple ERC20 tokens (wETH, wBTC, wSOL, USDC) — all of which have different decimals (e.g., USDC: 6, WETH/WSOL: 18, WBTC: 8). However, the system does not normalize token decimals during order creation, pricing, or transfers.

This can cause issues where:

  • A seller mistakenly prices a wBTC order as if it had 18 decimals

  • The protocol treats all tokens equally in terms of units without adjustment

IERC20(_tokenToSell).safeTransferFrom(msg.sender, address(this), _amountToSell); //<@ No check for token decimals; assumes amount is in correct units
orders[orderId] = Order({
id: orderId,
seller: msg.sender,
tokenToSell: _tokenToSell,
amountToSell: _amountToSell, //<@ Value stored as raw token amount, but no standardization across decimals
priceInUSDC: _priceInUSDC, //<@ Priced in USDC (6 decimals) but no logic ties price to token decimals
...
});

Risk

Likelihood:

  • Many tokens (wBTC, wETH, USDC) have different decimal standards

  • The protocol assumes that all amounts inputted are already scaled properly

  • Without explicit normalization, users can easily misprice or misinterpret values

  • Mispriced orders can be exploited by bots or sniped instantly

Impact:

  • Buyers may get tokens at unintended discounts

  • Sellers may list orders for less than intended value

  • Order book integrity suffers

  • Potential for griefing, bot sniping, and liquidity drain

  • Can cause silent financial loss with no contract-level errors

Proof of Concept

Decimals can be mistaken

// Seller thinks in 18 decimals, but wBTC has 8 decimals
wbtc.approve(address(book), 2e18); // mistake — 2e18 = 20 billion wBTC
book.createSellOrder(address(wbtc), 2e18, 5000e6, 2 days);
// Seller intended to sell 2 WBTC, but instead listed 20,000,000 WBTC
// A buyer can now buy this order for only 5000 USDC (mispricing)

Recommended Mitigation

+ function _normalizeAmount(address token, uint256 amount) internal view returns (uint256 normalized) {
+ uint8 decimals = IERC20Metadata(token).decimals();
+ return amount / (10 ** decimals); // or adjust to consistent base (e.g., 18)
+}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 4 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.