Summary
If a token is registered with the same symbol the address will be replaced by the new token address having a matching symbol in the mapping, symbol are not unique.
Vulnerability Details
Here is a test to show case the issue.
function testAddTokenWithSameSymbol() public {
vm.prank(owner);
tokenFactory.deployToken("TEST", type(L1Token).creationCode);
vm.prank(owner);
address tokenAddress2 = tokenFactory.deployToken("TEST", type(L1Token).creationCode);
assertEq(tokenFactory.getTokenAddressFromSymbol("TEST"), tokenAddress2);
}
Impact
High as it makes the getTokenAddressFromSymbol
returning a faulty result as the mapping is corrupted and if this method is used in an other script or contract (for example L1BossBridge) the wrong vault will be created.
Tools Used
forge test
Recommendations
Mitigation 1
If we want to keep the same implementation We could revert to avoid having new token with the same symbol in the mapping
+ error TokenFactory__SymbolExist();
+
function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
+ if (s_tokenToAddress[symbol] != address(0)) revert TokenFactory__SymbolExist();
assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}
s_tokenToAddress[symbol] = addr;
emit TokenDeployed(symbol, addr);
}
Mitigation 2
The symbol is probably not that useful we could only store the address in a mapping and use a boolean to know if the contract have been deploy using the TokenDeployed emitted events
+ mapping(address tokenAddress => bool success) private s_tokenToAddress;
- mapping(string tokenSymbol => address tokenAddress) private s_tokenToAddress;
+ event TokenDeployedFixed(address addr);
- event TokenDeployed(string symbol, address addr);
+ function deployToken(bytes memory contractBytecode) public onlyOwner returns (address addr) {
- function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}
+ s_tokenToAddress[addr] = true;
- s_tokenToAddress[symbol] = addr;
+ emit TokenDeployed(addr);
- emit TokenDeployed(addr);
}
+ function isTokenAddressDeployed(address addr) public view returns (bool success) {
+ return s_tokenToAddress_fixed[addr];
+ }
- function getTokenAddressFromSymbol(string memory symbol) public view returns (address addr) {
- return s_tokenToAddress[symbol];
- }