diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a16c0f82e..adb59f8e4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -21,6 +21,7 @@ - [Overview](./zksync-specifics/README.md) - [Execution Overview](./zksync-specifics/execution-overview.md) - [Compilation Overview](./zksync-specifics/compilation-overview.md) +- [Configuration Overview](./zksync-specifics/configuration-overview.md) - [Limitations](./zksync-specifics/limitations/README.md) - [General](./zksync-specifics/limitations/general.md) - [Compilation](./zksync-specifics/limitations/compilation.md) @@ -28,10 +29,13 @@ - [Events](./zksync-specifics/limitations/events.md) - [Traces](./zksync-specifics/limitations/traces.md) - [Cheatcodes](./zksync-specifics/limitations/cheatcodes.md) +- [Forge-ZKSync Standard Library](./zksync-specifics/forge-zksync-std.md) - [Additional Cheatcodes](./zksync-specifics/cheatcodes/README.md) - - [zkVm](./zksync-specifics/cheatcodes/zkvm.md) + - [zkRegisterContract](./zksync-specifics/cheatcodes/zk-register-contract.md) + - [zkVm](./zksync-specifics/cheatcodes/zk-vm.md) + - [zkVmSkip](./zksync-specifics/cheatcodes/zk-vm-skip.md) -# Supported Commands Overview +# Supported Commands - [Command List](./supported-commands/README.md) # Forge Overview @@ -40,7 +44,8 @@ - [Tests](./forge/tests.md) - [Writing Tests](./forge/writing-tests.md) - [Cheatcodes](./forge/cheatcodes.md) - - [Forge Standard Library Overview](./forge/forge-std.md) + - [Forge Standard Library](./forge/forge-std.md) + - [Forge ZKsync Standard Library](./forge/forge-zksync-std.md) - [Understanding Traces](./forge/traces.md) - [Fork Testing](./forge/fork-testing.md) - [Replaying Failures](./forge/replay-testing.md) @@ -58,7 +63,7 @@ - [Gas Tracking](./forge/gas-tracking.md) - [Gas Reports](./forge/gas-reports.md) - [Gas Snapshots](./forge/gas-snapshots.md) -- [Debugger](./forge/debugger.md) + # Cast Overview @@ -69,17 +74,15 @@ - [Anvil](./anvil/README.md) - [Chisel](./chisel/README.md) - + + + + + - + - [References](./reference/README.md) - - [CLI Reference](./reference/cli/README.md) - - + + + + + + + + --> + + diff --git a/src/forge/forge-zksync-std.md b/src/forge/forge-zksync-std.md new file mode 100644 index 000000000..131923e04 --- /dev/null +++ b/src/forge/forge-zksync-std.md @@ -0,0 +1,5 @@ +## Forge ZKsync Standard Library Overview + +Forge ZKsync Standard Library is an addition to the [Forge Standard Library](./forge-std.md) that adds further collection of helpful contracts that make writing tests easier, faster, and more user-friendly for the ZKsync ecosystem. + +Refer to this [section](../zksync-specifics/forge-zksync-std.md) for more details. \ No newline at end of file diff --git a/src/reference/config/README.md b/src/reference/config/README.md index 214e14f6d..9bf44a832 100644 --- a/src/reference/config/README.md +++ b/src/reference/config/README.md @@ -4,7 +4,7 @@ - [Project](./project.md) - [Solidity Compiler](./solidity-compiler.md) - [Testing](./testing.md) -- [In-line test configuration](./inline-test-config.md) + diff --git a/src/reference/config/project.md b/src/reference/config/project.md index 27988545c..e7b821d63 100644 --- a/src/reference/config/project.md +++ b/src/reference/config/project.md @@ -72,3 +72,104 @@ The path to the broadcast transaction logs, relative to the root of the project. - Environment: `FOUNDRY_FORCE` or `DAPP_FORCE` Whether or not to perform a clean build, discarding the cache. + + +### ZKsync Settings + +Additional zksync settings can be defined on the profile of choice by specifying `profile..zksync` section. + +For example to define the settings on `profile.default`: + +```toml +[profile.default] +# ...Normal foundry settings... + +[profile.default.zksync] +# ...ZKSync specific settings... +``` + +##### `compile` + +- Type: boolean +- Default: false + +Compile contracts for zkEVM. + +##### `startup` + +- Type: boolean +- Default: true (will only have effect if `compile = true`) + +Requires `compile = true` to have an effect. +Enable ZKsync context on startup. This applies to tests, scripts, and any other commands that need to switch immediately to zkEVM on startup. + +##### `zksolc` + +- Type: string +- Default: + +The zksolc version to use for compilation. + +##### `solc_path` + +- Type: string +- Default: + +The `solc` path to use during `zksolc` compilation. + +##### `bytecode_hash` + +- Type: boolean +- Default: "none" + +Whether to include the metadata hash for zksolc compiled bytecode. + +##### `fallback_oz` + +- Type: boolean +- Default: false + +Allow compiler to recompile using `optimizer_mode = 'z'` if contracts won't fit in the EraVM bytecode size limitations. + +##### `enable_eravm_extensions` + +- Type: boolean +- Default: false + +Enable EraVM extensions (e.g. system-mode). This allows compilation of ZKsync-specific simulations. + +##### `force_evmla` + +- Type: boolean +- Default: false + +Force compilation via EVMLA instead of Yul codegen pipeline. + +##### `avoid_contracts` + +- Type: array of strings +- Default: [] + +List of glob patterns to avoid compiling with zksolc. + +##### `optimizer` + +- Type: boolean +- Default: true + +Enable optimizer on zksolc. + +##### `optimizer_mode` + +- Type: string +- Default: '3' + +The zksolc optimizer mode (0 | 1 | 2 | 3 | s | z). + +##### `optimizer_details` + +- Type: object +- Default: {} + +Allows specifying additional zksolc [Optimizer Details](https://github.com/matter-labs/era-compiler-solidity/blob/main/era-compiler-solidity/src/solc/standard_json/input/settings/optimizer/details.rs#L10). + diff --git a/src/reference/config/testing.md b/src/reference/config/testing.md index c9baa4fe8..682869792 100644 --- a/src/reference/config/testing.md +++ b/src/reference/config/testing.md @@ -386,6 +386,13 @@ The flag indicating whether to include push bytes values. The flag indicates whether to display console logs in fuzz tests or not. Note that in order to enable displaying console logs, you'll need to set `show_logs = true` and then use `forge test -vv` or set `verbosity >= 2`. +##### `no_zksync_reserved_addresses` + +- Type: boolean +- Default: false + +Avoid generating [reserved](../../zksync-specifics/limitations/general.md#reserved-address-range) ZKsync addresses within the fuzzer. This avoids having to use `vm.assume(addr > 65535)` during fuzzing that can ignore too many inputs causing `max_test_rejects` to trigger. + ### Invariant @@ -473,3 +480,11 @@ The flag indicating whether to include push bytes values. See also [fuzz.include - Environment: `FOUNDRY_INVARIANT_SHRINK_RUN_LIMIT` The maximum number of attempts to shrink a failed the sequence. Shrink process is disabled if set to 0. + + +##### `no_zksync_reserved_addresses` + +- Type: boolean +- Default: false + +Avoid generating [reserved](../../zksync-specifics/limitations/general.md#reserved-address-range) ZKsync addresses within the invariant test. This avoids having to use `vm.assume(addr > 65535)` during invariant testing that can ignore too many inputs causing `max_test_rejects` to trigger. diff --git a/src/supported-commands/README.md b/src/supported-commands/README.md index 65b9516b2..15c72c601 100644 --- a/src/supported-commands/README.md +++ b/src/supported-commands/README.md @@ -1,4 +1,4 @@ -## Foundry-ZKSync supported commands +## Foundry-ZKSync Supported Commands This is a comprehensive review of all the Foundry commands actually supported in the actual stage of development. diff --git a/src/zksync-specifics/cheatcodes/README.md b/src/zksync-specifics/cheatcodes/README.md index d42ff4939..23671c9f9 100644 --- a/src/zksync-specifics/cheatcodes/README.md +++ b/src/zksync-specifics/cheatcodes/README.md @@ -8,11 +8,28 @@ In addition to the existing [Cheatcodes](../../cheatcodes/README.md), there are This is the extended Solidity interface for all ZKsync specific cheatcodes present in Forge. ```solidity -interface CheatCodes { - /// Existing forge cheatcodes - ... +interface CheatCodesExt { + /// Registers bytecodes for ZK-VM for transact/call and create instructions. + function zkRegisterContract( + string calldata name, + bytes32 evmBytecodeHash, + bytes calldata evmDeployedBytecode, + bytes calldata evmBytecode, + bytes32 zkBytecodeHash, + bytes calldata zkDeployedBytecode + ) external pure; /// Enables/Disables use ZK-VM usage for transact/call and create instructions. function zkVm(bool enable) external pure; + + /// When running in zkEVM context, skips the next CREATE or CALL, executing it on the EVM instead. + /// All `CREATE`s executed within this skip, will automatically have `CALL`s to their target addresses + /// executed in the EVM, and need not be marked with this cheatcode at every usage location. + function zkVmSkip() external pure; } ``` + + +### Usage + +Refer to the [forge-zksync-std](../forge-zksync-std.md) section on how to access these cheatcodes in your tests. \ No newline at end of file diff --git a/src/zksync-specifics/cheatcodes/zk-register-contract.md b/src/zksync-specifics/cheatcodes/zk-register-contract.md new file mode 100644 index 000000000..ac16c7690 --- /dev/null +++ b/src/zksync-specifics/cheatcodes/zk-register-contract.md @@ -0,0 +1,44 @@ +## `zkRegisterContract` + +### Signature + +```solidity +function zkRegisterContract( + string calldata name, + bytes32 evmBytecodeHash, + bytes calldata evmDeployedBytecode, + bytes calldata evmBytecode, + bytes32 zkBytecodeHash, + bytes calldata zkDeployedBytecode +) external pure; +``` + +### Description + +Registers bytecodes for ZK-VM for transact/call and create instructions. + +This is especially useful if there are certain contracts already deployed on-chain (EVM or ZKsync). Since we compile with both `solc` and `zksolc` as defined in the [Dual Compilation](../compilation-overview.md#dual-compilation) section, if there's an already existing EVM bytecode that must be translated into its zkEVM counterpart, we need to define it with this cheatcode. + +Such an operation must be carried out separately where the source of the pre-deployed contract must be obtained and compiled with zksolc. The artifact json will contain the `zkBytecodeHash` and `zkDeployedBytecode` parameters. The process is similar for obtaining EVM parameters with `solc` - `evmBytecodeHash`, `evmDeployedBytecode`, `evmBytecode`. + +The `name` parameter must be unique if possible and not clash with locally existing contracts. + +### Examples + +```solidity +// LeetContract is pre-deployed on EVM on address(65536) + +/// interface ILeetContract { +/// function leet() public { +/// // do something +/// } +/// } + +vmExt.zkVm(true); +ILeetContract(address(65536)).leet(); // fails, as the contract was not found locally so not migrated to zkEVM + + +vmExt.zkRegisterContract("LeetContract", 0x111.., 0x222.., 0x333..., 0x444..., 0x555...); // register LeetContract for migration +vmExt.zkVm(true); +ILeetContract(address(65536)).leet(); // succeeds, as the contract was registered via cheatcode, so migrated to zkEVM +``` diff --git a/src/zksync-specifics/cheatcodes/zk-vm-skip.md b/src/zksync-specifics/cheatcodes/zk-vm-skip.md new file mode 100644 index 000000000..05972d0cc --- /dev/null +++ b/src/zksync-specifics/cheatcodes/zk-vm-skip.md @@ -0,0 +1,72 @@ +## `zkVmSkip` + +### Signature + +```solidity +function zkVmSkip() external pure; +``` + +### Description + +When running in zkEVM context, skips the next CREATE or CALL, executing it on the EVM instead. +All `CREATE`s executed within this skip, will automatically have `CALL`s to their target addresses +executed in the EVM, and need not be marked with this cheatcode at every usage location. + +Skipping the next operation in zkEVM does not involve [migrating](../execution-overview.md#execution-overview) storages as is done for [zkVm](./zk-vm.md) cheatcode. + +### Examples + +```solidity +/// contract LeetContract { +/// constructor(uint8 value) public { +/// // do something +/// } +/// } + +vmExt.zkVm(true); +new LeetContract(1); // deployed in zkEVM + +vmExt.zkVmSkip(); +new LeetContract(2); // deployed in EVM + +new LeetContract(3); // deployed in zkEVM +``` + +Any contract deployed within a skip is remembered as such, so adding `zkVmSkip` to all of its calls is not necessary: + +```solidity +/// contract LeetContract { +/// constructor(uint8 value) public { +/// // do something +/// } +/// +/// function sayLeet() public { +/// // do something +/// } +/// } + +contract FooTest is Test, TestExt { + LeetContract leet1; + LeetContract leet2; + + function setUp() public { + leet1 = new LeetContract(1); // deployed in zkEVM + + vmExt.zkVmSkip(); + leet2 = new LeetContract(2); // deployed in EVM + } + + function testAutomaticLeetDetection() public { + leet1.sayLeet(); // executed in zkEVM + + leet2.sayLeet(); // automatically executed in EVM + } + + function testManualLeetDetection() public { + leet1.sayLeet(); // executed in zkEVM + + vmExt.zkVmSkip(); // redundant here, as it is + leet2.sayLeet(); // automatically executed in EVM + } +} +``` diff --git a/src/zksync-specifics/cheatcodes/zk-vm.md b/src/zksync-specifics/cheatcodes/zk-vm.md new file mode 100644 index 000000000..0c3778492 --- /dev/null +++ b/src/zksync-specifics/cheatcodes/zk-vm.md @@ -0,0 +1,35 @@ +## `zkVm` + +### Signature + +```solidity +function zkVm(bool enable) external pure; +``` + +### Description + +Enables/Disables ZKsync context for transact/call and create instructions within a test or script execution. + +Switching VMs is a intensive process that translates the entire storage back-and-forth between EVM and zkEVM, and as such must be used sparingly in a test to switch between contexts. + +See [Execution Overview](../execution-overview.md#execution-overview) for further details. + +See [zkVmSkip](./zk-vm-skip.md) for a one-off and much simpler operation. + +### Examples + +```solidity +/// contract LeetContract { +/// constructor(uint8 value) public { +/// // do something +/// } +/// } + +vmExt.zkVm(true); +new LeetContract(1); // deployed in zkEVM +new LeetContract(2); // deployed in zkEVM + +vmExt.zkVm(false); +new LeetContract(3); // deployed in EVM +new LeetContract(4); // deployed in EVM +``` diff --git a/src/zksync-specifics/cheatcodes/zkvm.md b/src/zksync-specifics/cheatcodes/zkvm.md deleted file mode 100644 index 36b0d9ab0..000000000 --- a/src/zksync-specifics/cheatcodes/zkvm.md +++ /dev/null @@ -1,27 +0,0 @@ -## `zkVm` - -### Signature - -```solidity - -function zkVm(bool enable) external pure; -``` - -### Description - -Enables/Disables ZKsync context for transact/call and create instructions within a test or script execution. - -### Examples - -```solidity -/// contract LeetContract { -/// function leet() public { -/// // do something -/// } -/// } - -vm.zkVm(true); -new LeetContract(); // deployed in zkEVM -vm.zkVm(false); -new LeetContract(); // deployed in EVM -``` diff --git a/src/zksync-specifics/compilation-overview.md b/src/zksync-specifics/compilation-overview.md index 606985e42..f5eef6c41 100644 --- a/src/zksync-specifics/compilation-overview.md +++ b/src/zksync-specifics/compilation-overview.md @@ -2,6 +2,9 @@ [zksolc](https://github.com/matter-labs/era-compiler-solidity/releases) is the compiler used by ZKsync to convert solidity code to zkEVM-compatible bytecode. It uses the same input format as solc but the output bytecodes and their respective hashes. Internally it uses a custom-compiled [solc](https://github.com/matter-labs/era-solidity/releases) +### Dual Compilation + +To allow switching back and forth between EVM and zkEVM as defined in the [Execution Overview](./execution-overview.md), we compile the same contract with `solc` and `zksolc`. This dual-compiled contract can then be freely translated between both environments as needed. As such every contract in Foundry ZKsync always has two bytecodes attached - EVM bytecode and zkEVM bytecode, which are not equivalent. ### Limitations diff --git a/src/zksync-specifics/configuration-overview.md b/src/zksync-specifics/configuration-overview.md new file mode 100644 index 000000000..872803a28 --- /dev/null +++ b/src/zksync-specifics/configuration-overview.md @@ -0,0 +1,10 @@ +## Configuration Overview + +Foundry-ZKsync adds additional configuration options that can be specified in the `foundry.toml`. + +These include the following: + +- [Project Configuration](../reference/config/project.md#zksync-settings) +- [Testing Configuration](../reference/config/testing.md) + - [Fuzz](../reference/config/testing.md#no_zksync_reserved_addresses) + - [Invariant](../reference/config/testing.md#no_zksync_reserved_addresses-1) diff --git a/src/zksync-specifics/forge-zksync-std.md b/src/zksync-specifics/forge-zksync-std.md new file mode 100644 index 000000000..a99d09b35 --- /dev/null +++ b/src/zksync-specifics/forge-zksync-std.md @@ -0,0 +1,49 @@ +## Forge-ZKsync Standard Library + +[`forge-std`](https://github.com/foundry-rs/forge-std) exports the most common constructs that allow users to write tests. However, in Foundry ZKsync, we've added some new additions in the form of cheatcodes (or anything we deem useful in the future). To allow users to access these interfaces, [`forge-zksync-std`](https://github.com/Moonsong-Labs/forge-zksync-std) is provided as an add-on to `forge-std`. + + +### Installation + +```bash +forge install Moonsong-Labs/forge-zksync-std +``` + + +### Usage + +In the absence of `forge-zksync-std`, the new cheatcodes are only accessible via low-level calls: + +```solidity +import {Test} from "forge-std/Test.sol"; + +contract FooTest is Test { + function testZkTraceOutputDuringCreate() public { + vm.startPrank(address(65536)); // normal foundry cheatcodes + new Contract1(); + + (bool success,) = address(vm).call(abi.encodeWithSignature("zkVmSkip()")); // additional foundry-zksync cheatcodes + require(success, "zkVmSkip() call failed"); + new Contract2(); + } +} +``` + +However with the `TextExt` interface, the new cheatcodes can be accessed via `vmExt` property directly. The usual foundry cheatcodes are still available under the `vm` property. + +```solidity +import {Test} from "forge-std/Test.sol"; +import {TestExt} from "forge-zksync-std/TestExt.sol"; + +contract FooTest is Test, TestExt { + function testZkTraceOutputDuringCreate() public { + vm.startPrank(address(65536)); // normal foundry cheatcodes + new Contract1(); + + vmExt.zkVmSkip(); // additional foundry-zksync cheatcodes + new Contract2(); + } +} +``` + +This approach ensures that the existing tests need not be modified to use a completely different package than `foundry/forge-std` yet still allow for the additional ZKsync functionality to be included when necessary. \ No newline at end of file