Skip to content

Commit

Permalink
feat: introducing hardhat zksync-ethers sdk helpers and ethers extens…
Browse files Browse the repository at this point in the history
…ion in hre
  • Loading branch information
kiriyaga committed Aug 21, 2024
2 parents 6eb4584 + 3511fb3 commit d888309
Show file tree
Hide file tree
Showing 45 changed files with 2,666 additions and 4 deletions.
4 changes: 4 additions & 0 deletions .github/release-please/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
"release-type": "node",
"component": "@matterlabs/hardhat-zksync-upgradable"
},
"packages/hardhat-zksync-ethers": {
"release-type": "node",
"component": "@matterlabs/hardhat-zksync-ethers"
},
"packages/hardhat-zksync": {
"prerelease-type": "beta",
"prerelease": true,
Expand Down
3 changes: 2 additions & 1 deletion .github/release-please/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"packages/hardhat-zksync-deploy": "0.11.0-beta.1",
"packages/hardhat-zksync-upgradable": "0.5.2-beta.1",
"packages/hardhat-zksync": "0.2.0-beta.1"
"packages/hardhat-zksync": "0.2.0-beta.1",
"packages/hardhat-zksync-ethers": "0.1.0-beta.1"
}
43 changes: 42 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,18 @@ jobs:
pnpm hardhat run scripts/upgrade-factory-beacon.ts
pnpm hardhat run scripts/upgrade-factory-uups.ts
pnpm hardhat run scripts/upgrade-factory.ts
- name: Test zksync-ethers example
run: |
cd examples/zksync-ethers-example
pnpm hardhat compile
pnpm hardhat deploy-zksync
- name: Show logs
if: always()
run: |
cat server.log

upgradable:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -143,4 +151,37 @@ jobs:
- name: Show logs
if: always()
run: |
cat server.log
cat server.log
zksync-ethers:
runs-on: ubuntu-latest
name: zksync-ethers
steps:
- uses: actions/checkout@v3

- uses: actions/checkout@v3
with:
repository: matter-labs/local-setup
path: local-setup

- name: Run server
run: |
cd local-setup
./start.sh &>../server.log &
- uses: pnpm/action-setup@v3

- uses: actions/setup-node@v3
with:
node-version: "18"
cache: pnpm

- name: Setup environment
run: |
pnpm install
pnpm build
- name: Wait until server is up
run: |
while ! curl -s -X POST -d '{"jsonrpc":"2.0","method":"net_version","id":1}' -H 'Content-Type: application/json' 0.0.0.0:3050; do sleep 1; done
- name: Test zksync ethers plugin
run: |
cd packages/hardhat-zksync-ethers
pnpm test
1 change: 1 addition & 0 deletions .github/workflows/npm-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ on:
options:
- hardhat-zksync-deploy
- hardhat-zksync-upgradable
- hardhat-zksync-ethers
- hardhat-zksync

jobs:
Expand Down
7 changes: 7 additions & 0 deletions examples/zksync-ethers-example/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: [`${__dirname}/../../config/eslint/eslintrc.cjs`],
parserOptions: {
project: `${__dirname}/tsconfig.json`,
sourceType: "module",
},
};
3 changes: 3 additions & 0 deletions examples/zksync-ethers-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cache
artifacts
contracts/tmp
61 changes: 61 additions & 0 deletions examples/zksync-ethers-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# ZKsync Era zksync-ethers environment example

This project demonstrates how to compile and deploy your contracts in ZKsync Era using the Hardhat plugins.

## Prerequisites

- node.js 14.x or later.
- yarn.

## Configuration

Plugin configuration is located in [`hardhat.config.ts`](./hardhat.config.ts).
You should only change the ZKsync network configuration.

`hardhat.config.ts` example with ZKsync network configured with the name `zkTestnet` and `sepolia` used as the underlying layer 1 network:
```ts
import "@matterlabs/hardhat-zksync-deploy";
import { HardhatUserConfig } from 'hardhat/types';

const config: HardhatUserConfig = {
networks: {
sepolia: {
url: 'https://sepolia.infura.io/v3/<API_KEY>' // you can use either the URL of the Ethereum Web3 RPC, or the identifier of the network (e.g. `mainnet` or `rinkeby`)
},
zkTestnet: {
url: 'https://sepolia.era.zksync.dev', // you should use the URL of the ZkSync network RPC
ethNetwork: 'sepolia',
zksync: true
},
}
};

export default config;
```

## Usage

Before using plugins, you need to build them first

```sh
# Run the following in the *root* of the repo.
yarn
yarn build
```

After that you should be able to run plugins:

```sh
# Run the following in `examples/ethers-example` folder.
yarn
yarn hardhat compile
yarn hardhat deploy-zksync
```

- `yarn hardhat compile`: compiles all the contracts in the `contracts` folder.
- `yarn hardhat deploy-zksync`: runs all the deploy scripts in the `deploy` folder.
- To run a specific script, add the `--script` argument, e.g. `--script 001_deploy.ts`.
- To run on a specific ZKsync network, use standard hardhat `--network` argument, e.g. `--network zkTestnet`
(with `zkTestnet` network specified in the `hardhat.config` networks section, with the `zksync` flag set to `true` and `ethNetwork` specified).

If you don't specify ZKsync network (`--network`), `local-setup` with <http://localhost:8545> (Ethereum RPC URL) and <http://localhost:3050> (ZKsync RPC URL) will be used.
19 changes: 19 additions & 0 deletions examples/zksync-ethers-example/contracts/Greeter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v2;

contract Greeter {
string greeting;
constructor(string memory _greeting) {
greeting = _greeting;
}

function greet() public view returns (string memory) {
return greeting;
}

function setGreeting(string memory _greeting) public {
greeting = _greeting;
}
}
49 changes: 49 additions & 0 deletions examples/zksync-ethers-example/deploy/001_deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import chalk from 'chalk';
import { Wallet } from 'zksync-ethers';

export default async function (hre: HardhatRuntimeEnvironment) {
console.info(chalk.yellow(`Running deploy`));
const wallet = await hre.zksyncEthers.getWallet(4);

// console.info(chalk.yellow(`Depositing to wallet: ${await wallet.getAddress()}`));
// 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 with loadArtifact!'], wallet);
const wallet1 = greets.signer as Wallet;
console.info(chalk.yellow(`Deploying Greeter with wallet: ${await wallet1.getAddress()}`));
console.info(chalk.green(`Greeter deployed to: ${greets.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`));
const tx1 = await greets.setGreeting('Hello, world again with loadArtifact!');
await tx1.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`));

const greeterFactory = await hre.zksyncEthers.getContractFactory(artifact.abi, artifact.bytecode);
const greeter = await greeterFactory.deploy('Hello, world with abi and bytecode!');
const wallet2 = greeter.signer as Wallet;
console.info(chalk.yellow(`Deploying Greeter with wallet: ${await wallet2.getAddress()}`));
console.info(chalk.green(`Greeter deployed to: ${greeter.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`));
const tx = await greeter.setGreeting('Hello, world again with abi and bytecode!');
await tx.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`));

const greeterFactoryFromName = await hre.zksyncEthers.getContractFactory(
'Greeter',
await hre.zksyncEthers.getWallet('0xbe79721778b48bcc679b78edac0ce48306a8578186ffcb9f2ee455ae6efeace1'),
);
const greeterFromName = await greeterFactoryFromName.deploy('Hello, world with name!');
const wallet3 = greeterFromName.signer as Wallet;
console.info(chalk.yellow(`Deploying Greeter with wallet: ${await wallet3.getAddress()}`));
console.info(chalk.green(`Greeter deployed to: ${greeterFromName.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greeterFromName.greet()}`));
const tx2 = await greeter.setGreeting('Hello, world again with name!');
await tx2.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`));
}
99 changes: 99 additions & 0 deletions examples/zksync-ethers-example/deploy/002_deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import chalk from 'chalk';
import { Signer } from 'ethers';

export default async function (hre: HardhatRuntimeEnvironment) {
console.info(chalk.yellow(`Running deploy script 002_deploy.ts`));

// Deploy Greeter contract with provided signer and name
const signer = await hre.ethers.getSigner('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049');
const greets = await hre.ethers.deployContract('Greeter', ['Hello, world with loadArtifact!'], signer);
await greets.deployed();
const greetsRunner = greets.signer as Signer;
console.info(chalk.green(`Greeter deployed to: ${greets.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`));
const tx1 = await greets.setGreeting('Hello, world again with loadArtifact!');
await tx1.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greetsRunner.getAddress()}`));

console.log('----------------------------------');

console.log('Greeter contract deployed with name factory');
const greeterFactory1 = await hre.ethers.getContractFactory('Greeter', signer);
const greets2 = await greeterFactory1.deploy('Hello, world with name!');
await greets2.deployed();
const greets2Runner = greets2.signer as Signer;
console.info(chalk.green(`Greeter deployed to: ${greets2.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets2.greet()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets2Runner.getAddress()}`));

console.log('----------------------------------');

console.log('Greeter contract deployed with abi and bytecode');
const artifact = await hre.artifacts.readArtifact('Greeter');
const greeterFactory2 = await hre.ethers.getContractFactory(artifact.abi, artifact.bytecode);
const greets3 = await greeterFactory2.deploy('Hello, world with abi and bytecode!');
await greets3.deployed();
const greets3Runner = greets3.signer as Signer;
console.info(chalk.green(`Greeter deployed to: ${greets3.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets3.greet()}`));
const tx = await greets3.setGreeting('Hello, world again with abi and bytecode!');
await tx.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greets3.greet()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets3Runner.getAddress()}`));

console.log('----------------------------------');

console.log('Greeter contract deployed with artifact');
const greeterFactory3 = await hre.ethers.getContractFactoryFromArtifact(artifact);
const greets4 = await greeterFactory3.deploy('Hello, world with artifact!');
await greets4.deployed();
const greets4Runner = greets4.signer as Signer;
console.info(chalk.green(`Greeter deployed to: ${greets4.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets4.greet()}`));
const tx2 = await greets4.setGreeting('Hello, world again with artifact!');
await tx2.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greets4.greet()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets4Runner.getAddress()}`));

console.log('----------------------------------');

console.log('Greeter contract deployed with factory and signer2');
const [, , signer2] = await hre.ethers.getSigners();
const greeterFactory4 = await hre.ethers.getContractFactory('Greeter', signer2);
const greets5 = await greeterFactory4.deploy('Hello, world with name!');
await greets5.deployed();
const greets5Runner = greets5.signer as Signer;
console.info(chalk.green(`Greeter deployed to: ${greets5.address}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets5.greet()}`));
const tx3 = await greets5.setGreeting('Hello, world again with name!');
await tx3.wait();
console.info(chalk.green(`Greeter greeting set to: ${await greets5.greet()}`));
console.info(chalk.green(`Greeter greeting set to: ${await greets5Runner.getAddress()}`));

console.log('----------------------------------');

console.log('Greeter get contract with name');
const signer3 = hre.ethers.provider.getSigner('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049');
const contract1 = await hre.ethers.getContractAt('Greeter', greets2.address, signer3);
const contract1Runner = contract1.signer as Signer;
console.info(chalk.green(`Greeter from getContractAt set to: ${await contract1.greet()}`));
console.info(chalk.green('Runner from getContractAt set to: ', await contract1Runner.getAddress()));

console.log('----------------------------------');

console.log('Greeter get contract with abi');
const contract2 = await hre.ethers.getContractAt(artifact.abi, greets3.address);
console.info(chalk.green(`Greeter from getContractAt set to: ${await contract2.greet()}`));
const contract2Runner = contract2.signer as Signer;
console.info(chalk.green('Runner from getContractAt set to: ', await contract2Runner.getAddress()));

console.log('----------------------------------');

console.log('Greeter get contract with artifact');
const contract3 = await hre.ethers.getContractAtFromArtifact(artifact, greets4.address);
console.info(chalk.green(`Greeter from getContractAt set to: ${await contract3.greet()}`));
const contract3Runner = contract3.signer as Signer;
console.info(chalk.green('Runner from getContractAt set to: ', await contract3Runner.getAddress()));
}
32 changes: 32 additions & 0 deletions examples/zksync-ethers-example/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import '@matterlabs/hardhat-zksync-deploy';
import '@matterlabs/hardhat-zksync-solc';
import '@matterlabs/hardhat-zksync-ethers';

import { HardhatUserConfig } from 'hardhat/config';

const config: HardhatUserConfig = {
zksolc: {
compilerSource: 'binary',
settings: {
enableEraVMExtensions: true,
optimizer: {
enabled: true,
},
}
},
defaultNetwork: 'zkSyncLocal',
networks: {
zkSyncLocal: {
zksync: true,
url: "http://0.0.0.0:3050",
ethNetwork: 'http://0.0.0.0:8545',
},
},
// Docker image only works for solidity ^0.8.0.
// For earlier versions you need to use binary releases of zksolc.
solidity: {
version: '0.8.17',
},
};

export default config;
Loading

0 comments on commit d888309

Please sign in to comment.