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

CREATE is not available in the zkSync Era.

Summary

In the current code devs are using CREATE but in zkSync Era, CREATE for arbitrary bytecode is not available, so a revert occurs in the deployToken process.

Vulnerability Details

According to the contest README which you can see here and i've listed it below also, the project can be deployed in zkSync Era

Chain(s) to deploy contracts to:
Ethereum Mainnet:
L1BossBridge.sol
L1Token.sol
L1Vault.sol
TokenFactory.sol
ZKSync Era:
TokenFactory.sol
Tokens:
L1Token.sol (And copies, with different names & initial supplies)

The zkSync Era docs explain how it differs from Ethereum.

The description of CREATE and CREATE2 (https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2) states that Create cannot be used for arbitrary code unknown to the compiler.

According to zkSync The following code will not function correctly because the compiler is not aware of the bytecode beforehand:

function myFactory(bytes memory bytecode) public {
assembly {
addr := create(0, add(bytecode, 0x20), mload(bytecode))
}
}

Now if we look at the code of Boss Bridge here we can see that Boss Bridge is using exactly similar code which is as below

function deployToken(string memory symbol, bytes memory contractBytecode) public onlyOwner returns (address addr) {
assembly {
addr := create(0, add(contractBytecode, 0x20), mload(contractBytecode))
}

Impact

Protocol will not work on zkSync

Tools Used

Manual Review

Recommendations

Follow the instructions that are stated in zksync docs here

To guarantee that create/create2 functions operate correctly, the compiler must be aware of the bytecode of the deployed contract in advance. The compiler interprets the calldata arguments as incomplete input for ContractDeployer, as the remaining part is filled in by the compiler internally. The Yul datasize and dataoffset instructions have been adjusted to return the constant size and bytecode hash rather than the bytecode itself

The code below should work as expected:

MyContract a = new MyContract();
MyContract a = new MyContract{salt: ...}();

In addition, the subsequent code should also work, but it must be explicitly tested to ensure its intended functionality:

bytes memory bytecode = type(MyContract).creationCode;
assembly {
addr := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
Updates

Lead Judging Commences

0xnevi Lead Judge
almost 2 years ago
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.