Summary
The TokenFactory::DeployToken()
function, using the L1Token
contractbytecode
, consistently deploys tokens with identical name, symbol, and totalSupply values, as these parameters are hardcoded in the L1Token
contract. Essentially, the DeployToken()
can only deploy a singular type of token.
Vulnerability Details
@> uint256 private constant INITIAL_SUPPLY = 1_000_000;
@> constructor() ERC20("BossBridgeToken", "BBT") {
_mint(msg.sender, INITIAL_SUPPLY * 10 ** decimals());
}
@> function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}
s_tokenToAddress[symbol] = addr;
emit TokenDeployed(symbol, addr);
}
Impact
function testDeployedTokensHaveSameNameAndSymbol() public {
vm.prank(owner);
address tokenAddress_1 = tokenFactory.deployToken("FIRST TOKEN", type(L1Token).creationCode);
vm.prank(owner);
address tokenAddress_2 = tokenFactory.deployToken("SECOND TOKEN", type(L1Token).creationCode);
assertEq(
keccak256(abi.encodePacked(L1Token(tokenAddress_1).name())),
keccak256(abi.encodePacked(L1Token(tokenAddress_2).name()))
);
assertEq(
keccak256(abi.encodePacked(L1Token(tokenAddress_1).symbol())),
keccak256(abi.encodePacked(L1Token(tokenAddress_2).symbol()))
);
assertEq(
keccak256(abi.encodePacked(L1Token(tokenAddress_1).totalSupply())),
keccak256(abi.encodePacked(L1Token(tokenAddress_2).totalSupply()))
);
}
Tools Used
Manual review.
Recommendations
Pass the name, the symbol and the total supply as parameters in the constructors.
contract L1Token is ERC20 {
- uint256 private constant INITIAL_SUPPLY = 1_000_000;
- constructor() ERC20("BossBridgeToken", "BBT") {
+ constructor(string memory name, string memory symbol, uint256 totalSupply) ERC20(name, symbol) {
_mint(msg.sender, totalSupply * 10 ** decimals());
}
}