Skip to content

Commit

Permalink
fix: update CREATE assembly restrictions (#305)
Browse files Browse the repository at this point in the history
# Description

Updates restrictions on using `create`/`create2` in assembly blocks.
In zksolc v1.5.9, it has been made a hard error, but it's not the final
decision yet.
There is a chance that we'll make a it a warning to allow smooth
compilation of OZ and ForceStd with Foundry.

## Linked Issues

matter-labs/era-compiler-solidity#239
  • Loading branch information
hedgar2017 authored Jan 20, 2025
1 parent 8305058 commit 5373fad
Showing 1 changed file with 13 additions and 9 deletions.
22 changes: 13 additions & 9 deletions content/20.zksync-protocol/70.differences/10.evm-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,30 @@ contract in advance. The compiler interprets the calldata arguments as incomplet
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:
The code below always works as expected:

```solidity
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:
However, using `create`/`create2` in assembly blocks is unsafe, because the compiler will most likely silently produce broken bytecode,
leading to security vulnerabilities and unreachable code. Some common libraries such as `openzeppelin-contracts` or `forge-std`
may include the following pattern:

```solidity
/// The `bytecode` is not bytecode here, but a header passed to `ContractDeployer`.
bytes memory bytecode = type(MyContract).creationCode;
assembly {
addr := create2(0, add(bytecode, 32), mload(bytecode), salt)
addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}
```

The following code will not function correctly because the compiler is not aware of the bytecode beforehand:
This specific pattern has been tested and must work correctly, but any variation of it will fail due to unsatisfied EraVM assumptions.
Newer versions of `zksolc` do not recommend using `create`/`create2` in assembly and produce a warning. The warning could not be made
an error as common libraries that use this feature cannot be easily changed by smart contract developers.

For instance, the following code will never work because ZKsync Era contracts cannot be deployed using any kind of bytecode:

```solidity
function myFactory(bytes memory bytecode) public {
Expand All @@ -40,11 +47,8 @@ function myFactory(bytes memory bytecode) public {
}
```

Unfortunately, it's impossible to differentiate between the above cases during compile-time. As a result, we strongly
recommend including tests for any factory that deploys child contracts using `type(T).creationCode`.

Since the deploy and runtime code is merged together on ZKsync Era, we do not support `type(T).runtimeCode` and it
always produces a compile-time error.
Since deploy and runtime code is indistinguishable on ZKsync Era, we do not support `type(T).runtimeCode`, and the compiler will
always produce an error for these constants.

### Address derivation

Expand Down

0 comments on commit 5373fad

Please sign in to comment.