Skip to content

Commit ba01e1f

Browse files
authored
feat: predeploys, not era (#465)
# Description - Adds createX predeploy - Rewrite security and best practices - More contracts in protocol ecosystem page ## Linked Issues N/A ## Additional context Feedback from Sophon team
1 parent 40cf54c commit ba01e1f

3 files changed

Lines changed: 80 additions & 64 deletions

File tree

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,75 @@
11
---
22
title: Security and best practices
3-
description:
3+
description: Guidelines to help you build secure, efficient, and maintainable smart contracts on ZKsync chains powered by the EraVM.
44
---
55

6-
Before diving into development on ZKsync Era, it's crucial to consider the following recommendations. These best
7-
practices will help you optimize your code, ensure security, and align with the unique characteristics of ZKsync Era.
6+
Before developing on a ZKsync chain, review these best practices. Following these recommendations will
7+
help you optimize performance, maintain security, and align your contracts with the design of the EraVM.
88

9-
## Use `call` over `.send` or `.transfer`
9+
## Use `call` instead of `.send` or `.transfer`
1010

11-
Avoid using `payable(addr).send(x)`/`payable(addr).transfer(x)` because the 2300 gas stipend may not be enough
12-
for such calls, especially if it involves state changes that require a large amount of L2 gas for data. Instead, we recommend using `call`.
11+
Avoid using `payable(addr).send(x)` or `payable(addr).transfer(x)`.
12+
These functions only provide a 2300 gas stipend, which may not be enough if the call triggers state changes or other operations that require more L2 gas.
1313

14-
Instead of:
14+
Use `call` instead.
15+
16+
**Instead of:**
1517

1618
```solidity
17-
payable(addr).send(x) // or
18-
payable(addr).transfer(x)
19+
payable(addr).send(x); // or
20+
payable(addr).transfer(x);
1921
```
2022

21-
Use:
23+
**Use:**
2224

2325
```solidity
2426
(bool s, ) = addr.call{value: x}("");
2527
require(s);
2628
```
2729

28-
This converts the `send`/`transfer` functionality to `call` and [avoids potential security risks outlined here.](https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/).
30+
This approach replicates the behavior of `.send` or `.transfer` while providing more flexibility and avoiding gas-limit issues.
31+
See [Consensys’ explanation of `.transfer` risks](https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/) for additional context.
2932

30-
While `.call` offers more flexibility compared to `.send` or `.transfer`, developers should be aware that `.call`
31-
does not provide the same level of reentrancy protection as `.transfer`/`.send`. It's crucial to adhere to best
32-
practices like the checks-effects-interactions pattern and/or use reentrancy guard protection to secure your
33-
contracts against reentrancy attacks. It can help ensure the robustness and security of your smart contracts on the ZKSync VM, even under unexpected conditions.
33+
While `.call` is safer in terms of gas, it does not provide built-in reentrancy protection. To prevent vulnerabilities:
3434

35-
## Use the proxy pattern at the early stage of the protocol
35+
- Follow the **checks-effects-interactions** pattern.
36+
- Use a **reentrancy guard** when interacting with external contracts.
3637

37-
ZKsync Era is based on the zk-friendly VM. Thus, we offer
38-
[a dedicated compiler](/zksync-protocol/era-vm/compiler/toolchain)
39-
responsible for transforming conventional Solidity and Vyper code into zkEVM bytecode.
38+
These practices help secure your contracts against reentrancy attacks and unexpected external behavior.
4039

41-
While we have extensive test coverage to ensure EVM compatibility, issues may still appear.
42-
We will implement the patches for these in a timely manner.
40+
## Use the Proxy Pattern
4341

44-
To integrate a compiler bug fix, you need to recompile and upgrade your smart contract. We recommend using the
45-
Proxy pattern for a few months after your first deployment on ZKsync Era, even if you plan to migrate to an immutable
46-
contract in the future.
42+
ZKsync chains running EraVM support Solidity and Vyper code compilation into **EraVM bytecode** using custom compilers.
43+
Although the compilers undergoes extensive testing to ensure EVM compatibility, minor issues can occasionally appear.
4744

48-
## Do not rely on EVM gas logic
45+
::callout{icon="i-heroicons-light-bulb"}
46+
ZKsync chains also support EVM Bytecode from the `solc` compiler.
47+
::
4948

50-
ZKsync Era has a distinctive gas logic compared to Ethereum. There are two main drivers:
49+
To handle potential compiler patches or updates, use the **Proxy pattern** when deploying new contracts.
50+
This allows you to recompile and upgrade your contract logic without requiring a full redeployment.
5151

52-
- We have a state-diff-based data availability, which means that the price for the execution depends on the L1 gas price.
53-
- ZKsync VM has a different set of computational trade-offs compared to the standard computational model. In
54-
practice, this means that the price for opcodes is different to Ethereum. Also, zkEVM contains a different set of
55-
opcodes under the hood and so the “gas” metric of the same set of operations may be different on ZKsync Era and on Ethereum.
52+
After your contracts have proven stable, you can migrate to an immutable version if desired.
5653

57-
::callout{icon="i-heroicons-exclamation-triangle" color="amber"}
58-
Our fee model is being constantly improved and so it is highly recommended **NOT** to hardcode any constants since the fee
59-
model changes in the future might be breaking for this constant.
60-
::
54+
Using the Proxy pattern during the initial deployment phase reduces maintenance effort and ensures flexibility as the EraVM continues to evolve.
55+
56+
## Do Not Rely on Ethereum Gas Logic
57+
58+
The gas model on ZKsync chains differs from Ethereum’s. Two key factors influence gas costs:
59+
60+
1. **State-diff-based data availability** – transaction costs depend on L1 gas prices.
61+
2. **Distinct computational model** – the EraVM uses a different opcode pricing model and computational trade-offs compared to the EVM.
6162

62-
## `gasPerPubdataByte` should be taken into account in development
63+
Because of these differences, gas usage on a ZKsync chain cannot be directly compared to Ethereum.
64+
Avoid hardcoding gas constants in your contracts, as future changes to ZKsync’s fee model could make these assumptions invalid.
6365

64-
Due to the state diff-based fee model of ZKsync Era, every transaction includes a constant called `gasPerPubdataByte`.
66+
## Account for `gasPerPubdataByte`
6567

66-
Presently, the operator has control over this value. However, in EIP712 transactions, users also sign an upper bound
67-
on this value, but the operator is free to choose any value up to that upper bound. Note, that even if the value
68-
is chosen by the protocol, it still fluctuates based on the L1 gas price. Therefore, relying solely on gas is inadequate.
68+
Each transaction on ZKsync includes a constant called `gasPerPubdataByte`.
69+
This value is set by the operator, although users define an upper bound for it in EIP-712 transactions.
70+
Since `gasPerPubdataByte` fluctuates with L1 gas prices, relying solely on gas limits can lead to unpredictable behavior.
6971

70-
A notable example is a Gnosis Safe’s `execTransaction` method:
72+
For example, in Gnosis Safe’s `execTransaction` method:
7173

7274
```solidity
7375
// We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
@@ -85,37 +87,46 @@ require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010
8587
}
8688
```
8789

88-
While the contract does enforce the correct `gasleft()`, it does not enforce the correct `gasPerPubdata`, since there
89-
was no such parameter on Ethereum. This means that a malicious user could call this wallet when the `gasPerPubdata` is
90-
high and make the transaction fail, hence making it spend artificially more gas than required.
90+
This logic enforces a minimum `gasleft()` but does not account for `gasPerPubdata`.
91+
A malicious user could exploit a high `gasPerPubdata` value to increase gas costs or cause transaction failures.
9192

92-
This is the case for all relayer-like logic ported directly from Ethereum and so if you see your code relying on logic
93-
like “the user should provide at X gas”, then the `gasPerPubdata` should be also taken into account on ZKsync Era.
93+
When porting logic from Ethereum:
9494

95-
For now, ZKsync Era operators use honest values for ETH L1 price and `gasPerPubdata`, so it should not be an issue if
96-
enough margin is added to the estimated gas. In order to prepare for the future decentralization of ZKsync Era,
97-
it is imperative that you update your contract.
95+
- Include `gasPerPubdata` in your gas calculations.
96+
- Add a safety margin to handle price fluctuations.
97+
- Avoid assumptions based on Ethereum’s static gas model.
9898

99-
## Use native account abstraction over `ecrecover` for validation
99+
Currently, ZKsync operators use accurate and fair values for ETH L1 pricing and `gasPerPubdata`,
100+
but preparing your contracts for future decentralization ensures long-term stability and reliability.
100101

101-
Use ZKsync Era's native account abstraction support for signature validation instead of this function.
102+
## Use Native Account Abstraction for Validation
102103

103-
We recommend not relying on the fact that an account has an ECDSA private key, since the account may be governed by
104-
multisig and use another signature scheme.
104+
Do not rely on `ecrecover` for signature verification.
105+
ZKsync chains running EraVM use **native account abstraction**, which supports flexible authentication
106+
mechanisms such as multisignature wallets or custom signature schemes.
105107

106-
Read more about [ZKsync Era Account Abstraction support](/zksync-protocol/era-vm/account-abstraction).
108+
Assuming all accounts use ECDSA private keys may cause compatibility issues.
109+
Instead, rely on the built-in account abstraction mechanisms for validation to ensure forward compatibility.
107110

108-
## Use local testing environment
111+
Learn more in the [Account Abstraction guide](/zksync-protocol/era-vm/account-abstraction).
109112

110-
For optimal development and testing of your contracts, it is highly recommended to perform local testing before deploying
111-
them to the mainnet. Local testing allows you to test your contracts in a controlled environment, providing benefits such as
112-
reduced network latency and cost.
113+
## Test in a Local Environment
113114

114-
We provide [two different testing environments](/zksync-network/tooling/local-setup) designed for local testing purposes.
115-
These tools allow you to simulate the ZKsync network locally, enabling you to validate your contracts effectively.
115+
Always test your contracts locally before deploying to mainnet.
116+
Local testing allows you to verify contract behavior in a controlled environment, reduce latency, and avoid transaction costs.
116117

117-
By incorporating local testing into your development workflow, you can effectively verify the behavior and functionality of
118-
your contracts in a controlled environment, ensuring a smooth deployment process to the mainnet.
118+
ZKsync provides [local testing environments](/zksync-network/tooling/local-setup) that simulate mainnet behavior for development purposes.
119+
120+
To test locally:
121+
122+
1. **Set up the local environment** using one of the available tools.
123+
2. **Run your tests** with frameworks such as **Foundry** and **Hardhat** to verify expected behavior.
124+
3. **Review results** and confirm that events, gas usage, and outputs match expectations.
125+
4. **Iterate and refine** before deploying to testnet or mainnet.
126+
127+
Local testing helps you identify issues early, ensuring a more reliable and predictable deployment on ZKsync chains.
128+
129+
---
119130

120-
For detailed instructions on configuring the local testing environment and performing tests using Mocha and Chai,
121-
refer to the dedicated [Testing](/zksync-network/tooling/local-setup) page.
131+
By following these best practices, you can improve the security, reliability, and maintainability of your smart
132+
contracts across all ZKsync chains powered by the EraVM.

content/20.zksync-protocol/20.contracts/10.l1-contracts/30.zk-chain-addresses.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ that expects a chain ID as an argument and returns the address of the ZKsync Cha
2222
| -------------- | ------- |
2323
| Bridgehub | [0x303a465B659cBB0ab36eE643eA362c509EEb5213](https://etherscan.io/address/0x303a465B659cBB0ab36eE643eA362c509EEb5213) |
2424
| Shared Bridge | [0xD7f9f54194C633F36CCD5F3da84ad4a1c38cB2cB](https://etherscan.io/address/0xD7f9f54194C633F36CCD5F3da84ad4a1c38cB2cB) |
25+
| L1AssetRouter | [0x8829AD80E425C646DAB305381ff105169FeEcE56](https://etherscan.io/address/0x8829AD80E425C646DAB305381ff105169FeEcE56) |
26+
| L1NativeTokenVault| [0xbeD1EB542f9a5aA6419Ff3deb921A372681111f6](https://etherscan.io/address/0xbeD1EB542f9a5aA6419Ff3deb921A372681111f6)|
2527
| CTM (official) | [0xc2eE6b6af7d616f6e27ce7F4A451Aedc2b0F5f5C](https://etherscan.io/address/0xc2eE6b6af7d616f6e27ce7F4A451Aedc2b0F5f5C) |
2628

2729
### CTM (official)
@@ -43,6 +45,8 @@ Learn [how to get the Chain Type Manager for a ZKsync Chain](#getting-the-chain-
4345
| -------------- | ------- |
4446
| Bridgehub | [0x35A54c8C757806eB6820629bc82d90E056394C92](https://sepolia.etherscan.io/address/0x35A54c8C757806eB6820629bc82d90E056394C92) |
4547
| SharedBridge | [0x3E8b2fe58675126ed30d0d12dea2A9bda72D18Ae](https://sepolia.etherscan.io/address/0x3E8b2fe58675126ed30d0d12dea2A9bda72D18Ae) |
48+
|L1AssetRouter| [0xF2a49545C5B1A85d2fB018cC39103661639a9B06](https://sepolia.etherscan.io/address/0xF2a49545C5B1A85d2fB018cC39103661639a9B06)|
49+
|L1NativeTokenVault| [0x746DBBa1edfBe1b547c87189eFE91B77d53d9E39](https://sepolia.etherscan.io/address/0x746DBBa1edfBe1b547c87189eFE91B77d53d9E39) |
4650
| CTM (official) | [0x4e39E90746A9ee410A8Ce173C7B96D3AfEd444a5](https://sepolia.etherscan.io/address/0x4e39E90746A9ee410A8Ce173C7B96D3AfEd444a5) |
4751
| CTM (custom) | [0x762b5F15CAd9880ace81776f9046d6a52DD67a9b](https://sepolia.etherscan.io/address/0x762b5F15CAd9880ace81776f9046d6a52DD67a9b) |
4852

content/20.zksync-protocol/30.era-vm/75.evm-interpreter/06.pre-deployed-contracts.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The following contracts are **pre-deployed** and available for use:
1313
| [Safe Singleton Factory](https://github.com/safe-global/safe-singleton-factory/blob/main/source/deterministic-deployment-proxy.yul) | `0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7` |
1414
| [Multicall3](https://github.com/mds1/multicall/tree/main) | `0xcA11bde05977b3631167028862bE2a173976CA11` |
1515
| [Create2 Proxy (Zoltu)](https://github.com/Zoltu/deterministic-deployment-proxy) | `0x7A0D94F55792C434d74a40883C6ed8545E406D12` |
16-
|[Universal Deployer](https://gist.github.com/Agusx1211/de05dabf918d448d315aa018e2572031)| `0x1b926fbb24a9f78dcdd3272f2d86f5d0660e59c0` |
16+
| [Universal Deployer](https://gist.github.com/Agusx1211/de05dabf918d448d315aa018e2572031)| `0x1b926fbb24a9f78dcdd3272f2d86f5d0660e59c0` |
17+
| [CreateX (pcaversaccio)](https://github.com/pcaversaccio/createx)| `0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed` |
1718

1819
These contracts are **readily available** and can be used without requiring redeployment.

0 commit comments

Comments
 (0)