Skip to content

Commit 33dc6ce

Browse files
authored
docs: Add bridging and l1<>l2 communications docs (matter-labs#3870)
## What ❔ <!-- What are the changes this PR brings about? --> Continuation of the effort to reorganize our documentation. In this pull request, bridging and l1<>l2 communications documentation have been added. Note, that bridging section will be extended upon interop documentation completion. Also, some of the links were fixed due to appearance of related files. ## Why ❔ <!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? --> This reorganization will allow us to review the documentation relevant to smart contracts and migrate it to the `zksync-era` repository, where it will be accessible via a generated website. ## Is this a breaking change? - [ ] Yes - [ ] No ## Operational changes <!-- Any config changes? Any new flags? Any changes to any scripts? --> <!-- Please add anything that non-Matter Labs entities running their own ZK Chain may need to know --> ## Checklist <!-- Check your PR fulfills the following items. --> <!-- For draft PRs check the boxes as you complete them. --> - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`.
1 parent 2c163a3 commit 33dc6ce

21 files changed

+469
-9
lines changed

docs/src/SUMMARY.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@
6666
- [Admin role](specs/contracts/chain_management/admin_role.md)
6767
- [Chain genesis](specs/contracts/chain_management/chain_genesis.md)
6868
- [Standard Upgrade process](specs/contracts/chain_management/upgrade_process.md)
69+
- [Bridging](specs/contracts/bridging/overview.md)
70+
- [Asset Router](specs/contracts/bridging/asset_router_and_ntv/asset_router.md)
71+
- [Native token vault](specs/contracts/bridging/asset_router_and_ntv/native_token_vault.md)
72+
- [Settlement Contracts](specs/contracts/settlement_contracts/zkchain_basics.md)
73+
- [L1 <> L2 communication](specs/contracts/settlement_contracts/priority_queue/README.md)
74+
- [Handling L1→L2 operations](specs/contracts/settlement_contracts/priority_queue/l1_l2_communication/l1_to_l2.md)
75+
- [L2→L1 communication](specs/contracts/settlement_contracts/priority_queue/l1_l2_communication/l2_to_l1.md)
76+
- [Overview - Deposits and Withdrawals](specs/contracts/settlement_contracts/priority_queue/l1_l2_communication/overview_deposits_withdrawals.md)
77+
- [Priority queue](specs/contracts/settlement_contracts/priority_queue/priority-queue.md)
6978
- [Prover](specs/prover/overview.md)
7079
- [Getting Started](specs/prover/getting_started.md)
7180
- [ZK Terminology](specs/prover/zk_terminology.md)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# AssetRouter
2+
3+
> **Overview:**
4+
> - **On L1:** The **L1 Asset Router** handles cross‑chain asset coordination _and_ is complemented by the **L1 Nullifier** for additional finalization and recovery features.
5+
> - **On L2:** Only the **L2 Asset Router** is pre-deployed at the same address (`0x10003`) on every L2 chain.
6+
7+
### AssetRouter (L1/L2)
8+
9+
The main job of the asset router is to be the central point of coordination for asset bridging. All crosschain token bridging is done between asset routers only and once the message reaches asset router, it then routes it to the corresponding asset handler.
10+
11+
In order to make this easier, all L2 chains have the asset router located on the same address on every chain. It is `0x10003` and it is pre-deployed contract. More on how it is deployed can be seen in the [Chain Genesis](../../chain_management/chain_genesis.md) section.
12+
13+
The endgame is to have L1 asset router have the same functionality as the L2 one. This is not the case yet, but some progress has been made: L2AssetRouter can now bridge L2-native assets to L1, from which it could be bridged to other chains in the ecosystem.
14+
15+
Examples of differences in functionality are:
16+
17+
1. Failed‐deposit recovery.
18+
The `L1AssetRouter` provides on-chain recovery for failed L1→L2 deposits via its `bridgeRecoverFailedTransfer` and `claimFailedDeposit` functions. The `L2AssetRouter` has no equivalent, because L2→L1 withdrawals are atomic on L2: burning the L2 token and sending the L2→L1 withdrawal message occur in the same transaction. If anything goes wrong, the entire transaction reverts and no token is burned and no message is sent.
19+
2. User-initiated L1→L2 deposits must go through Bridgehub (or the legacy bridge), not directly.
20+
There is no public `deposit(...)` on `L1AssetRouter` you can call as a user—only, by contrast, on L2 you have a public `withdraw(...)` method.
21+
In case of `L1AssetRouter` user has to start deposit through either `Bridgehub` or `L1ERC20Bridge` (legacy bridge).
22+
However in case of `L2AssetRouter` user is able to simply call `withdraw` function in `L2AssetRouter`.
23+
24+
The specifics of the L2AssetRouter is the need to interact with the previously deployed L2SharedBridgeLegacy if it was already present. It has less “rights” than the L1AssetRouter: at the moment it is assumed that all asset deployment trackers are from L1, the only way to register an asset handler on L2 is to make an L1→L2 transaction.
25+
26+
> Note, that today registering new asset deployment trackers is permissioned, but the plan is to make it permissionless in the future
27+
28+
The specifics of the L1AssetRouter come from the need to be backwards compatible with the old L1SharedBridge. Yes, it does not share the same storage, but it inherits the need to be backwards compatible with the current SDK. Also, L1AssetRouter needs to facilitate L1-only operations, such as recovering from failed deposits.
29+
30+
Also, L1AssetRouter is the only base token bridge contract that can participate in initiation of cross chain transactions via the bridgehub. This might change in the future.
31+
32+
### L1Nullifier
33+
34+
While the endgoal is to unify L1 and L2 asset routers, in reality, it may not be that easy: while L2 asset routers get called by L1→L2 transactions, L1 ones don't and require manual finalization of transactions, which involves proof verification, etc. To move this logic outside of the L1AssetRouter, it was moved into a separate L1Nullifier contract.
35+
36+
_This is the contract the previous L1SharedBridge had been upgraded to, so it has the backwards compatible storage._
37+
38+
### A separate L2Nullifier does not exist
39+
40+
The L1Nullifier stores two things:
41+
1. finalized L2->L1 withdrawals
42+
1. initiated L1->L2 priority transactions
43+
44+
1. is needed on L1 as L2->L1 txs are executed arbitrarily, so we need to record whether they happened or not to stop double spending. However, L1->L2 priority txs are enforced to be executed only once, so we don't need a separate L2Nullifier.
45+
46+
2. The initiated L2->L1 and L2->L2 transactions are not stored. This is needed for L1->L2 txs, as priority transactions have to be executed by the system, and cannot be retried if they fail. So failed deposits have to be redeemable on L1. L2->L2 and L2->L1 txs might also fail, but if they fail due to gas reasons, they can be retried. If they fail due to contract error, then the receiving contract has to be fixed ( another way of explaining it, there can always be a contract error even for claiming failed deposits. So the only sustainable way of fixing contract errors is to fix the contract).
47+
48+
For this reason, on the L2 claiming failed deposits and bridgehubConfirmL2Transaction are not implemented.
49+
50+
### L2SharedBridgeLegacy
51+
52+
L2AssetRouter is pre-deployed onto a specific address. The old L2SharedBridge is upgraded to L2SharedBridgeLegacy contract. The main purpose of this contract is to ensure compatibility with the incoming deposits and re-route them to the shared bridge.
53+
54+
This contract is never deployed for new chains.
105 KB
Loading
378 KB
Loading
195 KB
Loading
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Native Token Vault
2+
3+
### NativeTokenVault (L1/L2)
4+
5+
NativeTokenVault is an asset handler that is available on all chains and is also predeployed. It provides the functionality of the most basic bridging: locking funds on one chain and minting the bridged equivalent on the other one. On L2 chains NTV is predeployed at the `0x10004` address. NativeTokenVault acts as the default AssetHandler, so regular ERC-20 tokens can use it unless custom bridging logic or special features are required.
6+
7+
The L1 and L2 versions of the NativeTokenVault share the same core functionality, but differ in their deployment mechanics and certain L1-specific responsibilities.
8+
9+
On L1, the contract is deployed using standard CREATE2, while on L2 it uses low-level calls to the CONTRACT_DEPLOYER system contract.
10+
11+
Also, the L1NTV has the following specifics:
12+
13+
- It operates the `chainBalance` mapping, ensuring that the chains do not go beyond their balances.
14+
- It allows recovering from failed L1→L2 transfers.
15+
- It needs to both be able to retrieve funds from the former L1SharedBridge (now this contract has L1Nullifier in its place), but also needs to support the old SDK that gives out allowance to the “l1 shared bridge” value returned from the API, i.e. in our case this is will the L1AssetRouter.
16+
17+
### Summary
18+
19+
![image.png](./img/bridge_contracts.png)
20+
21+
> New bridge contracts
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Overview of Custom Asset Bridging with the Asset Router
2+
3+
Bridges are completely separate contracts from the ZKChains and system contracts. They are a wrapper for L1 <-> L2 communication on both L1 and L2. Upon locking assets on one layer, a request is sent to mint these bridged assets on the other layer.
4+
Upon burning assets on one layer, a request is sent to unlock them on the other.
5+
6+
Custom asset bridging is a new bridging model that allows to:
7+
8+
1. Minimize the effort needed by custom tokens to be able to become part of the elastic chain ecosystem. Before, each custom token would have to build its own bridge, but now just custom asset deployment trackers / asset handler is needed. This is achieved by building a modular bridge which separates the logic of L1<>L2 messaging from the holding of the asset.
9+
2. Unify the interfaces between L1 and L2 bridge contracts, paving the way for easy cross chain bridging. It will especially become valuable once interop is enabled.
10+
11+
#### New concepts
12+
13+
- assetId => identifier to track bridged assets across chains. This is used to link messages to specific asset handlers in the AssetRouters. Note, that since the same asset could be created on multiple chains, assetId is not just an address. It's obtained by combining chain id, NTV as asset deployment tracker and asset data. Usually, address is used as asset data field. This was assets that share the same address on different chains will have different assetId.
14+
- AssetHandler => contract that manages liquidity (burns/mints, locks/unlocks, etc.) for specific token (or a set of them) on a chain.
15+
- AssetDeploymentTracker => contract that manages the deployment of asset handlers across chains. This is the contract that registers these asset handlers in the AssetRouters.
16+
- AssetRouter => contract that coordinates crosschain token bridging and routes messages to the correct AssetHandler.
17+
18+
### Normal flow
19+
20+
#### Registering a custom asset
21+
22+
- AssetHandler Registration for New Tokens
23+
Before you can bridge a new token, you must register its AssetHandler in both routers. However, for NTV (Native Token Vault) assets this step isn’t required. If an L1→L2 transaction is submitted without a registered AssetHandler, it won’t fail—instead, the message is automatically forwarded to the L2NTV contract. The L2NTV then verifies that the asset was deployed by the L1NTV by checking that the `assetId` embeds the correct ADT address (for NTV assets, the ADT is the NTV and the relevant address is the L2NTV address). If the `assetId` is valid, the token contract is deployed on L2.
24+
25+
- Automatic Bridging via the Native Token Vault
26+
The Native Token Vault is a special AssetHandler designed for automatic bridging. It lets you bridge an L1 token to L2 without pre-deploying the token contract or registering it in the L2 router. Under the hood, unregistered AssetHandler messages are forwarded to the L2NTV, which performs the same `assetId` check and, upon validation, deploys the corresponding token contract.
27+
28+
- Custom Asset Registration Flow
29+
1. Deploy the Asset Handlers (on L1 and L2), the custom token contracts, and the Asset Deployment Tracker (ADT). The ADT is expected to be deployed on L1.
30+
2. The ADT calls `setAssetHandlerAddressThisChain` on `L1AssetRouter` to register itself and its corresponding Asset Handler by updating the appropriate mapping.
31+
3. During an L1→L2 deposit, the internal method `_setAssetHandlerAddressOnCounterpart` is invoked automatically to propagate the registration to the L2 router.
32+
33+
A visualization of this process can be seen here:
34+
[Asset Registration](./img/custom_asset_handler_registration.png)
35+
36+
#### Bridging an already-registered asset
37+
38+
- From L1 to L2
39+
1. The user calls `requestL2TransactionTwoBridges` on `Bridgehub`, specifying `L1AssetRouter` as the second bridge address, along with all other parameters required to initiate the transfer.
40+
2. Under the hood, `Bridgehub`, `L1AssetRouter`, and the Asset Handler contracts verify the validity of the provided data, value, and allowances. If everything checks out, the `bridgehubRequestL2Transaction` method is called on the ZK Chain, appending a priority transaction to `L2AssetRouter.finalizeDeposit`.
41+
3. The operator picks up the priority transaction. If it executes successfully, the transfer completes. Otherwise, the user can reclaim their assets via the `claimFailedDeposit` function in `L1AssetRouter`, providing proof that the transaction indeed failed on L2.
42+
43+
A visualization of steps 1–2 can be seen here:
44+
[RequestL2TransactionTwoBridges for token deposit](./img/requestl2transactiontwobridges_token_deposit.png).
45+
46+
- From L2 to L1
47+
1. The user calls `L2AssetRouter.withdraw(assetId, assetData)` directly. Here, `assetData` varies by Asset Handler; it’s parsed by the handler into the format it requires.
48+
2. The L2 handler burns the tokens, and `L2AssetRouter` sends an L2→L1 message.
49+
3. Once the L2→L1 message arrives on L1, the user calls `finalizeWithdrawal` on `L1AssetRouter`, providing the chain ID where the withdrawal was initiated, the message’s position in that chain, and proof of its inclusion. The `L1Nullifier` contract verifies the proof, and if it’s valid, control returns to `L1AssetRouter`, which then calls the appropriate Asset Handler (based on `assetId`) to release the assets.
50+
51+
### Read more
52+
53+
You can read more in the more in-depth about L1 and L2 asset routers and the default asset handler that is Native Token Vault [here](./asset_router.md).
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!--- WIP --->
2+
<!--- This document will be extended once interop docs come in place --->
3+
4+
# Overview of bridging
5+
6+
## Introduction
7+
8+
ZK Stack chains are launched on L1 into an ecosystem of contracts with the main registry being the [bridgehub](../chain_management/bridgehub.md). The Bridgehub creates an
9+
ecosystem of chains, with shared standards, upgrades. This allows chains to trust each other. The bridging of assets is handled by the [AssetRouter](./asset_router_and_ntv/asset_router.md) and NativeTokenVault contracts.

docs/src/specs/contracts/chain_management/chain_genesis.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Creating new chains with BridgeHub
22

3-
The main contract of the whole hyperchain ecosystem is called _`BridgeHub`_. It contains:
3+
The main contract of the whole ZK Chains ecosystem is called _`BridgeHub`_. It contains:
44

55
- the registry from chainId to CTMs that is responsible for that chainId
66
- the base token for each chainId.
@@ -9,7 +9,7 @@ The main contract of the whole hyperchain ecosystem is called _`BridgeHub`_. It
99
- the whitelist of settlement layers
1010
- etc
1111

12-
BridgeHub is responsible for creating new chains. It is also the main point of entry for L1→L2 transactions for all the chains. Users won't be able to interact with chains directly, all the actions must be done through the BridgeHub, which will ensure that the fees have been paid and will route the call to the corresponding chain. One of the reasons it was done this way was to have the unified interface for all chains that will ever be included in the hyperchain ecosystem.
12+
BridgeHub is responsible for creating new chains. It is also the main point of entry for L1→L2 transactions for all the chains. Users won't be able to interact with chains directly, all the actions must be done through the BridgeHub, which will ensure that the fees have been paid and will route the call to the corresponding chain. One of the reasons it was done this way was to have the unified interface for all chains that will ever be included in the ZK Chains ecosystem.
1313

1414
To create a chain, the `BridgeHub.createNewChain` function needs to be called:
1515

docs/src/specs/contracts/chain_management/chain_type_manager.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ The exact process of deploying & registering a chain can be [read here](./chain_
3030
| Chain parameter | Updatability | Comment |
3131
| --------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3232
| chainId | Permanent | Permanent identifier of the chain. Due to wallet support reasons, for now chainId has to be small (48 bits). This is one of the reasons why for now we’ll deploy chains manually, to prevent them from having the same chainId as some another popular chain. In the future it will be trustlessly assigned as a random 32-byte value. |
33-
| baseTokenAssetId | Permanent | Each chain can have their own custom base token (i.e. token used for paying the fees). It is set once during creation and can never be changed. Note, that we refer to and "asset id" here instead of an L1 address. To read more about what is assetId and how it works check out the document for [asset router][TODO] |
33+
| baseTokenAssetId | Permanent | Each chain can have their own custom base token (i.e. token used for paying the fees). It is set once during creation and can never be changed. Note, that we refer to and "asset id" here instead of an L1 address. To read more about what is assetId and how it works check out the document for [asset router](../bridging/asset_router_and_ntv/asset_router.md) |
3434
| chainTypeManager | Permanent | The CTM that deployed the chain. In principle, it could be possible to migrate between CTMs (assuming both CTMs support that). However, in practice it may be very hard and as of now such functionality is not supported. |
3535
| admin | By admin of chain | The admin of the chain. It has some limited powers to govern the chain. To read more about which powers are available to a chain admin and which precautions should be taken, check [out this document](./admin_role.md) |
3636
| validatorTimelock | CTM | For now, we want all the chains to use the same 3h timelock period before their batches are finalized. Only CTM can update the address that can submit state transitions to the rollup (that is, the validatorTimelock). |

0 commit comments

Comments
 (0)