Getting started
Hardhat
and Hardhat ZKsync plugins
without it, but it will work better if you use it.To install Node.js using WSL 2, please read this guide.Hardhat is an Ethereum development environment, designed for easy smart contract development. One of its most prominent features is extendability: you can easily add new plugins to your hardhat project.
Along with the official plugins, there are other plugins from the community that you can use with ZKsync Era.
To learn more about Hardhat itself, check out the official documentation.
This tutorial shows you how to setup a ZKsync Era Solidity project with Hardhat using the ZKsync CLI.
If you are using Vyper, check out the Vyper plugin documentation or the vyper-example in GitHub!
Project setup
To create a new project run the zksync-cli create
command, passing a project name:
Solidity project
npx zksync-cli create demo --template hardhat_solidity
Vyper project
npx zksync-cli create demo --template hardhat_vyper
This command creates a demo
folder and clones a Hardhat template project inside it.
The downloaded project is already configured and contains all the required plugins.
Hardhat configuration
The hardhat.config.ts
file contains some ZKsync Era specific configurations:
The ZKsync Era deployment and compiler plugin imports:
Solidity project
import '@matterlabs/hardhat-zksync';
The zksolc
block contains the minimal configuration for the compiler.
zksolc: {
version: 'latest', // Uses latest available in https://github.com/matter-labs/zksolc-bin
settings: {},
},
Vyper project
import '@nomiclabs/hardhat-vyper';
import '@matterlabs/hardhat-zksync-vyper';
import '@matterlabs/hardhat-zksync-node';
import '@matterlabs/hardhat-zksync-deploy';
The zkvyper
block contains the minimal configuration for the compiler.
zkvyper: {
version: 'latest', // Uses latest available in https://github.com/matter-labs/zkvyper-bin
settings: {},
},
Network
The default network is set to zkSyncSepoliaTestnet
, but mainnet and local test node networks are also configured.
defaultNetwork: 'zkSyncSepoliaTestnet',
networks: {
zkSyncSepoliaTestnet: {
url: 'https://sepolia.era.zksync.dev',
ethNetwork: 'sepolia',
zksync: true,
verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification',
},
zkSyncMainnet: {
url: 'https://mainnet.era.zksync.io',
ethNetwork: 'mainnet',
zksync: true,
verifyURL: 'https://zksync2-mainnet-explorer.zksync.io/contract_verification',
},
dockerizedNode: {
url: 'http://localhost:3050',
ethNetwork: 'http://localhost:8545',
zksync: true,
},
inMemoryNode: {
url: 'http://127.0.0.1:8011',
ethNetwork: 'localhost', // in-memory node doesn't support eth node; removing this line will cause an error
zksync: true,
},
hardhat: {
zksync: true,
},
},
/test
folder that runs with the local-setup and can be executed with yarn test
.Set your Private Key
Rename .env.example
to .env
and set your private key:
WALLET_PRIVATE_KEY=YourPrivateKeyHere
Your private key will be used for paying the costs of deploying the smart contract.
Compile and deploy a contract
Smart contracts belong in the contracts
folder.
1. To compile the contract, run
npm run compile
You'll see the following output:
Compiling 1 Solidity file
Successfully compiled 1 Solidity file
// Successfully compiled 1 Vyper file - Vyper project
✨ Done in 1.09s.
The artifacts-zk
and cache-zk
folders appear in the root directory (instead of the regular Hardhat's artifacts
and cache
).
These folders contain the compilation artifacts (including contract's ABIs) and compiler cache files.
artifacts-zk
and cache-zk
folders are included in the .gitignore
file.In the deploy
folder, the deploy.ts
script shows an example of how to deploy the Greeter.sol
/Greeter.vy
contract.
import { deployContract } from './utils';
// An example of a basic deploy script
// It will deploy a Greeter contract to selected network
// as well as verify it on Block Explorer if possible for the network
export default async function () {
const contractArtifactName = 'Greeter';
const constructorArguments = ['Hi there!'];
await deployContract(contractArtifactName, constructorArguments);
}
2. To execute the deployment script run
npm run deploy
This script deploys the Greeting
contract with the message "Hi there!" to ZKsync Sepolia Testnet.
You should see something like this:
Running deploy script for the Greeter contract
The deployment is estimated to cost 0.00579276320831943 ETH
constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000
Greeter was deployed to 0x46f1d2d8A16DBD8b47e9D61175a826ac667288Be4D1293a22E8
✨ Done in 12.69s.
Congratulations! You have deployed a smart contract project to ZKsync Sepolia Testnet with Hardhat 🎉
- This message is caused by using the default RPC endpoints provided by ethers.
- To avoid this, use your own Sepolia RPC endpoint in the
hardhat.config.ts
file. - Find multiple node providers here.
Interact with the contract
The template project contains another script to interact with the contract.
- Enter the address of the deployed Greeter contract in the
CONTRACT_ADDRESS
variable of theinteract.ts
script:interact.tsimport * as hre from 'hardhat'; import { getWallet } from './utils'; import { ethers } from 'ethers'; // Address of the contract to interact with const CONTRACT_ADDRESS = ''; if (!CONTRACT_ADDRESS) throw '⛔️ Provide address of the contract to interact with!'; // An example of a script to interact with the contract export default async function () { console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`); // Load compiled contract info const contractArtifact = await hre.artifacts.readArtifact('Greeter'); // Initialize contract instance for interaction const contract = new ethers.Contract( CONTRACT_ADDRESS, contractArtifact.abi, getWallet() // Interact with the contract on behalf of this wallet ); // Run contract read function const response = await contract.greet(); console.log(`Current message is: ${response}`); // Run contract write function const transaction = await contract.setGreeting('Hello people!'); console.log(`Transaction hash of setting new message: ${transaction.hash}`); // Wait until transaction is processed await transaction.wait(); // Read message after transaction console.log(`The message now is: ${await contract.greet()}`); }
- To execute the script, run:
npm run interact
The script will:- Retrieve the message from the contract by calling the
greet()
method. - Update the greeting message in the contract with the
setGreeting()
method. - Retrieve the message from the contract again.
You should see something like this:Running script to interact with contract Greeter The message is Hello there! Transaction to change the message is 0x12f16578A16DB0f47e9D61175a823ac214288Af The message now is Hello people! ✨ Done in 14.32s.
- Retrieve the message from the contract by calling the
Learn more
- To learn more about the ZKsync Hardhat plugins check out the plugins documentation.
- If you want to know more about how to interact with ZKsync using Javascript,
check out the
zksync-ethers
Javascript SDK documentation.