If you are using Windows, we strongly recommend you use Windows Subsystem for Linux (also known as WSL 2). You can use 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.
To create a new project run the zksync-cli create command, passing a project name:
Solidity project
npxzksync-clicreatedemo--templatehardhat_solidity
Vyper project
npxzksync-clicreatedemo--templatehardhat_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.
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 network endpoints of the zkSyncTestnet network change dynamically for local tests.
// dynamically changes endpoints for local testsconstzkSyncTestnet=process.env.NODE_ENV=="test"? { url:"http://localhost:3050", ethNetwork:"http://localhost:8545", zksync:true, }: { url:"https://sepolia.era.zksync.dev", ethNetwork:"sepolia", zksync:true, };
For local Validium testing, modify url and ethNetwork in hardhat.config.ts to align with your local Validium and Ethereum node's L2 and L1 RPC URLs, respectively.This template project includes a basic unit test in the /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.
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.
The artifacts-zk and cache-zk folders are included in the .gitignore file.
The deploy-greeter.ts script is in the deploy folder. This script uses the Deployer class from the hardhat-zksync-deploy package to deploy the Greeter.sol/Greeter.vy contract.
import { Wallet, utils } from"zksync-ethers";import*as ethers from"ethers";import { HardhatRuntimeEnvironment } from"hardhat/types";import { Deployer } from"@matterlabs/hardhat-zksync-deploy";// load env fileimport dotenv from"dotenv";dotenv.config();// load wallet private key from env fileconstPRIVATE_KEY=process.env.WALLET_PRIVATE_KEY||"";if (!PRIVATE_KEY) throw"⛔️ Private key not detected! Add it to the .env file!";// An example of a deploy script that will deploy and call a simple contract.exportdefaultasyncfunction (hre:HardhatRuntimeEnvironment) {console.log(`Running deploy script for the Greeter contract`);// Initialize the wallet.constwallet=newWallet(PRIVATE_KEY);// Create deployer object and load the artifact of the contract you want to deploy.constdeployer=newDeployer(hre, wallet);constartifact=awaitdeployer.loadArtifact("Greeter");// Estimate contract deployment feeconstgreeting="Hi there!";constdeploymentFee=awaitdeployer.estimateDeployFee(artifact, [greeting]);// ⚠️ OPTIONAL: You can skip this block if your account already has funds in L2// const depositHandle = await deployer.zkWallet.deposit({// to: deployer.zkWallet.address,// token: utils.ETH_ADDRESS,// amount: deploymentFee.mul(2),// });// // Wait until the deposit is processed on ZKsync// await depositHandle.wait();// Deploy this contract. The returned object will be of a `Contract` type, similar to ones in `ethers`.// `greeting` is an argument for contract constructor.constparsedFee=ethers.formatEther(deploymentFee);console.log(`The deployment is estimated to cost ${parsedFee} ETH`);constgreeterContract=awaitdeployer.deploy(artifact, [greeting]);// obtain the Constructor Argumentsconsole.log("constructor args:"+greeterContract.interface.encodeDeploy([greeting]));// Show the contract info.constcontractAddress=awaitgreeterContract.getAddress();console.log(`${artifact.contractName} was deployed to ${contractAddress}`);}
2. To execute the deployment script run
yarnhardhatdeploy-zksync--scriptdeploy-greeter.ts
This script deploys the Greeting contract with the message "Hi there!" to Validium Sepolia Testnet.
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 the use-greeter.ts script:use-greeter.ts
import { Provider } from"zksync-ethers";import*as ethers from"ethers";import { HardhatRuntimeEnvironment } from"hardhat/types";// load env fileimport dotenv from"dotenv";dotenv.config();// load contract artifact. Make sure to compile first! - Solidity Projectimport*as ContractArtifact from"../artifacts-zk/contracts/Greeter.sol/Greeter.json";// load contract artifact. Make sure to compile first! - Vyper Project//import * as ContractArtifact from "../artifacts-zk/contracts/Greeter.vy/Greeter.json";constPRIVATE_KEY=process.env.WALLET_PRIVATE_KEY||"";if (!PRIVATE_KEY) throw"⛔️ Private key not detected! Add it to the .env file!";// Address of the contract on Validium testnetconstCONTRACT_ADDRESS="";if (!CONTRACT_ADDRESS) throw"⛔️ Contract address not provided";// An example of a deploy script that will deploy and call a simple contract.exportdefaultasyncfunction (hre:HardhatRuntimeEnvironment) {console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`);// Initialize the provider.// @ts-ignoreconstprovider=newProvider(hre.userConfig.networks?.zkSyncTestnet?.url);constsigner=newethers.Wallet(PRIVATE_KEY, provider);// Initialise contract instanceconstcontract=newethers.Contract(CONTRACT_ADDRESS,ContractArtifact.abi, signer);// Read message from contractconsole.log(`The message is ${awaitcontract.greet()}`);// send transaction to update the messageconstnewMessage="Hello people!";consttx=awaitcontract.setGreeting(newMessage);console.log(`Transaction to change the message is ${tx.hash}`);awaittx.wait();// Read message after transactionconsole.log(`The message now is ${awaitcontract.greet()}`);}
To execute the script, run:
yarnhardhatdeploy-zksync--scriptuse-greeter.ts
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.