OrderBook

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

Missing Token Symbol for Dynamically Allowed Tokens in getOrderDetailsString Output

Root + Impact

Description

  • Under normal behavior, the getOrderDetailsString(uint256 _orderId) function provides a human-readable summary of an order, including the token being sold, its amount, price, deadline, and status.

  • However, the implementation only supports symbol display for a hardcoded list of core tokens (wETH, wBTC, wSOL). Tokens added later via setAllowedSellToken() are not handled. As a result, orders using newly allowed tokens display an empty or missing token symbol, reducing off-chain readability and user clarity.

// Root cause in the codebase with @> marks to highlight the relevant section
// Inside getOrderDetailsString
string memory tokenSymbol;
if (order.tokenToSell == address(iWETH)) {
tokenSymbol = "wETH";
} else if (order.tokenToSell == address(iWBTC)) {
tokenSymbol = "wBTC";
} else if (order.tokenToSell == address(iWSOL)) {
tokenSymbol = "wSOL";
}
@> // No fallback to handle other allowed ERC20 tokens

Risk

Likelihood: Low

  • A protocol owner must add a new ERC20 token via setAllowedSellToken.

  • A user must create an order with that token and query getOrderDetailsString.

Impact: Low

  • Token symbol will be missing in the output string.

  • This affects only off-chain UX (e.g., logs, frontends using this string).

  • Does not impact order creation, execution, or funds.

Proof of Concept

The getOrderDetailsString() function only recognizes a hardcoded list of core tokens (wETH, wBTC, wSOL) and assigns their symbols manually.
When a new ERC20 token is allowed via setAllowedSellToken(), any orders created with it will not display a token symbol in the order details string — leading to incomplete or confusing output.

// A mock ERC20 token (testToken) with symbol "mwtestToken" and 18 decimals was deployed for testing.
function test_GetOrderDetailsAfterAddingNewSellToken() public {
vm.startPrank(owner);
book.setAllowedSellToken(address(testToken), true);
vm.stopPrank();
vm.startPrank(alice);
testToken.approve(address(book), 1000 ether);
uint256 orderId = book.createSellOrder(address(testToken), 1000 ether, 1000e6, 2 days);
vm.stopPrank();
// Expect output to be missing the token name
console2.log(book.getOrderDetailsString(orderId));
}

Recommended Mitigation

Add a fallback that uses IERC20Metadata(order.tokenToSell).symbol() to fetch the token symbol dynamically.
Wrap it in a try/catch block in case the token doesn't implement symbol() (or fails for any reason), and fallback to "Unknown" if needed.

This makes the UI/debug output complete for both core and custom tokens.

- remove this code
+ add this code
+ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
// inside function getOrderDetailsString
- }
+ } else {
+ try IERC20Metadata(order.tokenToSell).symbol() returns (string memory sym) {
+ tokenSymbol = sym;
+ } catch {
+ tokenSymbol = "Unknown";
+ }
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 5 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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