OrderBook

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

Improper Token Whitelisting Allows Fee-on-Transfer Tokens

Description

The buyOrder function assumes the full amount of tokens specified in the order (order.amountToSell) will be transferred to the buyer (https://github.com/CodeHawks-Contests/2025-07-orderbook/blob/fdef247b2f2bd7c0f9c19310406c8e072d9ffda4/src/OrderBook.sol#L207). This is true only if the token implements a standard ERC-20 transfer behavior, i.e., it does not apply a transfer fee. However, tokens with fee-on-transfer mechanics (such as SafeMoon, Reflect Finance, etc.) will deduct a portion of the tokens during transfer, causing the buyer to receive less than the promised amount.

The setAllowedSellToken function enables the owner to allow arbitrary tokens for selling without verifying whether they are fee-on-transfer tokens. As a result, the owner may allow such a token, breaking trade integrity.

function buyOrder(uint256 _orderId) public {
...
@> IERC20(order.tokenToSell).safeTransfer(msg.sender, order.amountToSell);
...
}
function setAllowedSellToken(address _token, bool _isAllowed) external onlyOwner {
...
@> allowedSellToken[_token] = _isAllowed;
...
}

Risk

Likelihood:MEDIUM

  • this will occur Whenever the owner whitelists a token without knowing it applies transfer fees

-When a user places an order using a whitelisted fee-on-transfer token

Impact:

-Buyers will receive fewer tokens than expected, resulting in silent value loss

-Protocol reputation is damaged due to inconsistent trade outcomes and user distrust

Proof of Concept

-Admin whitelists a fee-on-transfer token
contract.setAllowedSellToken(address(feeToken), true);
- Seller creates an order to sell 100 feeToken for 100 USDC
contract.createSellOrder(feeToken, 100e18, 100e6, ...);
- Buyer buys the order
feeToken takes 10% fee -> only 90 tokens sent to buyer

-Buyer receives only 90 tokens after paying full price, silently losing value

Recommended Mitigation

- allowedSellToken[_token] = _isAllowed;
+ if (_isAllowed) {
+ require(!isFeeOnTransferToken(_token), "Fee-on-transfer tokens not allowed");
+ }
+ allowedSellToken[_token] = _isAllowed;

You can implement isFeeOnTransferToken off-chain or use a static whitelist of trusted, well-known non–fee-on-transfer tokens like WETH, WBTC, USDC e.t.c

Updates

Lead Judging Commences

yeahchibyke Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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