OrderBook

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

`OrderBook::getOrderDetailsString` Fails to Display Symbol for Newly Allowed Tokens

Root + Impact

Description

  • When calling OrderBook::getOrderDetailsString, the function will display the tokenSymbol only for tokens hardcoded in the constructor (iWETH, iWBTC, iWSOL).

  • If a new token is later added via OrderBook::setAllowedSellToken, its symbol will not be displayed in the order details string, leading to inconsistent or incomplete UI data for those orders.

function getOrderDetailsString(uint256 _orderId) public view returns (string memory details) {
Order storage order = orders[_orderId];
if (order.seller == address(0)) revert OrderNotFound(); // Check if order exists
@> 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";
}
}

Risk

LowSeverity: Low

Likelihood: Medium

Impact: Low

Likelihood:

  • Reason 1
    The issue will occur any time a new ERC20 token is added via OrderBook::setAllowedSellToken.

Impact:

  • Impact 1
    Orders created with newly added tokens will have missing or blank token symbols in the returned order details string.

  • Impact 2
    This can affect frontends or UIs that display token data to users, leading to confusion or reduced trust.

Proof of Concept

Note: MockCoolToken is a standard ERC20-compatible mock with a mint() function for testing (similar to the other mock tokens).

  1. User creates a sell order with a pre-approved token (e.g., wBTC) using OrderBook::createSellOrder, and retrieves the order details using OrderBook::getOrderDetailsString. The returned string includes the token symbol (e.g., wBTC).

  2. The contract owner allows a new token (coolToken) via setAllowedSellToken(address(coolToken), true).

  3. A new user is minted some coolToken, approves the OrderBook, and creates a sell order with it.

  4. The user then calls OrderBook::getOrderDetailsString for their order.

  5. The returned string is missing the token symbol because OrderBook::getOrderDetailsString only checks for hardcoded token addresses (iWETH, iWBTC, iWSOL), and does not dynamically fetch the symbol from the ERC20 token interface.

//forge test --mt testGetOrderDetailsString -vvvv
function testGetOrderDetailsString() public {
// existing token - token symbol will be displayed
vm.startPrank(alice);
wbtc.approve(address(book), 2e8);
uint256 aliceId = book.createSellOrder(address(wbtc), 2e8, 180_000e6, 2 days);
vm.stopPrank();
string memory orderDetailsAlice = book.getOrderDetailsString(aliceId);
console2.log(orderDetailsAlice); ✅ contains "wBTC"
//add a new token and display the absence of a token symbol
vm.prank(owner);
book.setAllowedSellToken(address(coolToken), true);
address ana = makeAddr("ana");
coolToken.mint(ana, 2);
vm.startPrank(ana);
coolToken.approve(address(book), 2e18);
uint256 anaId = book.createSellOrder(address(coolToken), 2e18, 100e6, 2 days);
string memory orderDetailsAna = book.getOrderDetailsString(anaId);
console2.log(orderDetailsAna); ❌ token symbol is missing
}

Recommended Mitigation

// Add this import at the top
+import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
// Add this state variable near other mappings
+mapping(address => string) public tokenSymbols;
function setAllowedSellToken(address _token, bool _isAllowed) external onlyOwner {
allowedSellToken[_token] = _isAllowed;
+ if (_isAllowed) {
+ string memory symbol = "";
+ try IERC20Metadata(_token).symbol() returns (string memory sym) {
+ symbol = sym;
+ } catch {
+ symbol = "UNKNOWN";
+ }
+ tokenSymbols[_token] = symbol;
+ } else {
+ delete tokenSymbols[_token];
+ }
emit AllowedSellTokenUpdated(_token, _isAllowed);
}
Updates

Lead Judging Commences

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