Skip to content

Commit

Permalink
A new era
Browse files Browse the repository at this point in the history
vitalik.ca
  • Loading branch information
shahar4 committed Feb 15, 2023
0 parents commit 36fe0fd
Show file tree
Hide file tree
Showing 125 changed files with 23,729 additions and 0 deletions.
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Contribution Guidelines

Thank you for considering helping out with the source code! We are extremely grateful for any consideration of
contributions to this repository. However, at this time, we generally do not accept external contributions. This policy
will change in the future, so please check back regularly for updates.

For security issues, please contact us at [[email protected]](mailto:[email protected]).

Thank you for your support in accelerating the mass adoption of crypto for personal sovereignty!
21 changes: 21 additions & 0 deletions LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Matter Labs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# zkSync Era: Smart Contracts

[![Logo](eraLogo.svg)](https://zksync.io/)

zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or
decentralization. Since it's EVM compatible (Solidity/Vyper), 99% of Ethereum projects can redeploy without refactoring
or re-auditing a single line of code. zkSync Era also uses an LLVM-based compiler that will eventually let developers
write smart contracts in C++, Rust and other popular languages.

This repository contains both L1 and L2 zkSync smart contracts. For their description see the
[system overview](docs/Overview.md).

## Disclaimer

It is used as a submodule of a private repo. Compilation and test scripts should work without additional tooling, but
others may not.

## License

zkSync Era contracts are distributed under the terms of the MIT license.

See [LICENSE-MIT](LICENSE-MIT) for details.

## Official Links

- [Website](https://zksync.io/)
- [GitHub](https://github.com/matter-labs)
- [Twitter](https://twitter.com/zksync)
- [Twitter for Devs](https://twitter.com/zkSyncDevs)
- [Discord](https://discord.gg/px2ar7w)
19 changes: 19 additions & 0 deletions SystemConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"L2_TX_MAX_GAS_LIMIT": 80000000,
"MAX_PUBDATA_PER_BLOCK": 110000,
"PRIORITY_TX_MAX_PUBDATA": 99000,
"FAIR_L2_GAS_PRICE": 500000000,
"L1_GAS_PER_PUBDATA_BYTE": 17,
"BLOCK_OVERHEAD_L2_GAS": 1200000,
"BLOCK_OVERHEAD_L1_GAS": 1000000,
"MAX_TRANSACTIONS_IN_BLOCK": 1024,
"BOOTLOADER_TX_ENCODING_SPACE": 519017,
"L1_TX_INTRINSIC_L2_GAS": 167157,
"L1_TX_INTRINSIC_PUBDATA": 88,
"L1_TX_MIN_L2_GAS_BASE": 173484,
"L1_TX_DELTA_544_ENCODING_BYTES": 1656,
"L1_TX_DELTA_FACTORY_DEPS_L2_GAS": 2473,
"L1_TX_DELTA_FACTORY_DEPS_PUBDATA": 64,
"MAX_NEW_FACTORY_DEPS": 32,
"DEFAULT_L2_GAS_PRICE_PER_PUBDATA": 800
}
274 changes: 274 additions & 0 deletions docs/Overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
# Overview

zkSync Era is a permissionless general-purpose ZK rollup. Similar to many L1 blockchains and sidechains it enables
deployment and interaction with Turing-complete smart contracts.

- L2 smart contracts are executed on a zkEVM.
- zkEVM bytecode is different from the L1 EVM.
- There is a Solidity and Vyper compilers for L2 smart contracts.
- There is a standard way to pass messages between L1 and L2. That is a part of the protocol.
- There is no escape hatch mechanism yet, but there will be one.

All data that is needed to restore the L2 state are also pushed on-chain. There are two approaches, publishing inputs of
L2 transactions on-chain and publishing the state transition diff. zkSync follows the second option.

See the [documentation](https://v2-docs.zksync.io/dev/fundamentals/rollups.html) to read more!

## Glossary

- **Governor** - privileged address that controls the upgradability of the network and sets other privileged addresses.
- **Validator/Operator** - a privileged address that can commit/verify/execute L2 blocks.
- **Facet** - implementation contract. The word comes from the EIP-2535.
- **Security council** - set of trusted addresses that can decrease upgrade timelock.
- **Gas** - a unit that measures the amount of computational effort required to execute specific operations on the
zkSync v2 network.

### L1 Smart contracts

#### Diamond

Technically, this L1 smart contract acts as a connector between Ethereum (L1) and zkSync (L2). This contract checks the
validity proof and data availability, handles L2 <-> L1 communication, finalizes L2 state transition, and more.

There are also important contracts deployed on the L2 that can also execute logic called _system contracts_. Using L2
<-> L1 communication, they can affect both the L1 and the L2.

#### DiamondProxy

The main contract uses [EIP-2535](https://eips.ethereum.org/EIPS/eip-2535) diamond proxy pattern. It is an in-house
implementation that is inspired by the [mudgen reference implementation](https://github.com/mudgen/Diamond). It has no
external functions, only the fallback that delegates a call to one of the facets (target/implementation contract). So
even an upgrade system is a separate facet that can be replaced.

One of the differences from the reference implementation is access freezability. Each of the facets has an associated
parameter that indicates if it is possible to freeze access to the facet. Privileged actors can freeze the **diamond**
(not a specific facet!) and all facets with the marker `isFreezable` should be inaccessible until the governor unfreezes
the diamond. Note that it is a very dangerous thing since the diamond proxy can freeze the upgrade system and then the
diamond will be frozen forever.

#### DiamondInit

It is a one-function contract that implements the logic of initializing a diamond proxy. It is called only once on the
diamond constructor and is not saved in the diamond as a facet.

Implementation detail - function returns a magic value just like it is designed in
[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271), but the magic value is 32 bytes in size.

#### DiamondCutFacet

These smart contracts manage the freezing/unfreezing and upgrades of the diamond proxy. That being said, the contract
must never be frozen.

Currently, freezing and unfreezing are implemented as access control functions. It is fully controlled by the governor
but can be changed later. The governor can call `freezeDiamond` to freeze the diamond and `unfreezeDiamond` to restore
it.

Another purpose of `DiamondCutFacet` is to upgrade the facets. The upgrading is split into 2-3 phases:

- `proposeTransparentUpgrade`/`proposeShadowUpgrade` - propose an upgrade with visible/hidden parameters.
- `cancelUpgradeProposal` - cancel the upgrade proposal.
- `securityCouncilUpgradeApprove` - approve the upgrade by the security council.
- `executeUpgrade` - finalize the upgrade.

The upgrade itself characterizes by three variables:

- `facetCuts` - a set of changes to the facets (adding new facets, removing facets, and replacing them).
- pair `(address _initAddress, bytes _calldata)` for initializing the upgrade by making a delegate call to
`_initAddress` with `_calldata` inputs.

#### GettersFacet

Separate facet, whose only function is providing `view` and `pure` methods. It also implements
[diamond loupe](https://eips.ethereum.org/EIPS/eip-2535#diamond-loupe) which makes managing facets easier.

#### GovernanceFacet

Controls changing the privileged addresses such as governor and validators or one of the system parameters (L2
bootloader bytecode hash, verifier address, verifier parameters, etc).

At the current stage, the governor has permission to instantly change the key system parameters with `GovernanceFacet`.
Later such functionality will be removed and changing system parameters will be possible only via Diamond upgrade (see
_DiamondCutFacet_).

#### MailboxFacet

The facet that handles L2 <-> L1 communication, an overview for which can be found in
[docs](https://v2-docs.zksync.io/dev/developer-guides/bridging/l1-l2-interop.html).

The Mailbox performs three functions:

- L1 <-> L2 communication.
- Bridging native Ether to the L2.
- Censorship resistance mechanism (not yet implemented).

L1 -> L2 communication is implemented as requesting an L2 transaction on L1 and executing it on L2. This means a user
can call the function on the L1 contract to save the data about the transaction in some queue. Later on, a validator can
process it on L2 and mark them as processed on the L1 priority queue. Currently, it is used for sending information from
L1 to L2 or implementing multi-layer protocols.

_NOTE_: While user requests the transaction from L1, the initiated transaction on L2 will have such a `msg.sender`:

```solidity
address sender = msg.sender;
if (sender != tx.origin) {
sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
}
```

where

```solidity
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + offset);
}
}
```

The L1 -> L2 communication is also used for bridging ether. The user should include a `msg.value` when initiating a
transaction request on the L1 contract. Before executing a transaction on L2, the specified address will be credited
with the funds. To withdraw funds user should call `withdraw` function on the `L2EtherToken` system contracts. This will
burn the funds on L2, allowing the user to reclaim them through the `finalizeEthWithdrawal` function on the
`MailboxFacet`.

L2 -> L1 communication, in contrast to L1 -> L2 communication, is based only on transferring the information, and not on
the transaction execution on L1.

From the L2 side, there is a special zkEVM opcode that saves `l2ToL1Log` in the L2 block. A validator will send all
`l2ToL1Logs` when sending an L2 block to the L1 (see `ExecutorFacet`). Later on, users will be able to both read their
`l2ToL1logs` on L1 and _prove_ that they sent it.

From the L1 side, for each L2 block, a Merkle root with such logs in leaves is calculated. Thus, a user can provide
Merkle proof for each `l2ToL1Logs`.

_NOTE_: For each executed L1 -> L2 transaction, the system program necessarily sends an L2 -> L1 log. To verify the
execution status user may use the `proveL1ToL2TransactionStatus`.

_NOTE_: The `l2ToL1Log` structure consists of fixed-size fields! Because of this, it is inconvenient to send a lot of
data from L2 and to prove that they were sent on L1 using only `l2ToL1log`. To send a variable-length message we use
this trick:

- One of the system contracts accepts an arbitrary length message and sends a fixed length message with parameters
`senderAddress == this`, `marker == true`, `key == msg.sender`, `value == keccak256(message)`.
- The contract on L1 accepts all sent messages and if the message came from this system contract it requires that the
preimage of `value` be provided.

#### ExecutorFacet

A contract that accepts L2 blocks, enforces data availability and checks the validity of zk-proofs.

The state transition is divided into three stages:

- `commitBlocks` - check L2 block timestamp, process the L2 logs, save data for a block, and prepare data for zk-proof.
- `proveBlocks` - validate zk-proof.
- `executeBlocks` - finalize the state, marking L1 -> L2 communication processing, and saving Merkle tree with L2 logs.

When a block is committed, we process L2 -> L1 logs. Here are the invariants that are expected there:

- The only L2 -> L1 log from the `L2_SYSTEM_CONTEXT_ADDRESS`, with the `key == l2BlockTimestamp` and
`value == l2BlockHash`.
- Several (or none) logs from the `L2_KNOWN_CODE_STORAGE_ADDRESS` with the `key == bytecodeHash`, where bytecode is
marked as a known factory dependency.
- Several (or none) logs from the `L2_BOOTLOADER_ADDRESS` with the `key == canonicalTxHash` where `canonicalTxHash` is a
hash of processed L1 -> L2 transaction.
- Several (of none) logs from the `L2_TO_L1_MESSENGER` with the `value == hashedMessage` where `hashedMessage` is a hash
of an arbitrary-length message that is sent from L2
- None logs from other addresses (may be changed in future).

#### Bridges

Bridges are completely separate contracts from the Diamond. They are a wrapper for L1 <-> L2 communication on contracts
on both L1 and L2. Upon locking assets on one layer, a request is sent to mint these bridged assets on the other layer.
Upon burning assets on one layer, a request is sent to unlock them on the other.

Unlike the native Ether bridging, all other assets can be bridged by the custom implementation relying on the trustless
L1 <-> L2 communication.

##### L1ERC20Bridge

- `deposit` - lock funds inside the contract and send a request to mint bridged assets on L2.
- `claimFailedDeposit` - unlock funds if the deposit was initiated but then failed on L2.
- `finalizeWithdrawal` - unlock funds for the valid withdrawal request from L2.

##### L2ERC20Bridge

- `withdraw` - initiate a withdrawal by burning funds on the contract and sending a corresponding message to L1.
- `finalizeDeposit` - finalize the deposit and mint funds on L2.

#### Allowlist

The auxiliary contract controls the permission access list. It is used in bridges and diamond proxies to control which
addresses can interact with them in the Alpha release.

### L2 specifics

#### Deployment

The L2 deployment process is different from Ethereum.

In L1, the deployment always goes through two opcodes `create` and `create2`, each of which provides its address
derivation. The parameter of these opcodes is the so-called "init bytecode" - a bytecode that returns the bytecode to be
deployed. This works well in L1 but is suboptimal for L2.

In the case of L2, there are also two ways to deploy contracts - `create` and `create2`. However, the expected input
parameters for `create` and `create2` are different. It accepts the hash of the bytecode, rather than the full bytecode.
Therefore, users pay less for contract creation and don't need to send the full contract code by the network upon
deploys.

A good question could be, _how does the validator know the preimage of the bytecode hashes to execute the code?_ Here
comes the concept of factory dependencies! Factory dependencies are a list of bytecode hashes whose preimages were shown
on L1 (data is always available). Such bytecode hashes can be deployed, others - no. Note that they can be added to the
system by either L2 transaction or L1 -> L2 communication, where you can specify the full bytecode and the system will
mark it as known and allow you to deploy it.

Besides that, due to the bytecode differences for L1 and L2 contracts, address derivation is different. This applies to
both `create` and `create2` and means that contracts deployed on the L1 cannot have a collision with contracts deployed
on the L2. Please note that EOA address derivation is the same as on Ethereum.

Thus:

- L2 contracts are deployed by bytecode hash, not by full bytecode
- Factory dependencies - list of bytecode hashes that can be deployed on L2
- Address derivation for `create`/`create2` on L1 and L2 is different

### Withdrawal/Deposit Limitation

It is decided to have a limit on the amount of fund being deposited and withdrawn from the protocol.

#### Withdrawal Limitation

In case a malicious user could mint illegally some tokens on L2, there should be limitation to not allow the malicious
user withdrwing all the funds on L1. The current plan is to put withdrawal limitation on protocol level. In other words,
it is not allowed to withdraw more than some percent of the protocol balance for the defined tokens every day. Through
governance transaction, it is possible to add tokens to the list of withdrawal limitation, and also define the percent
that is allowed to withdraw daily.

```solidity
struct Withdrawal {
bool withdrawalLimitation;
uint256 withdrawalFactor;
}
```

#### Deposit Limitation

To be on the safe side, the amount of deposit is also going to be limited. This limitation is applied on account level,
and is not time-based. In other words, each account can not deposit more than the cap defined. The tokens and the cap
can be set through governance transaction. Moreover, there is a whitelisting mechanism as well (only some whitelisted
accounts can call some specific functions). So, the combination of deposit limiation and whitelisting lead to limiting
deposit of whitelisted account to be less than the defined cap.

```solidity
struct Deposit {
bool depositLimitation;
uint256 depositCap;
}
```

See the [documentation](https://v2-docs.zksync.io/dev/developer-guides/contracts/contracts.html#solidity-vyper-support)
to read more!
37 changes: 37 additions & 0 deletions eraLogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions ethereum/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CHAIN_ETH_NETWORK=localhost
CONTRACTS_PRIORITY_TX_MAX_GAS_LIMIT=72000000
ETH_CLIENT_WEB3_URL=http://127.0.0.1:8545
Loading

0 comments on commit 36fe0fd

Please sign in to comment.