Hello ZKsync!

Learn to deploy smart contracts efficiently in the ZKsync environment.

Welcome to ZKsync 101 for deploying smart contracts on ZKsync! In this series, we'll walk you through the process of creating and deploying a simple smart contract that creates a crowdfunding campaign for Zeek. In this section you will learn how to:

Craft a smart contract to fund Zeek's latest adventure.

Deploy the contract onto your local in-memory anvil-zksync node.

Interact with the contract with ZKsync CLI

Let's dive in and start your developer journey on ZKsync!


This series requires some initial setup of tools to enhance your development experience building for ZKsync. Make sure to go through the setup provided in the initial Getting started section.

Compile the CrowdfundingCampaign.sol contract

To compile and deploy to ZKsync you can use either EVM or EraVM:

Learn more about using EraVM vs. EVM bytecode.

Compile the CrowdfundingCampaign.sol contract

This guide introduces a crowdfunding campaign contract aimed at supporting Zeek's creative ventures. Let's start by reviewing the starter contract CrowdfundingCampaign.sol in the contracts/1-hello-zksync/CrowdfundingCampaign.sol directory.

The CrowdfundingCampaign contract is designed for a simple crowdfunding campaign. This contract features:

  • A constructor to initialize the campaign's funding target.
  • The contribute method to log funds, triggering ContributionReceived and GoalReached events.
  • The withdrawFunds method, allowing the owner to collect accumulated funds post-goal achievement.
  • The getTotalFundsRaised method to return the total amount of funds that's been raised.
  • The getFundingGoal method to return the goal for the campaign to reach.
npm run compile

Upon successful compilation, you'll receive output detailing the typings and Solidity files compiled.

Generating typings for: 20 artifacts in dir: typechain-types for target: ethers-v6
Successfully generated 78 typings!
Compiled 20 Solidity files successfully

The compiled artifacts will be located in the /artifacts folder.

Run a local node

For this section, we will deploy to a local Hardhat node. Run the command below to start a persistent in-memory node:

npx hardhat node

Configuring a Hardhat Wallet

Since we are using a local Hardhat in-memory node for development, we can use one of the rich wallets for transactions and deployments.

Copy one of the private keys logged after starting the node to the .env file, using the .env.example file as an example.

Deploy the contract

The deployment script is located at /deploy/1-hello-zksync/deploy.ts.

Key Components:

  • contractArtifactName: Identifies the CrowdfundingCampaign contract for deployment.
  • constructorArguments: Sets initialization parameters for the contract. In this case, the fundraising goal, converted from ether to wei to match Solidity's uint256 type.

Execute the deployment command from package.json.

npm run deploy:hello-zksync

Upon successful deployment, you'll receive output showing the contract name and address.

Deploying CrowdfundingCampaign contract to localhost
CrowdfundingCampaign deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3

Interact with the contract

Now that our contract is deployed to our local in-memory node, let's interact with it! We initially set up the crowdfunding campaign with an amount of .02 ETH for the goal.

Interact with contract

Let's try interacting with the deployed contract.

In the deploy/1-hello-zksync/interact.ts script, use your deployed contract address for the CONTRACT_ADDRESS variable.

Then, run the script:

npm run interact:hello-zksync

Congratulations! You've deployed a crowdfunding contract and learned how to interact with the deployed contract using Hardhat!

Compile the CrowdfundingCampaign.sol contract

This guide introduces a crowdfunding campaign contract aimed at supporting Zeek's creative ventures. Let's start by reviewing the starter contract CrowdfundingCampaign.sol in the contracts/1-hello-zksync/CrowdfundingCampaign.sol directory.

The CrowdfundingCampaign contract is designed for a simple crowdfunding campaign. This contract features:

  • A constructor to initialize the campaign's funding target.
  • The contribute method to log funds, triggering ContributionReceived and GoalReached events.
  • The withdrawFunds method, allowing the owner to collect accumulated funds post-goal achievement.
  • The getTotalFundsRaised method to return the total amount of funds that's been raised.
  • The getFundingGoal method to return the goal for the campaign to reach.

Run the compile script from your project in the terminal:

npm run compile

Upon successful compilation, you'll receive output detailing the zksolc and solc versions used during compiling and the number of Solidity files compiled.

Compiling contracts for ZKsync Era with zksolc v1.5.13 and solc v0.8.17
Compiling 15 Solidity files
Successfully compiled 15 Solidity files

The compiled artifacts will be located in the /artifacts-zk folder.

Smart contracts deployed to ZKsync must be compiled using our custom compiler. zksolc is the compiler used for Solidity. This is why they're placed in the artifacts-zk folder!

Setup local node

This series of guides will use in-memory anvil-zksync node which allows for quicker testing and debugging processes. A great benefit of using a local node is that you will avoid incurring any actual transaction costs as the node provides a set of rich wallets that come with more than enough ETH to use for development.

anvil-zksync can be used with EraVM or EVM. For EVM contracts, you can also use any standard EVM local node like anvil.

Run a local node

To run a local in-memory anvil-zksync node on your machine, you will need Docker running. The easiest way to start Docker is to run the Docker Desktop app.

We are going to use the "in-memory node" module for our local node setup.

  1. Run the following command in your terminal:
    zksync-cli dev config
    

    It will provide a list of available node types you can run locally.
  2. Use the arrow keys to navigate to "in-memory node" and press Enter to select. The next question will ask what additional modules you want to use. Make sure additional modules are unselected for this setup and press Enter to finish the configuration.
    ? Node to use (Use arrow keys)
     in-memory node - Quick startup, no persisted state, only L2 node - zkcli-in-memory-node
      Dockerized node - Persistent state, includes L1 and L2 nodes - zkcli-dockerized-node
    (Move up and down to reveal more choices)
    

    The in-memory node module will run a lighter version of the ZKsync Era node which is ideal for swift testing, prototyping, bootloader and system contract testing.
  3. Run the following command in your terminal to start up the node:
    zksync-cli dev start
    

    anvil-zksync node includes pre-configured rich wallets for use, see anvil-zksync rich wallets.

Your anvil-zksync node is accessible at http://127.0.0.1:8011, ready for deployment or testing purposes. You can use the Docker Desktop app to view logs from the running ZKsync Era node or use the zksync-cli dev logs command.

When you are done running your anvil-zksync node, you can stop it with zksync-cli dev stop. You can learn more about managing a local node with ZKsync CLI on Running a node.

Configuring a Hardhat Wallet

Since we are using a local in-memory anvil-zksync node for development, we can use one of the rich wallets for transactions and deployments.

Copy the private key for the first rich wallet from .env.example to the .env file.

Never save a real private key to the .env file!

Deploy the contract

The deployment script is located at /deploy/1-hello-zksync/deploy.ts.

Key Components:

  • contractArtifactName: Identifies the CrowdfundingCampaign contract for deployment.
  • constructorArguments: Sets initialization parameters for the contract. In this case, the fundraising goal, converted from ether to wei to match Solidity's uint256 type.

Execute the deployment command from package.json.

npm run deploy:hello-zksync

Upon successful deployment, you'll receive output detailing the deployment process, including the contract address, source, and encoded constructor arguments:

Starting deployment process of "CrowdfundingCampaign"...
Estimated deployment cost: 0.0065057128 ETH

"CrowdfundingCampaign" was successfully deployed:
 - Contract address: 0x26b368C3Ed16313eBd6660b72d8e4439a697Cb0B
 - Contract source: contracts/1-hello-zksync/CrowdfundingCampaign.sol:CrowdfundingCampaign
 - Encoded constructor arguments: 0x00000000000000000000000000000000000000000000000000470de4df820000

Interact with the contract

Now that our contract is deployed to our local in-memory node, let's interact with it! We initially set up the crowdfunding campaign with an amount of .02 ETH for the goal.

Read from the contract using ZKsync CLI

We can confirm the amount by calling the getFundingGoal method using ZKsync CLI.

In the terminal, run the following in your project directory, replacing the contract address with your contract's address:

zksync-cli contract read \
--chain in-memory-node \
--contract <0xYOUR_CONTRACT_ADDRESS> \
--abi artifacts-zk/contracts/1-hello-zksync/CrowdfundingCampaign.sol/CrowdfundingCampaign.json

The CLI will prompt you with a list of available methods to select from. Navigate with the arrow keys and press Enter on the method getFundingGoal().

Using provided ABI file
? Contract method to call (Use arrow keys)
  ──────────────── Provided contract ────────────────
 getFundingGoal() view returns (uint256)
  getTotalFundsRaised() view returns (uint256)
  owner() view returns (address)
  ───────────────────────────────────────────────────
  Type method manually
  • The --chain option defines the network we want to use, which is our local in-memory node.
  • The --contract is the address of the contract you just deployed.
  • The --abi provides the ABI to decode the contract and provide the list of methods to select from. Without the ABI provided, you will have to manually type out the method name.

You will get a response with the amount that we passed in to the constructor on deploy:

? Contract method to call getFundingGoal() view returns (uint256)

 Method response (raw): 0x00000000000000000000000000000000000000000000000000470de4df820000
 Decoded method response: 20000000000000000

Write to the contract using ZKsync CLI

Let's fund this crowdfunding campaign and make Zeek happy!

We will write to the contract using ZKsync CLI, which requires a private key. In this demonstration we will use the second wallet provided in the list of rich wallets.

In the terminal, run the following command with your deployed contract's address:

zksync-cli contract write \
--chain in-memory-node \
--contract <0xCONTRACT_ADDRESS> \
--abi artifacts-zk/contracts/1-hello-zksync/CrowdfundingCampaign.sol/CrowdfundingCampaign.json \
--pk <0xDEPLOYER_PRIVATE_KEY> \
--value 0.5

In the prompt, press Enter on the contribute() payable method. The CLI will then output the transaction information upon success.

We can read the transaction data of the contribution with the following:

zksync-cli transaction info \
--tx <0xTRANSACTION_HASH> \
--chain in-memory-node

Our crowdfund has reached its funding goal! Let's withdraw the funds for the owner:

zksync-cli contract write \
--chain in-memory-node \
--contract <0xCONTRACT_ADDRESS> \
--pk <0xDEPLOYER_PRIVATE_KEY>

The CLI will prompt for the method to call, we will call withdrawFunds():

? Enter method to call withdrawFunds()

Congratulations! You've deployed a crowdfunding contract and learned how to interact with the deployed contract using ZKsync CLI!

Takeaways

  • EVM Compatibility: ZKsync is EVM compatible and you can write smart contracts in Solidity or Vyper.
  • Custom Compilation: Contracts deployed to ZKsync are compiled using zksolc or zkvyper as they generate a special bytecode for ZKsync's ZKEVM.
  • Development Tools: in-memory anvil-zksync node is a quick and easy local node environment to deploy to, saving costs on deployment while developing.
  • ZKsync CLI: A powerful command line tool to interact with contracts easily.

Next steps

Having successfully deployed your first contract on ZKsync, you're well on your way to becoming a proficient ZKsync developer. To expand your expertise:

  • Explore Contract Factories: Enhance your project by building a contract factory for the CrowdfundingCampaign contract in the next guide. This will allow you to efficiently manage multiple crowdfunding campaigns, each with their own unique parameters.
  • Dive Deeper into ZKsync Features: Investigate advanced ZKsync features such as account abstraction, and paymasters.
  • Join the Community: Engage with the ZKsync developer community through forums, Discord channels, Dev Discussions, or GitHub repositories. Share your experiences, ask questions, and collaborate on projects.

Made with ❤️ by the ZKsync Community