Beginner FriendlyFoundryBridge
100 EXP
View results
Submission Details
Severity: high
Valid

The `TokenFactory::deployToken()` method will not work on ZKSync Era

Summary

The TokenFactory::deployToken() method deploys the token contract using inline assembly with CREATE opcode. This is not supported on ZKSync Era, where the contract is supposed to be deployed.

Vulnerability Details

The TokenFactory::deployToken() deployes the token with the following inline assembly block:

assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}

The ZKSync Era documentation states:

To guarantee that create/create2 functions operate correctly, the compiler must be aware of the bytecode of the deployed contract in advance.

In the TokenFactory contract the compiler is not aware of the bytecode of the deployed contract in advance, as the bytecode gets passed as an argument to deployToken() function during the runtime. In fact, the inline assembly block from the deployToken() method is almost identical to the one provided in the ZKSync Era documentation as an example of code that will not work.

Impact

TokenFactory contract will be broken on the ZKSync Era chain.

Tools Used

Manual review, Patrick's auditing course curriculum

Recommendations

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
+import {L1Token} from "./L1Token.sol";
/*
* @title TokenFactory
* @dev Allows the owner to deploy new ERC20 contracts
* @dev This contract will be deployed on both an L1 & an L2
*/
contract TokenFactory is Ownable {
mapping(string tokenSymbol => address tokenAddress) private s_tokenToAddress;
event TokenDeployed(string symbol, address addr);
constructor() Ownable(msg.sender) { }
/*
* @dev Deploys a new ERC20 contract
* @param symbol The symbol of the new token
* @param contractBytecode The bytecode of the new token
*/
- function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
+ function deployToken(string memory symbol) public onlyOwner returns (address addr) {
- assembly {
- addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
- }
+ addr = address(new L1Token());
s_tokenToAddress[symbol] = addr;
emit TokenDeployed(symbol, addr);
}
function getTokenAddressFromSymbol(string memory symbol) public view returns (address addr) {
return s_tokenToAddress[symbol];
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

deployToken(): zksync compatibility issues

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.