Custom Base Tokens

You can customize your ZK chain by changing the base token used for gas from ETH to an ERC20 token.

With the initial release of ZK stack, custom ERC20 base tokens must be added to an allowlist for use as a base token for a chain. The allowed addresses for all ERC20 tokens that can be used as a base token for a ZK chain are stored in the BridgeHub contract on the L1.

In the future it will be possible to add a new token in a permissionless process. For now, you have the ability to add any tokens to the allowlist in your local ecosystem.

Custom Base Token Setup

The overall flow for setting up a local chain with a custom ERC20 base token looks like the following:

  1. Deploy an ERC20 token to the L1.
  2. Create your new chain that uses the ERC20 token and set it as the default.
    • When you set up your chain, you will be asked for the nominator and denominator for your base token.
    • The base token nominator and denominator are used to define the relationship of the base token price with ETH.
    • For example, if you set the nominator to 20 and the denominator to 1, together the relation is 20/1. This would mean that 20 tokens would be given the equivalent value as 1 ETH for gas.
  3. Send ERC20 tokens to both the ecosystem and chain governor addresses on the L1.
    • You can find the addresses for the governor in <YOUR_ECOSYSTEM_DIRECTORY>/configs/wallets.yaml and <YOUR_ECOSYSTEM_DIRECTORY>/chains/<YOUR_CHAIN_NAME>/configs/wallets.yaml under governor.
    • See the example below for how to do this using the cast CLI:
    cast send <0xYOUR_TOKEN_ADDRESS> "transfer(address,uint256)" \
    <0x_YOUR_GOVERNOR_ADDRESS> 1000000000000000000 \
    --private-key <0x_YOUR_PRIVATE_KEY> \
    --rpc-url http://localhost:8545 \
    --gas-price 30000000000
    
  4. Initialize the new chain in the ecosystem.
  5. Bridge tokens from the L1 to your new chain.
    • You can use ZKsync CLI to bridge the tokens:
    zksync-cli bridge deposit --token <0x_YOUR_TOKEN_ADDRESS> \
    --rpc=http://localhost:3050 \
    --l1-rpc=http://localhost:8545
    

When you bridge the ERC20 token to your ZK chain, the token resolves to the same address used for ETH on a standard ZK chain:

const L2_BASE_TOKEN_ADDRESS = '0x000000000000000000000000000000000000800a';

If you want to check the balance of your bridged tokens with ZKsync CLI, you don't need to input the token address.

zksync-cli wallet balance --address <0x_YOUR_ADDRESS> --rpc http://localhost:3050

Restarting a custom base token chain

To run your custom ZK chain again after setting up and shutting it down, follow the steps below:

  1. If you shut down your local L1 node that had your ERC20 token deployed to it:
    • Redeploy your ERC20 contract to the L1.
    • Update the base token address in <YOUR_ECOSYSTEM_DIRECTORY>/chains/<YOUR_CHAIN_NAME>/configs/contracts.yaml under l1.base_token_addr and in <YOUR_ECOSYSTEM_DIRECTORY>/chains/<YOUR_CHAIN_NAME>/ZkStack.yaml under base_token.address.
    • Send ERC20 tokens to both the ecosystem and chain governor addresses on the L1.
  2. Initialize the chain in the ecosystem
  3. Start the chain server with zk_inception server.
  4. Bridge ERC20 tokens from the L1 to L2.

Bridging ETH to your chain

If you try to bridge regular ETH to a chain with a custom base token, the ETH will be bridged to a different token contract address.

To get the token address for ETH on your chain, you can pass the ETH_ADDRESS_IN_CONTRACTS constant to the l2TokenAddress method from zksync-ethers.

import { ETH_ADDRESS_IN_CONTRACTS } from "zksync-ethers/build/utils.js";

const l2ETHAddress = await wallet.l2TokenAddress(ETH_ADDRESS_IN_CONTRACTS);

Made with ❤️ by the ZKsync Community