Root + Impact
Uninitialized Local Variable Causes Empty Token Symbol in Order Details
Description
The getOrderDetailsString() function is designed to return a formatted string containing order details including the token symbol for display purposes.
The function declares a local variable tokenSymbol but never initializes it, causing the function to return an empty string for the token symbol field, breaking the intended functionality.
function getOrderDetailsString(uint256 _orderId) external view returns (string memory) {
Order memory order = orders[_orderId];
string memory tokenSymbol;
string memory status;
if (!order.isActive) {
status = "Cancelled";
} else if (order.isActive && block.timestamp >= order.deadlineTimestamp) {
status = "Expired";
} else if (block.timestamp < order.deadlineTimestamp) {
status = "Active";
}
return string(abi.encodePacked(
"Order ID: ", Strings.toString(_orderId),
", Token: ", tokenSymbol,
", Amount: ", Strings.toString(order.amountToSell),
", Price: ", Strings.toString(order.priceInUSDC),
", Status: ", status,
", Deadline: ", Strings.toString(order.deadlineTimestamp)
));
}
Risk
Likelihood:
Impact:
-
Frontend applications cannot display meaningful token information to users
-
Order details become incomplete and potentially confusing for users trying to identify which token is being traded
-
Integration partners relying on this function will receive malformed data
Proof of Concept
OrderBook orderBook = new OrderBook(owner, usdc, feeRecipient, oracle, admin);
address wethToken = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
orderBook.createSellOrder(wethToken, 1000e18, 100e6, 3600);
string memory details = orderBook.getOrderDetailsString(1);
console.log(details);
Recommended Mitigation
function getOrderDetailsString(uint256 _orderId) external view returns (string memory) {
Order memory order = orders[_orderId];
- string memory tokenSymbol;
+ string memory tokenSymbol = "UNKNOWN";
+
+ // Try to get actual token symbol if possible
+ try IERC20Metadata(order.tokenToSell).symbol() returns (string memory symbol) {
+ if (bytes(symbol).length > 0) {
+ tokenSymbol = symbol;
+ }
+ } catch {
+ // Fallback to truncated address if symbol() fails
+ tokenSymbol = Strings.toHexString(uint160(order.tokenToSell), 20);
+ }
string memory status;
if (!order.isActive) {
status = "Cancelled";
} else if (order.isActive && block.timestamp >= order.deadlineTimestamp) {
status = "Expired";
} else if (block.timestamp < order.deadlineTimestamp) {
status = "Active";
}
return string(abi.encodePacked(
"Order ID: ", Strings.toString(_orderId),
", Token: ", tokenSymbol,
", Amount: ", Strings.toString(order.amountToSell),
", Price: ", Strings.toString(order.priceInUSDC),
", Status: ", status,
", Deadline: ", Strings.toString(order.deadlineTimestamp)
));
}