Getting Started
Learn how to setup and use Foundry with your ZKsync project.
Prerequisites
The primary prerequisite for using foundry-zksync
is the Rust Compiler.
Installation Guide
To integrate foundry-zksync
into your projects, you have the flexibility to install its components individually or
the entire suite at once. Follow the steps below to get started:
Step 1: Clone the repository:
git clone git@github.com:matter-labs/foundry-zksync.git
Step 2: Navigate to the project directory:
cd foundry-zksync
Step 3: Run the Installer: Execute the script to install the foundry-zksync binaries forge and cast
./install-foundry-zksync
Once the forge
and cast
binaries are installed, you can start using foundry-zksync
. Source your preferred
profile or refresh your terminal window to activate the changes. You are now ready to begin working with foundry-zksync
.
For component-specific installations from source:
- Forge: To install, execute:
cargo install --path ./crates/forge --profile local --force --locked
- Cast: To install, run:
cargo install --path ./crates/cast --profile local --force --locked
For the entire suite:
- Execute the following command for a comprehensive installation:
cargo build --release
Choose the installation that best fits your development needs.
Configuration
Initial Setup
After installation, initialize a new project with forge init <project_name>
, which sets up the basic structure of a new Foundry project.
Project Configuration using foundry.toml
Foundry is designed to be very configurable.
You can configure Foundry using a file called foundry.toml
in the root of your project, or any other parent directory.
Configuration can be arbitrarily namespaced by profiles. The default profile is named default
.
You can select another profile using the FOUNDRY_PROFILE
environment variable.
You can also override parts of your configuration using FOUNDRY_
or DAPP_
prefixed environment variables, like FOUNDRY_SRC
.
forge init
creates a basic, extendable foundry.toml
file.
To see your current configuration, run forge config
. To see only basic options (as set with forge init
), run forge config --basic
.
This can be used to create a new foundry.toml
file with forge config --basic > foundry.toml
.
By default forge config
shows the currently selected foundry profile and its values.
It also accepts the same arguments as forge build
.
An example foundry.toml
for ZKsync with zksolc configurations may look like:
[profile.default]
src = 'src'
out = 'out'
libs = ['lib']
[profile.zksync]
src = 'src'
libs = ['lib']
fallback_oz = true
is_system = false
mode = "3"
Private key setup with Foundry keystore
Follow these steps to securely store your wallet's private key to use it in Foundry projects:
- Extract Your Private Key: If you are using the local era node, use a private key from the available rich accounts. Otherwise, find your personal wallet's private key. For MetaMask users, here's how to export your wallet's private key.
- Create a Foundry keystore: Create a keystore and import your private key by running
cast wallet import myKeystore --interactive
# enter your PK when prompted, provide a password, and copy the returned address
It'll return an address (keystore address).
myKeystore
is arbitrary and can be updated. For our docs, we've chosen this name for consistency.
If you decide to use another name, be sure to reference it when using cast
.Using the keystore
When running commands that require a private key, like forge create
or cast send
, use --account myKeystore --sender <KEYSTORE_ADDRESS>
. This will
require you to enter the keystore password you provided before.
Basic Usage
Running Tests
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/
.
Usage:
forge build [OPTIONS] --zksync
Key Compiler Options:
--use-zksolc <ZK_SOLC_VERSION>
: Specify the zksolc version or a local zksolc path.--is-system <SYSTEM_MODE>
: Enables system contract compilation mode (true
/false
).--force-evmla <FORCE_EVMLA>
: Switch to the EVM legacy assembly pipeline.--fallback-oz <FALLBACK_OZ>
: Recompile with-Oz
if bytecode is too large.--detect-missing-libraries
: Detect and report missing libraries.-O, --optimization <LEVEL>
: Set LLVM optimization levels.--zk-optimizer
: Optimize specifically for ZKsync.
Example Usage:
Compile with default settings or specify zksolc
version:
forge build --zksync
Deployment with forge create --zksync
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:
--constructor-args <ARGS>
: Specify constructor arguments.--constructor-args-path <FILE>
: File path for constructor arguments.<CONTRACT>
: Contract identifier in<path>:<contractname>
format.--factory-deps <FACTORY-DEPS>
: Specify factory dependencies.
Example:
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
Deploying Factory Contracts
To deploy contracts like GreeterFactory.sol
, use the is-system
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 --is-system=true --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.
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!".