Description: The helper getOrderDetailsString does not query the token’s actual symbol(), so custom tokens always show a default or hard-coded abbreviation rather than their on-chain symbol.
Impact: Off-chain UIs and end users may see misleading token names, causing confusion or trading the wrong asset.
Proof of Concept: Add the following contract of custom ERC-20 token:
pragma solidity 0.8.26;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MockERC20 is ERC20 {
uint8 tokenDecimals;
constructor(uint8 _tokenDecimals) ERC20("MockERC20", "MOCK") {
tokenDecimals = _tokenDecimals;
}
function decimals() public view override returns (uint8) {
return tokenDecimals;
}
function mint(address to, uint256 value) public {
uint256 updateDecimals = uint256(tokenDecimals);
_mint(to, (value * 10 ** updateDecimals));
}
}
Include the following test in the TestOrderBook.t.sol file:
import {MockERC20} from "./mocks/MockERC20.sol";
function testOrderDetailsCustomSymbol() public {
MockERC20 customToken = new MockERC20(18);
customToken.mint(alice, 100 ether);
vm.prank(owner);
book.setAllowedSellToken(address(customToken), true);
vm.startPrank(alice);
customToken.approve(address(book), 100 ether);
uint256 orderId = book.createSellOrder(address(customToken), 100 ether, 100e6, 2 days);
vm.stopPrank();
string memory orderDetails = book.getOrderDetailsString(orderId);
console2.log(orderDetails);
string memory tokenSymbol = customToken.symbol();
assertFalse(vm.contains(orderDetails, tokenSymbol));
}
Mitigation:
– Import ERC20 and call symbol() on order.tokenToSell when building human-readable strings.
string memory tokenSymbol = ERC20(order.tokenToSell).symbol();