Validium Docs
  • Overview
  • Connect to Validium
  • Start Coding 🚀
    • Quickstart
      • Overview
      • Deploy using Validium CLI
      • Deploy using Quickstart Repository
      • Deploy your first contract
      • Create an ERC20 token
  • Tooling
    • Block Explorers
    • Hardhat-Validium
      • Overview
      • Installation
      • Guides
        • Getting started
        • Migrating Hardhat project to Validium
        • Compiling non-inlinable libraries
      • Plugins
        • hardhat-zksync
        • hardhat-zksync-solc
        • hardhat-zksync-vyper
        • hardhat-zksync-deploy
        • hardhat-zksync-upgradable
        • hardhat-zksync-verify
        • hardhat-zksync-verify-vyper
        • hardhat-zksync-ethers
        • hardhat-zksync-node
        • Hardhat Community Plugins
    • Foundary
      • Overview
      • Installation
      • Getting Started
      • Migration Guide
        • Overview
        • Compilation
        • Deployment
        • Testing
  • Test and Debug
    • Getting Started
    • Docker L1 - L2 Nodes
    • In-Memory Node
    • Continuous Integration
    • Hardhat
    • Foundry
  • API Reference
    • Overview
    • Conventions
    • ZKs JSON-RPC API
    • Debug JSON-RPC API
    • Ethereum JSON-RPC API
    • PubSub JSON-RPC API
  • Concepts
    • Transaction Lifecycle
    • Blocks and Batches
    • Validium Network Fee Mechanism
    • Finality
    • System Upgrades
    • ZK Chains
    • Data Availability
      • Overview
      • Recreating L2 state from L1 pubdata
      • Validiums
    • Account Abstraction
    • L1 <-> L2 Communication
  • Components
    • Overview
    • Smart & System Contracts
      • Smart Contracts
      • System Contracts
    • Shared Bridges
    • Sequencer / Server
    • Validium Network EVM
      • Overview
      • Bootloader
      • Precompiles
      • Virtual Machine Specification
        • ZKsync Virtual Machine primer
        • VM Formal Specification
    • Prover
      • Overview
      • ZK Terminology
      • Running the Prover
      • Circuits
        • Overview
        • Circuit Testing
        • CodeDecommitter
        • DemuxLogQueue
        • ECRecover
        • KeccakRoundFunction
        • L1MessagesHasher
        • LogSorter
        • Main VM
        • RAMPermutation
        • Sha256RoundFunction
        • StorageApplication
        • Sorting and Deduplicating
          • Overview
          • SortDecommitments
          • StorageSorter
          • LogSorter
      • Boojum Gadgets
      • Boojum Function - `check_if_satisfied`
    • Compiler
      • Compiler Toolchain Overview
        • Compiler Toolchain Overview
        • Solidity Compiler
        • Vyper Compiler
        • LLVM Framework
      • Specification
        • Overview
        • Code Separation
        • System Contracts
        • Exception Handling
        • EVM Legacy Assembly Translator
        • Instructions
          • Instruction Reference
          • EVM
            • Native EVM Instructions
            • Arithmetic
            • Bitwise
            • Block
            • Call
            • Create
            • Environment
            • Logging
            • Logical
            • Memory
            • Return
            • Sha3
            • Stack
          • Extensions
            • Overview
            • Validium Network Extension Simulation (call)
            • Validium Network Extension Simulation (verbatim)
          • EVM Legacy Assembly
          • Yul
        • EraVM Binary Layout
    • Fee Withdrawer
    • Portal - Wallet + Bridge
    • Block Explorer
    • Transaction filtering
Powered by GitBook
On this page
  • Environment setup
  • Run tests with Hardhat
  • Expand test coverage
  • Understanding the test file
  1. Test and Debug

Hardhat

Learn how to test on era-test-node with Hardhat.

PreviousContinuous IntegrationNextFoundry

Last updated 7 months ago


In the world of decentralized applications, the margin for error is remarkably narrow. A single mistake in a contract can have catastrophic implications. For those seeking an efficient method to test and refine their contracts, this guide showcases how to utilize Hardhat and era_test_node for all testing needs.

To test our contract, we are going to use Hardhat and era_test_node for rapid local development. In our tests we're going to use zksync-ethers to interact with the Greeter contract, and we'll use as our test runner.

Prerequisites

  • zksync-cli installed from the .

  • era_test_node installed and running. See .


Environment setup

  1. Create a new project with the required dependencies and boilerplate paymaster implementations:

    zksync-cli create test-greeter

    Choose Hardhat + Solidity to setup the project repository. The contract for this guide exists under /contracts/Greeter.sol. Install dependencies:yarnnpmbun

    yarn install
  2. Add the following additional dependencies:yarnnpmbun

    yarn add -D @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers
  3. Import @nomicfoundation/hardhat-chai-matchers into the hardhat.config.ts file:hardhat.config.ts

    import "@nomicfoundation/hardhat-chai-matchers";

    The @nomicfoundation/hardhat-chai-matchers plugin adds Ethereum specific capabilities to the assertion library for testing smart contracts.

  4. Start era_test_node:

    ./target/release/era_test_node run

Run tests with Hardhat

Under the /test directory there is a main.test.ts . The initial test checks if our Greeter contract returns the set greeting.

/test/main.test.ts

import { expect } from "chai";
import { Wallet, Provider, Contract } from "zksync-ethers";
import * as hre from "hardhat";
import { Deployer } from "@matterlabs/hardhat-zksync";
import { zkSyncTestnet } from "../hardhat.config";

const RICH_WALLET_PK = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";

async function deployGreeter(deployer: Deployer): Promise<Contract> {
  const artifact = await deployer.loadArtifact("Greeter");
  return await deployer.deploy(artifact, ["Hi"]);
}

describe("Greeter", function () {
  it("Should return the new greeting once it's changed", async function () {
    const provider = new Provider(zkSyncTestnet.url);

    const wallet = new Wallet(RICH_WALLET_PK, provider);
    const deployer = new Deployer(hre, wallet);

    const greeter = await deployGreeter(deployer);

    expect(await greeter.greet()).to.eq("Hi");

    const setGreetingTx = await greeter.setGreeting("Hola, mundo!");
    // wait until the transaction is mined
    await setGreetingTx.wait();

    expect(await greeter.greet()).to.equal("Hola, mundo!");
  });
});

To run this test:

yarnnpmbun

yarn test

You should see the following output:

  Greeter
    ✔ Should return the new greeting once it's changed (174ms)

  1 passing (174ms)

Expand test coverage

Our aim is comprehensive coverage. Here are the test scenarios we will cover:

  1. Testing greet() function: Check the returned greeting.

  2. Testing setGreeting() function: Verify the ability to update greetings.

  3. Testing Insufficient Funds: Ensure transactions fail without enough funds.

  4. Event Emission: Ensure an event is emitted when changing the greeting.

Each of these test cases will rely on a common setup, which involves creating a provider connected to the Validium Sepolia Testnet, initializing a wallet with a known private key, and deploying the Greeter contract.

Let's refactor our test file with the provided script:

test/main.test.ts

To run this test:

yarnnpmbun

yarn test

You should see the following output:

  Greeter
    ✔ Should return the new greeting once it's changed (211ms)
    ✔ Should set a new greeting and return it (2682ms)
    ✔ Should fail when insufficient funds (299ms)
    ✔ Should emit an event when the greeting is changed (2939ms)

  4 passing (6s)

Understanding the test file

Have a look at the test/main.test.ts file's imports:

test/main.test.ts

import { expect } from "chai";
import { Wallet, Provider, Contract } from "zksync-ethers";
import * as hre from "hardhat";
import { Deployer } from "@matterlabs/hardhat-zksync";
import { zkSyncTestnet } from "../hardhat.config";

This section imports all necessary utilities and configurations needed to run our tests.

  • expect from Chai provides assertion functionalities for our tests.

  • Wallet, Provider, and Contract from zksync-ethers help us with Validium functionalities like creating wallets and interacting with contracts.

  • hre and Deployer give us hardhat specific functionalities for deploying and interacting with our contract.

  • zkSyncTestnet from our hardhat configuration provides network details of our running era_test_node.

Contract Deployment Utility

async function deployGreeter(deployer: Deployer): Promise<Contract> { ... }

This utility function simplifies deploying the Greeter contract for our tests.

Main Test Suite

describe('Greeter', function () {
  ...
});

Here, we've declared our main test suite. Each test or nested suite inside provides specific scenarios or functionalities we want to test regarding the Greeter contract.

  1. Initialization Before running any test, we initialize commonly used variables like the provider, wallet, deployer, and the greeter contract.

  2. Test greet() function We check that the greet function returns the initial greeting of 'Hi' after deployment.

    it("Should return the new greeting once it's changed", async function () { ... });
  3. Test setGreeting() function We test that setting a new greeting updates the contract's state as expected.

    it("Should set a new greeting and return it", async function () { ... });
  4. Test insufficient funds Here, we simulate a scenario where an empty wallet (with no funds) tries to set a new greeting. We make use of the connect method on your zksync-ethers Contract object to connect it to a different account.

    it("Should fail when insufficient funds", async function () { ... });
  5. Test event emission We test the emission of an event when the greeting changes in the contract making use of the hardhat-chai-matchers.

    it("Should emit an event when the greeting is changed", async function () { ... });
Mocha
zksync-cli section
In-memory Node
Chai