hardhat-zksync-ethers
Integrate ZKsync with Hardhat using the hardhat-zksync-ethers plugin.
Ensure you are using the correct version of the plugin with ethers:
- For plugin version <1.0.0:
- Compatible with ethers v5.
- For plugin version ≥1.0.0:
- Compatible with ethers v6 (⭐ Recommended)
Prerequisite
To use hardhat-zksync-ethers
in your project, ensure the following:
- Node.js version 18 or higher is installed.
- Hardhat version 2.16.0 or higher is installed as a dependency.
Installation
@matterlabs/hardhat-zksync-ethers
Add the latest version of this plugin to your project with the following command:
yarn add -D @matterlabs/hardhat-zksync-ethers zksync-ethers ethers
Configuration
Import the package in the hardhat.config.ts
file:
import "@matterlabs/hardhat-zksync-ethers";
Tasks
This plugin creates no additional tasks.
Environment extensions
This plugins adds an zksync-ethers object to the Hardhat Runtime Environment.
This object has the same API as zksync-ethers, with some extra Hardhat-specific functionality.
Helpers
Helpers added to zksync-ethers object:
interface FactoryDeps {
// A mapping from the contract hash to the contract bytecode.
[contractHash: string]: string;
}
interface ZkSyncArtifact extends Artifact {
// List of factory dependencies of a contract.
factoryDeps: FactoryDeps;
// Mapping from the bytecode to the ZKsync VM assembly (used for tracing).
sourceMapping: string;
}
interface FactoryOptions {
wallet?: zk.Wallet;
}
function providerL2: () => zk.Provider;
function providerL1: () => ethers.Provider;
function getWallet: (privateKeyOrIndex?: string | number) => zk.Wallet;
function getContractFactory: (name: string, wallet?: zk.Wallet, deploymentType?: DeploymentType) => Promise<zk.ContractFactory>;
function getContractFactory: (abi: any[], bytecode: ethers.BytesLike,wallet?: Wallet,deploymentType?: DeploymentType) => Promise<zk.ContractFactory>;
function getContractFactoryFromArtifact: (artifact: ZkSyncArtifact, wallet?: zk.Wallet, deploymentType?: DeploymentType) => Promise<zk.ContractFactory>;
function getContractAt: (nameOrAbi: string | any[], address: string | Address, wallet?: zk.Wallet) => Promise<zk.Contract>;
function getContractAtFromArtifact: (artifact: ZkSyncArtifact, address: string, wallet?: zk.Wallet) => Promise<zk.Contract>;
function getSigner: (address: string) => zk.Signer;
function getSigners: () => zk.Signer[];
function getImpersonatedSigner: (address: string) => Promise<zk.Signer>;
function extractFactoryDeps: (artifact: ZkSyncArtifact) => Promise<string[]>;
function loadArtifact: (name: string) => Promise<ZkSyncArtifact>;
function deployContract: (artifact: ZkSyncArtifact, constructorArguments: any[], wallet?: zk.Wallet, overrides?: ethers.Overrides, additionalFactoryDeps?: ethers.BytesLike[]) => Promise<zk.Contract>;
providerL2()
- returns azk.Provider
for L2, automatically connected to the selected network.providerL1()
- returns aethers.Provider
for L1, automatically connected to the selected network.getWallet(privateKeyOrIndex?: string | number)
- returnszk.Wallet
for the given private key or index. If the network is set to local and the private key is not provided, the method will return a wallet for rich accounts with the default index of0
or the specified index. If theaccounts
object is set in the hardhat config and the private key is not specified, the method will return the wallet for the given account with the default index0
or for the specified index.getWallets()
- returns all wallets of typezk.Wallet
. If the network is set to local, the method will return wallets for rich accounts. If theaccounts
object is set in the hardhat config for the used network, the method will return the wallets for the provided accounts.getContractFactory(name: string, wallet?: zk.Wallet, deploymentType?: DeploymentType)
- returns azk.ContractFactory
for provided artifact name.getContractFactory: (abi: any[], bytecode: ethers.BytesLike,wallet?: Wallet,deploymentType?: DeploymentType)
- returns a zk.ContractFactory for provided artifact abi and bytecode.getContractFactoryFromArtifact(artifact: ZkSyncArtifact, wallet?: zk.Wallet, deploymentType?: DeploymentType)
- returns azk.ContractFactory
for provided artifact.getContractAt(nameOrAbi: string | any[], address: string | Address, wallet?: zk.Wallet)
- returnszk.Contract
for provided artifact name or abi and address of deployed contractgetContractAtFromArtifact: (artifact: ZkSyncArtifact, address: string, wallet?: zk.Wallet)
- returnszk.ContractFactory
for provided artifact and address of deployed contractgetImpersonatedSigner(address: string)
- impersonateszk.Signer
from addressloadArtifact(name: string)
- loadZkSyncArtifact
from contract nameextractFactoryDeps(artifact: ZkSyncArtifact)
- extracts factory deps from artifact
deployContract(artifact: ZkSyncArtifact, constructorArguments: any[], wallet?: zk.Wallet, overrides?: ethers.Overrides, additionalFactoryDeps?: ethers.BytesLike[])
- deploys contract, for more details check out the deployment section of the quickstart.
- If
wallet?: zk.Wallet
is not provided and if the network is set to local, the default wallet will be the first account in the list of rich accounts. If anaccounts
object is set in the hardhat config for the used network, the default wallet will be taken from that object. - If
deploymentType?: DeploymentType
is not provided default value will becreate
.
Usage
Install it and access zksync-ethers through the Hardhat Runtime Environment anywhere you need it (tasks, scripts, tests, etc). For example:
Task usage:
task("getFeeData", "Returns a fee data.").setAction(async (hre) => {
const feeDataL2 = await hre.zksyncEthers.providerL2.getFeeData();
const feeDataL1 = await this.env.zksyncEthers.providerL1.getFeeData();
return { feeDataL2, feeDataL1 };
});
Script usage:
export default async function (hre: HardhatRuntimeEnvironment) {
console.info(chalk.yellow(`Running deploy`));
//automatically connected to the selected network
const gasPrice = await hre.zksyncEthers.providerL2.send("eth_gasPrice", []);
//getContractFactory with default wallet, deploy contract and set new greeting message
const greeterFactory = await hre.zksyncEthers.getContractFactory("Greeter");
const greeter = await greeterFactory.deploy("Hello, world!");
console.info(chalk.green(`Greeter deployed to: ${await greeter.getAddress()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`));
const tx = await greeter.setGreeting("Hello, world again!");
await tx.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`));
// deploy with provided wallet using loadArtifact and deployContract
const wallet = await hre.zksyncEthers.getWallet("0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110");
console.info(chalk.green(`Wallet address: ${await wallet.getAddress()}`));
// deposit ETH from L1 to L2 to cover costs of deployment
const depositHandle = await wallet.deposit({
to: wallet.address,
token: utils.ETH_ADDRESS,
amount: ethers.parseEther("0.001"),
});
await depositHandle.wait();
const artifact = await hre.zksyncEthers.loadArtifact("Greeter");
const greets = await hre.zksyncEthers.deployContract(artifact, ["Hello, world!"], wallet);
console.info(chalk.green(`Greeter deployed to: ${await greets.getAddress()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`));
}