ZKsync Gateway settlement layer

ZKsync Gateway is an optional settlement layer for ZK 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 an ecosystem with a ZK chain settling on L1 as detailed in the quickstart.
  1. Create a new ZK 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
    
  2. Initialise 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
    
  3. Transform gateway chain from rollup into a ZKsync Gateway settlement layer:
    zkstack chain gateway convert-to-gateway --chain gateway --ignore-prerequisites
    
  4. Start gateway chain server:
    mkdir zlogs
    zkstack server --ignore-prerequisites --chain gateway &> ./zlogs/gateway.log &
    
  5. Migrate existing ZK chain to settle on gateway:
    zkstack chain gateway migrate-to-gateway --chain YOUR_CHAIN_NAME --gateway-chain-name gateway
    
  6. Start your chain server:
    zkstack server --ignore-prerequisites --chain YOUR_CHAIN &> ./era.log &
    

Migrate existing ZK chain to Gateway on testnet or mainnet

ZK 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 ZK 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 ZK 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