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

```TokenFactory::DeployToken()``` address no 100% predictable on L2

Summary

The TokenFactory::DeployToken() function uses CREATE instead of CREATE2 for deploying the token. The TokenFactory contract is deployed on Ethereum and also on ZKSync Era (Layer 2), as specified in the @natspec comment and in the README file. Consequently, the address of the deployed token on L2 isn't 100% predictable due to the use of CREATE instead of CREATE2.

Vulnerability Details

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

In the ZK Rollups (like ZKsync Era), in the context of "off-chain contract creation", it is necessary to set up the contracts that will be used in the rollup off-chain. This includes the contracts that will hold the state of the rollup, handle transactions, and generate zk-SNARKs.

Parties involved in a ZK Rollup can agree on the address where a contract would be deployed, if needed, without actually deploying the contract on-chain. They can then perform operations as though the contract was deployed at that address.

When the rollup operator submits a batch of transactions to the Ethereum network, they include the address of the contract that would handle those transactions. Because the address is predictable the Ethereum network can verify that the contract at that address would indeed handle the transactions correctly.

This allows the transactions to be processed without the need for the contract to be actually deployed on-chain. Using CREATE instead of CREATE2 doesn't guarantee the predictable of the address and the correct use of the L2.

Using CREATE for creating a smart contract:

new_address = hash(sender, nonce)

the address for the new contract is computed as a function of the sender’s own address and a nonce. So it is possible to predict the address where the next created contract will be deployed, but only if no other transactions happen before then - an undesirable property for counterfactual systems

Using CREATE2 for creating a smart contract:
new_address = hash(0xFF, sender, salt, bytecode)

the resulting address is independent of future events. Regardless of what may happen on the blockchain, it will always be possible to deploy the contract at the precomputed address.

Tools Used

Manual review.

Recommendations

Use CREATE2 instead of CREATE

- 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);
- }
+ function deployToken(
+ string memory symbol,
+ bytes memory contractBytecode,
+ string memory saltString
+ )
+ public
+ onlyOwner
+ returns (address addr)
+ {
+ bytes32 salt = keccak256(abi.encodePacked(saltString));
+ assembly {
+ let size := mload(contractBytecode)
+ let data := add(contractBytecode, 0x20)
+ addr := create2(0, data, size, salt)
+ }
+ require(addr != address(0), "Token deployment failed");
+ s_tokenToAddress[symbol] = addr;
+ emit TokenDeployed(symbol, addr);
+ }
Updates

Lead Judging Commences

0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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