Getting Started with ZK Chains
In this tutorial, you will get familiar with the ZK Inception CLI. You will create a local Elastic Chain ecosystem and deploy a contract to a ZK chain. Next, you will create a new ZK chain that uses a custom ERC20 base token.
What you'll learn:
- How to create and locally run an Elastic Chain ecosystem.
- How to create a ZK chain and deploy a contract to it.
- How to setup a ZK chain with a custom base token.
Tools:
- - zk_inception
- - hardhat
- - cast
- - zksync-cli
- - zksync-ethers
This tutorial shows you how to use the zk_inception
CLI to run an Elastic Chain ecosystem and custom ZK chain locally:
- You'll set up a local Elastic Chain ecosystem
- You'll create a standard ZK chain
- You'll deploy a smart contract to your local ZK chain
- You'll create a second ZK chain that uses a custom ERC20 base token
Prerequisites
- Make sure your machine satisfies the system requirements.
- If you aren't already familiar with deploying smart contracts on ZKsync Era, please refer to the first section of the quickstart tutorial.
- For background on the Elastic Chain or ZK chains, read the ZK chains section in our docs.
- Install the dependencies for the
zksync-era
repo by following the instructions in the matter-labs/zksync-era project's Setup dev guide (you can skip the "Environment" section).
foundry-zksync
installed,
reinstall the normal version of foundry for this tutorial.Installing zk_inception
CLI
To install the CLI globally, run this command in your root folder.
You can use the Rust command cargo
to install the CLI with the command below:
cargo install --git https://github.com/matter-labs/zksync-era/ \
--locked zk_inception --force
zk_inception
CLI in the zksync-era
repo.Setting up the Elastic Chain ecosystem
An Elastic Chain ecosystem is, in short, a system to manage multiple ZK chains. The vision for the Elastic Chain is an ever-expanding network of ZK rollups, secured by math and natively interoperable under a uniform, intuitive UX. New chains can be registered to the ecosystem to scale applications and communities as needed, making it "elastic".
There are two components needed for running a ZK chain locally:
- An Elastic Chain ecosystem to manage different chains
- At least one chain deployed within the ecosystem
To setup both of these components, use the zk_inception
CLI.
The first step is to create a new ecosystem with the ecosystem create
command.
Move to a directory where you want your ecosystem folder to be, and run the command below to generate an ecosystem folder.
zk_inception ecosystem create
You will be prompted with a series of options to customize your ecosystem and generate a new chain within the ecosystem. For this tutorial, use the options shown below. If you choose different names for your ecosystem or chain, remember to update the names in the commands later on.
$ zk_inception ecosystem create
┌ ZKsync toolbox
│
◇ What do you want to name the ecosystem?
│ my_elastic_chain
│
◇ Select the origin of zksync-era repository
│ Clone for me (recommended)
│
◇ Select the L1 network
│ Localhost
│
◇ What do you want to name the chain?
│ zk_chain_1
│
◇ Whats the chain id?
│ 271
│
◇ Select how do you want to create the wallet
│ Localhost
│
◇ Select the prover mode
│ NoProofs
│
◇ Select the commit data generator mode
│ Rollup
│
◇ Select the base token to use
│ Eth
│
◇ Do you want to start containers after creating the ecosystem?
│ Yes
By running this command and selecting these options, you just:
- Created a new ecosystem called
my_elastic_chain
, which can contain many chains. - Cloned the
zksync-era
repository inside themy_elastic_chain
folder. - Chose to use a local network to act as the L1. This means we'll have to run a local reth node as well (don't worry, the CLI will automatically set this up and run it for you!). We need to do this because our ecosystem contracts need to get deployed on an L1, so we can either use a local L1 chain or the Sepolia testnet. For development purposes, it's easier to use a local L1 chain.
- Created a new chain called
zk_chain_1
and set it as your default chain. - Set the chain id to
271
. - Chose the default wallet configuration.
This option will use known mnemonic phrases to generate the
wallets.yaml
configuration files for the ecosystem and chain. You can also chooserandom
to randomly generate the wallets,empty
to generate a config file with empty values for the wallets, orin-file
to set the location of the config to an existing file. - Selected to not use proofs, which makes testing more lightweight.
- Chose a standard rollup for the data availability. You can read more about data availability options for ZK chains in the ZK chains docs.
- Selected ETH to use as the base token.
- Started the containers for the ecosystem in Docker.
Inside the generated my_elastic_chain
folder, you should now have the following contents:
ZkStack.yaml
: a configuration file for the ecosystem.chains
: a folder with configurations for each chain created.configs
: configuration for the deployments and wallets.volumes
: dependencies for running local nodes.zksync-era
: a clone of thezksync-era
repository.docker-compose.yml
: a Docker compose file to start up a local environment.
Deploying the ecosystem
You've just set up your ecosystem and chain, and have two Docker containers running: a postgres database for your chain, and a reth node for the local L1 chain.
The L1 chain is already running, but your ecosystem and chain aren't deployed yet. The next step is to deploy your ecosystem contracts to the L1 and register your chain to the ecosystem.
Move into the ecosystem folder:
cd my_elastic_chain
Next, run the ecosystem init
command below to deploy the ecosystem:
zk_inception ecosystem init --dev
The --dev
flag will choose the default options for development.
This process will take some time as there is a lot happening here.
To see more detailed logs of what is happening at each step, you can add the --verbose
flag to the command.
To summarize, the ecosystem init
command:
- Checks to see if your environment has the necessary dependencies.
- Compiles and deploys all of the necessary contracts for the ecosystem.
- Deploys
zk_chain_1
to the ecosystem. - Sets up a database for the default chain (in this case
zk_chain_1
). - Deploys a paymaster contract and some test ERC20 contracts to use for development.
You can find the paymaster contract code deployed to your chain in the zksync-era
repo in contracts/l2-contracts/contracts/TestnetPaymaster.sol
,
and the deployed address inside <my_elastic_chain>/chains/zk_chain_1/configs/contracts.yaml
at l2:testnet_paymaster_addr
.
For the ERC20 contracts, you can find the deployed addresses inside <my_elastic_chain>/configs/erc20.yaml
.
Understanding the chain configs
Running the init
command will also modify your chain configuration files in the ecosystem folder.
The main configuration file for zk_chain_1
can be found in <my_elastic_chain>/chains/zk_chain_1/ZkStack.yaml
.
It contains the most basic configurations for the chain.
Inside <my_elastic_chain>/chains/zk_chain_1/configs
, you can find six more configuration files:
contracts.yaml
: configurations for all the L1 & L2 contracts.external_node.yaml
: configurations for the chain's node server.general.yaml
: general configurations.genesis.yaml
: chain specific configurations with parameters that were used during genesis.secrets.yaml
: secrets that are individual for every chain.wallets.yaml
: all wallets that you are using for this chain.
Starting the chain server
The last step here is to start a server for zk_chain_1
:
zk_inception server
With this, your L1 chain should be running at port 8545
, and the zk_chain_1
node should be running at port 3050
.
Funding a wallet on your chain
Because you chose to use a local reth node for your L1 and selected ETH as the base asset,
you have access to several rich wallets on the L1 that you can use to bridge ETH to zk_chain_1
.
You can find a full list of rich wallet addresses and their private keys in the ZKsync docs.
Open a new terminal and run the command below to bridge some ETH to zk_chain_1
using ZKsync CLI:
npx zksync-cli bridge deposit --rpc=http://localhost:3050 --l1-rpc=http://localhost:8545
For testing purposes, we'll use one of the rich wallets as both the sender and recipient:
? Amount to deposit 10
? Private key of the sender 0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110
? Recipient address on L2 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049
To see that it worked, let's check the balance of that address on zk_chain_1
:
npx zksync-cli wallet balance \
--address 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 \
--rpc http://localhost:3050
Now this address has ETH available on zk_chain_1
to use for testing.
Deploying a contract to chain 1
Now that your chain is deployed and your wallet is funded, let's create a template contract and deploy it to zk_chain_1
:
Move out of your ecosystem folder and initialize a new hardhat project using ZKsync CLI:
npx zksync-cli@latest create --template zksync-101 zk-chain-test
cd zk-chain-test
Use the same private key for the rich wallet:
? Private key of the wallet responsible for deploying contracts (optional)
0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110
In the hardhat.config.ts
file, change the default network on line 6 to dockerizedNode
,
which is already configured to connect to the local chain node running on port 3050
:
defaultNetwork: "dockerizedNode",
Finally, compile the contract and run the deploy script:
yarn compile && yarn deploy:hello-zksync
Nice - you just deployed a contract to your own local ZK chain!
Next, let's take a look at customizing a chain.