Run Prividium Chain
This guide shows you how to use the ZK Stack CLI to run local a Prividium chain. By following this guide you will:
- Set up a local Elastic Network ecosystem
- Create a Prividium chain
- Deploy a smart contract to your chain
- Test interacting with your contract
- Run a local block explorer
Installing ZK Stack CLI
Before getting started, make sure to install all of the dependencies for the zksync-era
repo
by following the instructions in the matter-labs/zksync-era
project's Setup dev guide.
You can use zkstackup
to install and manage zkstack
:
curl -L https://raw.githubusercontent.com/matter-labs/zksync-era/main/zkstack_cli/zkstackup/install | bash
zkstackup
zksync-era
repo.Setting up the Elastic Network ecosystem
The first step is to create a new ecosystem with the zkstack 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.
zkstack 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.
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.
Make sure to have the following ports free:
3050
, 3070
, 4041
, 5432
, and 8545
.
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_network
Next, run the zkstack ecosystem init
command below to deploy the ecosystem:
zkstack ecosystem init --dev --validium-type no-da
Starting the chain server
The last step here is to start a server for prividium_chain
:
zkstack server
With this, your L1 chain should be running at port 8545
,
the prividium_chain
database running at port 5432
,
and the prividium_chain
node running at port 3050
.
Note that the node running at port 3050
provides full access to your chain.
This URL should be kept private.
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 prividium_chain
.
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 prividium_chain
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 prividium_chain
:
npx zksync-cli wallet balance \
--address 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 \
--rpc http://localhost:3050
Now this address has ETH available on prividium_chain
to use for testing.
Deploying a contract
Now that your chain is deployed and your wallet is funded, let's create a template contract and deploy it to prividium_chain
:
Move out of your ecosystem folder and initialize a new hardhat project using ZKsync CLI:
npx zksync-cli create prividium-token --template hardhat_solidity --project contracts
cd prividium-token
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, let's configure the local network as the default:
defaultNetwork: "dockerizedNode",
Note that this will connect hardhat to your standard full-access RPC API, which allows you to deploy contracts.
Finally, compile the contracts and run the deploy script for the ERC20 token contract:
npm run deploy-erc20
Save the deployed contract address for later.
Proxy RPC API
To initialize the Proxy API service, open a new terminal in your ecosystem folder and run:
zkstack private-rpc init
You can select the default options for the prompts.
This command will generate two files:
- A private proxy
docker-compose
file at/chains/prividium_chain/configs/private-proxy-docker-compose.yml
- An example permissions config file at
/chains/prividium_chain/configs/private-rpc-permissions.yaml
.
Next, you can start the Proxy API service with:
zkstack private-rpc run
The Proxy API should now be running at port 4041
.
Configuring access
The permissions config file at
/chains/prividium_chain/configs/private-rpc-permissions.yaml
can be edited based on what access you want end users to have.
There are two sections in the permissions file:
groups
: Logical collections of users or addresses sharing the same permissions.contracts
: Specific contracts or methods that a group is allowed to access.
Groups Access
You can define hard-coded groups of administrative addresses in the groups
section.
A group consists of a name and a list of member addresses.
After defining a group,
the group name can be used in the contracts
section to grant the entire group certain access.
Contracts Access
The contracts
section defines the level of access available to specific contracts and their functions.
If a contract is not included here, or a function not defined,
it can only be accessed via the standard RPC API.
Note that contracts can only be deployed via the standard RPC API.
Defining Methods
For a given contract address, the methods
field defines the contract functions that can be called.
The function signature is used to identify functions and define rules for them. The format should the same signature as the canonical signature defined in Solidity ABI.
To generate a list of your contract's functions in this format,
you can use the formatAbiItem
method from abitype
,
as shown in the example script below.
import ABI_JSON from '../artifacts-zk/contracts/erc20/MyERC20Token.sol/MyERC20Token.json';
import { type AbiFunction, formatAbiItem } from 'abitype';
async function main() {
const { abi } = ABI_JSON;
abi.forEach((item) => {
if (item.type === 'function') {
const signature = formatAbiItem(item as AbiFunction);
console.log(signature);
}
});
}
Method Access
For each function, you can define a rule for read
and write
regardless of whether the function itself is a pure function.
For each rule within a read
or write
section,
you must choose a type
.
The types available out-of-the-box include:
public
: anyone can call this function.closed
: no one can call this function (default).group
: only the specified groups can call this.checkArgument
: the specified argument index must match the function caller's address.oneOf
: allows you to define more than one rule type. It functions as anOR
operator; if at least one condition is met, access is granted.
In addition to these rules,
there is a universal rule applied
so that users can only see transactions where
their address is equal to the msg.sender
.
You can fully customize the types and their access logic by editing the zksync-era/private-rpc/src/permissions/yaml-parser.ts
file.
ERC-20 Config
Replace the generated access config with the one below:
Then replace <0xYOUR_CONTRACT_ADDRESS>
with the deployed ERC-20 contract address.
Note that the transfer
and approve
methods are marked as public
,
however this doesn't mean that anyone can see the details of these transactions.
This is because for these methods, the private proxy RPC API validates that current user is equal to the msg.sender
in the transactions.
To apply changes to the permissions file, you will need to restart the Proxy API. If your config file isn't correctly configured, the API won't start.
Interacting With the contract
Make a new file in the scripts
folder called priv-interact.ts
and copy/paste the script below:
This script:
- Registers the deployer address as a user
- Uses the generated user token to access the Proxy RPC API
- Sends tokens from the deployer address to another address
There is no method available to fetch a token that was previously generated. If you generate a user token and it's forgotten, you can simply generate a new token.
Before running, update your .env
file with the RECIPIENT_ADDRESS
and CONTRACT_ADDRESS
.
Use the deployed ERC20 contract address for CONTRACT_ADDRESS
,
and any other wallet address for the recipient.
Choose an address you also have the private key for.
Then, run the interact script with:
npx hardhat run ./scripts/priv-interact.ts
Note that the user will be able to see their own balance, but not the balance of the recipient wallet.
If you try to access the balance from a different wallet (or without a wallet), you will see an Unauthorized
error.
Checking balance
Make a new file called check-balance.ts
in the scripts folder
and copy/paste the script below.
This script just checks the ERC20 balance of the default wallet.
To check the balance of another address,
you must register a user token for that address,
update the private key in your .env
file,
and then run the check-balance
script.
Before running, update your .env
file with the USER_TOKEN
obtained during the previous step.
You can run the script with:
npx hardhat run ./scripts/check-balance.ts
Block explorer
The next step is to set up the block explorer and contract verifier service.
Start the contract verifier
The contract verifier is used to check contract source code against deployed bytecode. This is going to be used in the explorer to display the source code and ABIs of contracts.
In a new terminal run:
zkstack contract-verifier init \
--zksolc-version v1.5.6 \
--zkvyper-version v1.5.10 \
--solc-version 0.8.24 \
--era-vm-solc-version 0.8.28-1.0.2 \
--vyper-version v0.4.1
This will download the needed binaries for verifying contracts on the block explorer.
Next, run:
zkstack contract-verifier run
Once this is done you are going to have the verifier running on port 3070
.
Setting up a block explorer
In a new terminal run:
zkstack explorer init --prividium
You can select the default options in the prompts.
This command creates a database to store explorer data and generates a docker compose file with explorer services
at prividium_chain/configs/explorer-docker-compose.yml
.
Next, you need to start the explorer backend services:
zkstack explorer backend
This command uses the previously created docker compose file to start the services required for the explorer.
Finally, in a new terminal you can run the explorer app:
zkstack explorer run
This command will start the dockerized explorer app using configuration from apps/explorer.config.json
file inside
your ecosystem directory. You can edit this file to configure the app if needed.
You can now navigate to the explorer web-app. By default, the explorer frontend starts on
http://127.0.0.1:3010
, you can configure the port in apps.yaml
file.
Switching to an internal explorer
To switch between the public-facing Prividium block explorer and a standard full-access block explorer for internal use:
- Stop the explorer frontend.
- Stop the explorer backend.
- Run
zkstack explorer init
and selectNo
when prompted to use the Prividium explorer. - Restart the explorer backend and frontend services.
Right now both versions of the explorer can't be run at the same time with zkstack
,
but it's possible to configure this manually.
To switch back to a Prividium block explorer, re-run the steps from "Setting up a block explorer".
Using the Block Explorer
To use the public-facing Prividium block explorer, users must first sign in with their wallet. The block explorer then provides the configured level of access based on their account.
Restarting your Chain
If at some point during development you wish to stop and restart your chain, here are the complete steps for restarting.
To restart the chain and RPC APIs, go to the ecosystem folder and:
- Run
zkstack containers
to restart the L1 and postgres Docker containers. If you have deleted the containers, go through the initial ecosystem setup steps again. - Run
zkstack server
to start the standard RPC API. - In a new terminal, start the proxy RPC API with
zkstack private-rpc run
. - In a new terminal, start the contract verifier with
zkstack contract-verifier run
. - In another terminal, start the explorer backend with
zkstack explorer backend
. - In another terminal, start the explorer frontend with
zkstack explorer run
.
Next Steps
To see a full example application running on Prividium, check out this example escrow application.