Getting Started

Learn how to setup and use Foundry with your ZKsync project.

Basic Usage

Testing

Use forge test --zksync to run tests written for your smart contracts.

For an overview of how to write tests using foundry-zksync please refer to Foundry testing here.

Deploying Smart Contracts with forge

Compilation with forge build --zksync

forge build --zksync is used for compiling smart contracts into ZKsync VM bytecode. The compiled files are stored in a structured directory at <PROJECT-ROOT>/zkout/.

Command:

forge build [OPTIONS] --zksync

Options:

To get the list of all build options run:

forge build --help

Besides standard options from original Foundry, there are ZKsync specific set of options:

  • --zk-startup[=<ENABLE_ZKVM_AT_STARTUP>] Enable zkEVM at startup.
  • --zk-compile[=<COMPILE_FOR_ZKVM>] Compile for zkEVM.
  • --zk-solc-path <ZK_SOLC_PATH> Solc compiler path to use when compiling with zksolc.
  • --zk-enable-eravm-extensions[=<ENABLE_ERAVM_EXTENSIONS>] Enable the system contract compilation mode.
  • --zk-force-evmla[=<FORCE_EVMLA>] Forcibly switch to the EVM legacy assembly pipeline.
  • --zk-llvm-options <LLVM_OPTIONS> ZkSolc extra LLVM options.
  • --zk-fallback-oz[=<FALLBACK_OZ>] Try to recompile with -Oz if the bytecode is too large.
  • --zk-detect-missing-libraries Detect missing libraries, instead of erroring.
  • -O, --zk-optimizer-mode <LEVEL> Set the LLVM optimization parameter -O[0 | 1 | 2 | 3 | s | z]. Use 3 for best performance and z for minimal size.
  • --zk-optimizer Enables optimizations.
  • --zk-avoid-contracts <AVOID_CONTRACTS> Contracts to avoid compiling on ZKsync.

Examples:

Compile with default settings or specify zksolc version:

forge build --zksync

Deployment with forge create --zksync

Command:

forge create <CONTRACT> [OPTIONS] --zksync
The following commands make use of Foundry keystore instead of private keys. Learn how to create a foundry keystore.

forge create --zksync deploys smart contracts to ZKsync.

Usage:

forge create <CONTRACT> [OPTIONS] --rpc-url <RPC-URL> --chain <CHAIN-ID> --account myKeystore --sender <KEYSTORE_ADDRESS> --zksync

Options: To get the list of all create options run:

forge create --help

Examples: Deploy Greeter.sol to ZKsync Sepolia Testnet:

Click to view the `Greeter.sol` contract
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }
}
forge create src/Greeter.sol:Greeter --constructor-args "Hello ZKsync" --account myKeystore --sender <KEYSTORE_ADDRESS> --rpc-url https://sepolia.era.zksync.dev --chain 300 --zksync

Verifying Contracts with forge

You can verify your contracts on the ZKsync block explorer using forge by specifying the zksync verifier and the appropriate verifier-url. Here's an example command:

forge create src/Greeter.sol:Greeter \
  --constructor-args "Hello ZKsync" \
  --account myKeystore \
  --sender <KEYSTORE_ADDRESS> \
  --rpc-url https://sepolia.era.zksync.dev \
  --chain 300 \
  --verifier zksync \
  --verifier-url https://explorer.sepolia.era.zksync.dev/contract_verification \
  --verify \
  --zksync

Deploying Factory Contracts

To deploy contracts like GreeterFactory.sol, use the --zk-enable-eravm-extensions flag.

Click to view the `GreeterFactory.sol` contract
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./Greeter.sol";

contract Factory {
    Greeter[] public GreeterArray;

    function CreateNewGreeter(string memory _greeting) public {
        Greeter greeter = new Greeter(_greeting);
        GreeterArray.push(greeter);
    }

    function gfSetter(uint256 _greeterIndex, string memory _greeting) public {
        Greeter(address(GreeterArray[_greeterIndex])).setGreeting(_greeting);
    }

    function gfGetter(uint256 _greeterIndex) public view returns (string memory) {
        return Greeter(address(GreeterArray[_greeterIndex])).greet();
    }
}

Compile GreeterFactory.sol:

forge build --zk-enable-eravm-extensions --zksync

Deploy GreeterFactory.sol:

forge create src/GreeterFactory.sol:Factory --factory-deps src/Greeter.sol:Greeter --account myKeystore --sender <KEYSTORE_ADDRESS> --rpc-url https://sepolia.era.zksync.dev --chain 300 --zksync

Deploy Greeter.sol via GreeterFactory.sol:

cast send <FACTORY_ADDRESS> "CreateNewGreeter(string)" "ZKsync Rules"  --account myKeystore --sender <KEYSTORE_ADDRESS> --rpc-url https://sepolia.era.zksync.dev --chain 300

Interact with Greeter.sol

cast call <CONTRACT_ADDRESS> "greet()(string)" --rpc-url https://sepolia.era.zksync.dev --chain 300

Output:

0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000

To decode the output to a readable string:

cast to-ascii  0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000

Output:

ZKsync Rules

Basic ZKsync Chain Interactions with cast

Introduction

This guide introduces you to fundamental interactions within the ZKsync chain using cast, a component of the foundry-zksync toolkit. Learn how to query chain IDs, retrieve client versions, check L2 ETH balances, obtain gas prices, and more.

Command:

cast <subcommand>

Chain ID Retrieval

  • Local Node:
    Retrieve the Chain ID for a local ZKsync node with:
    cast chain-id --rpc-url http://localhost:3050
    

    Expected Output: 270, indicating the Chain ID of your local ZKsync node.
  • ZKsync Sepolia Testnet:
    For the ZKsync Sepolia Testnet, use:
    cast chain-id --rpc-url https://sepolia.era.zksync.dev
    

    Expected Output: 300, the Chain ID for the ZKsync Sepolia Testnet.

Client Version Information

Knowing the client version is vital for compatibility checks and debugging:

cast client --rpc-url https://sepolia.era.zksync.dev

Expected Output: ZKsync/v2.0, denoting the client version.

L2 Balance Check

Verify the Layer 2 (L2) balance of an account:

cast balance 0x8b1d48a69ACEbC6eb201e2F4d162A002203Bfe8E --rpc-url https://sepolia.era.zksync.dev

Expected Output: A numerical value, e.g., 774909739323110932, representing the account's L2 balance.

Current Gas Price

Fetch the current gas price on the network for transaction cost estimations:

cast gas-price --rpc-url https://sepolia.era.zksync.dev

Expected Output: A value such as 100000000, indicating the current gas price.

Latest Block Details

Gain insights into the latest block on the ZKsync chain:

cast block latest --rpc-url https://sepolia.era.zksync.dev

Expected Output: Detailed information about the latest block, including base fee per gas, gas limit, block hash, and more.

Sending Transactions

Initiate transactions, such as contract function calls, using cast:

cast send <CONTRACT_ADDRESS> <FUNCTION_SIGNATURE> <ARGUMENTS> --rpc-url <RPC-URL> --account myKeystore --sender <KEYSTORE_ADDRESS> --chain <CHAIN-ID>

Example:

cast send 0xe34E488C1B0Fb372Cc4a5d39219261A5a6fc7996 "setGreeting(string)" "Hello, ZKsync!" --rpc-url https://sepolia.era.zksync.dev --account myKeystore --sender <KEYSTORE_ADDRESS> --chain 300

This command calls the setGreeting function of a contract, updating the greeting to "Hello, ZKsync!".

Support

If you're having an issues creating Foundry ZKsync project, please check out list of issues in foundry-zksync github issues page or reach out to us by creating a GitHub discussion.


Made with ❤️ by the ZKsync Community