Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General Improvements rev 2 #61

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/tutorials/create2-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ if (!success) {
}
```

### Computing the Contract Address on zkSync
### Computing the Contract Address on ZKsync

Lastly, we will create a view function named `computeAddress`. This function should take in the `salt`, `bytecodeHash`, and `constructorInput` as parameters and return the address of the contract that would be deployed using the `deploy` function on ZKsync:

Expand Down Expand Up @@ -174,7 +174,7 @@ The ZKsync-specific address derivation formula differs slightly from Ethereum’
```solidity
bytes32 hash = keccak256(
bytes.concat(
CREATE2_PREFIX, // zkSync-specific prefix
CREATE2_PREFIX, // ZKsync-specific prefix
bytes32(uint256(uint160(_sender))), // Address of the contract deployer
_salt, // Salt for the deployment
_bytecodeHash, // Hash of the bytecode
Expand Down
4 changes: 2 additions & 2 deletions src/zksync-specifics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ This section covers the specific parts of ZKSync foundry, how it works, insight

## Context

Foundry-zkSync tests are initially [executed](execution-overview.md) in the EVM context (the traditional execution environment for Ethereum smart contracts). This is done to maintain compatibility with Ethereum tooling and to leverage Foundry features like [Cheatcodes](limitations/cheatcodes.md).
Foundry-ZKsync tests are initially [executed](execution-overview.md) in the EVM context (the traditional execution environment for Ethereum smart contracts). This is done to maintain compatibility with Ethereum tooling and to leverage Foundry features like [Cheatcodes](limitations/cheatcodes.md).

![Features](../images/key-features.png)

### Lifetime Execution

A forge test begins execution in the EVM context but can switch to the EraVM context during the test for zkSync-specific features. Selecting the EraVM context ensures all calls and deployments are executed within zkSync.
A forge test begins execution in the EVM context but can switch to the EraVM context during the test for ZKsync-specific features. Selecting the EraVM context ensures all calls and deployments are executed within ZKsync.
There are mainly three steps

**Step 1)** Aggregate: [Dual compiling](compilation-overview.md) contracts
Expand Down
2 changes: 1 addition & 1 deletion src/zksync-specifics/examples/paymaster-approval-based.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Using the zkUsePaymaster Cheatcode in Approval-Based Paymaster Contracts

This example covers the use of an approval-based paymaster contract. The paymaster contract used is the testnet paymaster of zkSync documented [here](https://docs.zksync.io/build/start-coding/quick-start/paymasters-introduction).
This example covers the use of an approval-based paymaster contract. The paymaster contract used is the testnet paymaster of ZKsync documented [here](https://docs.zksync.io/build/start-coding/quick-start/paymasters-introduction).

### Steps Overview

Expand Down
15 changes: 9 additions & 6 deletions src/zksync-specifics/gas.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
### Gas reported back to the EVM
Foundry has an `isolate` mode for the EVM, in which all `CALL`/`CREATE` operations at the root level of a test (i.e., with depth 1) are intercepted and treated as independent transactions. This allows for accounting for the actual transaction gas, including, for example, the fixed 21000 gas cost charged to the user.

Running in zkEVM mode is analogous to running in `isolate` mode, but using the zkEVM is better. Every `CALL`/`CREATE` will be intercepted, a transaction representing the operation built. Finally, a VM with that transaction in the bootloader's heap will be spawned and run to simulate the execution of that transaction. The gas used is reported back to the EVM; hence, the one seen on traces and gas reports would be charged to the user for submitting that transaction. That value differs from the computational cost of running the called contract code and includes:

1. Intrinsic costs: Overhead charged on each transaction.
2. Validation costs: Gas spent on transaction validation. It may vary depending on the account making the transaction. See [Account Abstraction](https://docs.zksync.io/build/developer-reference/account-abstraction) docs.
3. Execution costs: Gas spent on marking factory dependencies and executing the transaction.
4. Pubdata costs: Gas spent on publishing pubdata is influenced by the `gasPerPubdata` network value.
Running in zkEVM mode is analogous to running in `isolate` mode, but using the zkEVM instead. Here's a short summary:
- Every `CALL`/`CREATE` will be intercepted, a transaction representing the operation built.
MBerguer marked this conversation as resolved.
Show resolved Hide resolved
- A VM with that transaction in the bootloader's heap will be spawned and run to simulate the execution of that transaction.
- The gas used is reported back to the EVM; hence, the one seen on traces and gas reports would be charged to the user for submitting that transaction. That value differs from the computational cost of running the called contract code and includes:
MBerguer marked this conversation as resolved.
Show resolved Hide resolved

1. **Intrinsic costs**: Overhead charged on each transaction.
2. **Validation costs**: Gas spent on transaction validation. It may vary depending on the account making the transaction. See [Account Abstraction](https://docs.zksync.io/build/developer-reference/account-abstraction) docs.
3. **Execution costs**: Gas spent on marking factory dependencies and executing the transaction.
4. **Pubdata costs**: Gas spent on publishing pubdata. It is influenced by the `gasPerPubdata` network value.

More info about ZKSync Era's fee model can be found [here](https://docs.zksync.io/build/developer-reference/fee-model).

Expand Down
75 changes: 39 additions & 36 deletions src/zksync-specifics/limitations/compilation.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract FooTest is Test {
}
```

See [here](./general.md#accessing-contract-bytecode-and-hash) to circumvent this issue.
See [here](./general.md#accessing-contract-bytecode-and-hash) on how to circumvent this issue.

### Contract Size Limit

Expand All @@ -38,50 +38,55 @@ There are three possible solutions to address this issue:

1. **Compilation with `--zk-force-evmla=true`:**

Compiling in a different mode can sometimes bypass the contract size limit. You can attempt to compile the contract using ZKsync's EVM legacy architecture by adding the `--zk-force-evmla=true` flag.
Compiling in a different mode can sometimes bypass the contract size limit. You can attempt to compile the contract using ZKsync's EVM legacy architecture by adding the `--zk-force-evmla=true` flag.

Example command:
```bash
forge build --zk-force-evmla=true --zksync
```
Example command:

```bash
forge build --zk-force-evmla=true --zksync
```

1. **Compilation with `--zk-fallback-oz=true`:**

If the contract size still exceeds the limit, try compiling with optimization level `-Oz` by using the `--zk-fallback-oz=true` flag. This tells the compiler to fall back to `-Oz` optimization when the bytecode is too large, potentially reducing the contract size further.
If the contract size still exceeds the limit, try compiling with optimization level `-Oz` by using the `--zk-fallback-oz=true` flag. This tells the compiler to fall back to `-Oz` optimization when the bytecode is too large, potentially reducing the contract size further.

Example command:

Example command:
```bash
forge build --zk-fallback-oz=true --zksync
```
```bash
forge build --zk-fallback-oz=true --zksync
```

1. **Split the Contract into Smaller Units**

If neither of the above flags resolves the issue, the contract must be refactored into more minor, modular contracts. This involves separating your logic into different contracts and using contract inheritance or external contract calls to maintain functionality.
If neither of the above flags resolves the issue, the contract must be refactored into smaller, modular contracts. This involves separating your logic into different contracts and using contract inheritance or external contract calls to maintain functionality.

**Before (single large contract):**
```solidity
contract LargeContract {
function largeFunction1() public { /* complex logic */ }
function largeFunction2() public { /* complex logic */ }
// Additional large functions and state variables...
}
```
**After (multiple smaller contracts):**
```solidity
contract ContractPart1 {
function part1Function() public { /* logic from largeFunction1 */ }
}
contract ContractPart2 {
function part2Function() public { /* logic from largeFunction2 */ }
}
contract MainContract is ContractPart1, ContractPart2 {
// Logic to combine the functionalities of both parts
}
```
**Before (single large contract):**

### _Non-inlinable_ libraries
```solidity
contract LargeContract {
function largeFunction1() public { /* complex logic */ }
function largeFunction2() public { /* complex logic */ }
// Additional large functions and state variables...
}
```

Compiling contracts without linking _non-inlinable_ libraries is currently not supported. Libraries must be deployed before building contracts using them.
**After (multiple smaller contracts):**

```solidity
contract ContractPart1 {
function part1Function() public { /* logic from largeFunction1 */ }
}
contract ContractPart2 {
function part2Function() public { /* logic from largeFunction2 */ }
}
contract MainContract is ContractPart1, ContractPart2 {
// Logic to combine the functionalities of both parts
}
```

### Non-inlinable libraries

Compiling contracts without linking [non-inlinable](https://docs.zksync.io/zksync-era/tooling/hardhat/guides/compiling-libraries) libraries is currently not supported. Libraries must be deployed before building contracts using them.

When building the contracts, the addresses must be passed using the `libraries` config, which contains a list of `CONTRACT_PATH`:`ADDRESS` mappings.

Expand All @@ -105,5 +110,3 @@ Please refer to [official docs](https://docs.zksync.io/build/developer-reference
#### Listing missing libraries

To scan missing non-inlinable libraries, you can build the project using the `--zk-detect-missing-libraries` flag. This will list the libraries that must be deployed and their addresses provided via the `libraries` option for the contracts to compile. Metadata about the libraries will be saved in `.zksolc-libraries-cache/missing_library_dependencies.json`.


2 changes: 1 addition & 1 deletion src/zksync-specifics/limitations/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,4 @@ Traces:
```


To avoid such a scenario, it's recommended that the events for `expectEmit` be explicitly emitted with hard-coded values.
To avoid such a scenario, it's recommended to explicitly emit the events for `expectEmit` with hard-coded values.
Loading