ZKsync Gateway settlement layer

ZKsync Gateway is an optional settlement layer for ZKsync chains, including both rollups and validiums. It is purpose-built to enhance interoperability, provide proof aggregation, and offer cost efficiencies for chains that wish to settle on top of it.

Learn more about ZKsync Gateway in the protocol documentation.

Running ZKsync Gateway locally

This guide assumes you already have zkstackup and the required system dependencies installed as detailed in the quickstart.
  1. Update foundry-zksync to use the version from commit 27360d4c8:
    foundryup-zksync -C 27360d4c8
    
  2. Install the latest version of zkstack:
    zkstackup
    
  3. Create a new local ecosystem and chain, and start the containers with Docker running the background:
    zkstack ecosystem create
    
  4. Move into the ecosystem folder and initialize the ecosystem:
    cd <YOUR_ECOSYSTEM>
    zkstack ecosystem init --dev
    
  5. Create a new ZKsync chain that will become your local gateway chain:
    zkstack chain create \
        --chain-name gateway \
        --chain-id 506 \
        --prover-mode no-proofs \
        --wallet-creation localhost \
        --l1-batch-commit-data-generator-mode rollup \
        --base-token-address 0x0000000000000000000000000000000000000001 \
        --base-token-price-nominator 1 \
        --base-token-price-denominator 1 \
        --set-as-default false \
        --evm-emulator false \
        --ignore-prerequisites --update-submodules false
    
  6. Initialize gateway chain:
    zkstack chain init \
      --deploy-paymaster \
      --l1-rpc-url=http://localhost:8545 \
      --server-db-url=postgres://postgres:notsecurepassword@localhost:5432 \
      --server-db-name=zksync_server_localhost_gateway \
      --chain gateway --update-submodules false
    
  7. Setup the transaction filterer for gateway:
    zkstack chain gateway create-tx-filterer --chain gateway --ignore-prerequisites
    
  8. Transform gateway chain from rollup into a ZKsync Gateway settlement layer:
    zkstack chain gateway convert-to-gateway --chain gateway --ignore-prerequisites
    
  9. Start gateway chain server:
    zkstack server --ignore-prerequisites --chain gateway
    

    Or to start the server in the background, use:
    mkdir zlogs
    zkstack server --ignore-prerequisites --chain gateway &> ./zlogs/gateway.log &
    zkstack server wait --ignore-prerequisites --verbose --chain gateway
    
  10. Migrate existing ZKsync chain to settle on gateway:
    zkstack chain gateway migrate-to-gateway --chain <YOUR_CHAIN_NAME> --gateway-chain-name gateway
    
  11. Start your chain server:
    zkstack server --ignore-prerequisites --chain <YOUR_CHAIN_NAME>
    

Your chains will be running on the following ports:

  • Your chain (271 or the chain ID you defined): localhost:3050
  • Gateway (506): localhost:3150

Multichain Local Setup

Once you have completed the steps in the previous section, you may want to test interoperability across different chains. To add an additional chain that settles on Gateway, follow these steps:

  1. Create a new chain. You can change any details about the chain as needed.
    zkstack chain create \
        --chain-name zk_chain_2 \
        --chain-id 5328 \
        --prover-mode no-proofs \
        --wallet-creation localhost \
        --l1-batch-commit-data-generator-mode rollup \
        --base-token-address 0x0000000000000000000000000000000000000001 \
        --base-token-price-nominator 1 \
        --base-token-price-denominator 1 \
        --set-as-default false \
        --evm-emulator true \
        --ignore-prerequisites --update-submodules false
    
  2. Initialize the new chain. Make sure the chain name matches the one you created in the previous step.
    zkstack chain init \
        --deploy-paymaster \
        --l1-rpc-url=http://localhost:8545 \
        --server-db-url=postgres://postgres:notsecurepassword@localhost:5432 \
        --server-db-name=zksync_server_localhost_zk_chain_2 \
        --chain zk_chain_2 \
        --update-submodules false
    
  3. Migrate the new chain to gateway:
    zkstack chain gateway migrate-to-gateway --chain zk_chain_2 --gateway-chain-name gateway
    
  4. Start the new chain server:
    zkstack server --ignore-prerequisites --chain zk_chain_2
    

Now you should have three chains running on the following ports:

  • Your first chain (271 or the chain ID you defined): localhost:3050
  • Gateway (506): localhost:3150
  • zk_chain_2 (5328): localhost:3250

To get funds for testing, you can use the dev rich-account command below to bridge testnet ETH to your new chain:

zkstack dev rich-account --chain zk_chain_2

Migrate existing ZKsync chain to Gateway on testnet or mainnet

ZKsync chains can be migrated to use ZKsync Gateway as their settlement layer by updating the chain's metadata and coordinating the transition with off-chain services. This migration is performed using the zkstack cli tool.

Requirements

In order to migrate a chain, operators will need the following information:

  • Tooling:
    • zkstack CLI
    • Foundry
  • Credentials:
    • Private key of the L2 network chain governor.
  • RPC URLs for all the networks involved:
  • Addresses:
    • L1_BRIDGEHUB_ADDRESS: can be found in the ZKsync chains info page
    • REFUND_RECIPIENT_ADDRESS: address that will receive gas refunds.
    • VALIDATOR_1_ADDRESS: address of the operator.
    • VALIDATOR_2_ADDRESS: address of the blob operator.
    • NEW_SL_DA_VALIDATOR: data availability contract validator deployed on Gateway. See data availability considerations for more info
  • Chain identifiers:
  • ZKsync Gateway configuration: the ZKsync Stack config file for the ZKsync Gateway, which contains relevant information of how the chain operates. This file can be found in the zksync-era repository. Save in etc/ecosystem/gateway/<gateway>.yaml.

Notify server about migration

Pause the ETH transaction sender on the server to avoid having unconfirmed transactions on L1:

zkstack chain gw notify-about-to-gateway-update-calldata \
  <L1_BRIDGEHUB_ADDRESS> \
  <L2_CHAIN_ID> \
  <L1_RPC_URL> \
  --l2-rpc-url=<L2_RPC_URL> \
  --gw-rpc-url=<GATEWAY_RPC_URL>

Send migration calldata on L1

Send the generated migration calldata to L1

cast send <L1_BRIDGEHUB_ADDRESS> <CALLDATA> \
  --rpc-url=<L1_RPC_URL> \
  --private-key=<PRIVATE_KEY>

Generate calldata for migration

The following command will check the status of the migration to Gateway and will only output the calldata after the notification has passed and the server is ready to migrate. To prepare the calldata even before the server is ready (helpful for multisigs), please provide --no-cross-check option. Governor must have enough ZK to top up validators (min-validator-balance).

zkstack chain gw migrate-to-gateway-calldata \
  --l1-rpc-url <L1_RPC_URL> \
  --l1-bridgehub-addr <L1_BRIDGEHUB_ADDRESS> \
  --max-l1-gas-price <MAX_L1_GAS_PRICE> \
  --gateway-chain-id <GATEWAY_CHAIN_ID> \
  --gateway-rpc-url <GATEWAY_RPC_URL> \
  --refund-recipient <REFUND_RECIPIENT_ADDRESS> \
  --l2-chain-id <L2_CHAIN_ID> \
  --l2-rpc-url <L2_RPC_URL> \
  --gateway-config-path <GATEWAY_CONFIG_PATH> \
  --validator-1 <VALIDATOR_1_ADDRESS> \
  --validator-2 <VALIDATOR_2_ADDRESS> \
  --min-validator-balance <MIN_VALIDATOR_BALANCE> \
  --new-sl-da-validator <NEW_SL_DA_VALIDATOR>

This will generate L1 → Gateway transaction. The L2 network server will restart 2 times:

  1. When the gateway status changed on L1.
  2. When the transaction is processed on ZKsync Gateway.

Submit final migration transaction

Send the output calldata from previous step to L1 to confirm migration:

cast send <TO_ADDRESS> <CALLDATA> \
  --rpc-url=<L1_RPC_URL> \
  --private-key=<PRIVATE_KEY>

Verify migration

Check that settlementLayer(chainId) on the Bridgehub contract returns the ZKsync Gateway chain id: 506 (testnet) or 9075 (mainnet).

CLI Reference

For more information about commands and calldata generation details, refer to the official zkstack cli migration guide.


Made with ❤️ by the ZKsync Community