Skip to content

Commit

Permalink
Add examples/contract-verification/ethers-5 examples to the repo (#184)
Browse files Browse the repository at this point in the history
This PR adds usage of `@tenderly/hardhat-tenderly` with the `ethers-5` structure project to `examples/contract-verification/ethers-5`.
  • Loading branch information
dule-git committed Feb 23, 2024
1 parent 8717587 commit 2485b9c
Show file tree
Hide file tree
Showing 55 changed files with 7,153 additions and 42 deletions.
6 changes: 6 additions & 0 deletions .changeset/tiny-steaks-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@tenderly/hardhat-tenderly": patch
"tenderly": patch
---

Added hardhat example project for ethers-5 and changed AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG to TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG
7 changes: 7 additions & 0 deletions examples/contract-verification/ethers-v5/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: [`${__dirname}/../../../config/eslint/eslintrc.js`],
parserOptions: {
project: `${__dirname}/tsconfig.json`,
sourceType: "module"
},
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.DS_Store

node_modules
# Logs
logs
*.log
Expand Down Expand Up @@ -59,6 +58,7 @@ typechain-types
cache
artifacts
deployments
.openzeppelin

# ts
dist
Expand Down
File renamed without changes.
106 changes: 106 additions & 0 deletions examples/contract-verification/ethers-v5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Hardhat + Tenderly Contract Verification

This repo demonstrates deployment and verification of Smart Contracts in Tenderly platform, using:

- **Tenderly Hardhat plugin** to perform verification using Ethers in several ways (automatic and manual). There are 18 different possibilities you can play around with.

To learn more explore [Tenderly documentation](https://docs.tenderly.co/monitoring/smart-contract-verification).

# The examples

There are two example contracts (`Greeter` and `Calculator`). Their build scripts are located in:

- `scripts/greeter/`, deploying the classical Greeter contract.
- `scripts/calculator`, deploying `Calculator` and `Maths` - a library used by the contract.

From these examples, you can learn:

- How to verify a Smart Contract referencing a non-deployed library: Greeter uses **non-deployed** `hardhat/console.log`.
- How to verify a Smart Contract referencing an library deployed on-chain: Calculator uses **deployed** `Maths.sol` library.

# Environment setup

This example requires some environment variables:

- The **provider access** and **tenderly access** parameters should be placed in an .env file.
- Run configuration should be set on per-run basis. This allows us to run the same deployment script in public and private mode or on a fork, without changing any code. These values are used only in `hardhat.config.ts`. See [Building and verifying](#building-and-verifying-greeter-and-environment-variables) section for more information.

Run the following script to to get an `.env` file initialized with placeholders, necessary for running the examples:

```bash
cat tpl.env
cp tpl.env .env
```

To get going, run

```
yarn install
```

Try running automatic verification:

```bash
TENDERLY_AUTOMATIC_VERIFICATION=true \
hardhat run scripts/greeter/automatic.ts --network sepolia
```

## Building and Verifying Greeter and environment variables

The `/scripts/greeter` contains 4 deployment scripts that illustrate the 3 approaches of verification (automatic, manual simple, manual advanced) and verification of a contract deployed on a Tenderly Fork. The `scripts/calculator` example has the same structure.

| Verification method | Script |
| ---------------------- |--------------------------------------|
| Automatic verification | `scripts/greeter/automatic.ts` |
| Manual simple | `scripts/greeter/manual-simple.ts` |
| Manual advanced | `scripts/greeter/manual-advanced.ts` |
| Fork | `scripts/greeter/fork.ts` |

For example, to run the automatic verification example, you have to run it with [`TENDERLY_AUTOMATIC_VERIFICATION`](#modes-of-verification-public-private-and-fork) variable:

```bash
TENDERLY_AUTOMATIC_VERIFICATION=true \
hardhat run scripts/greeter/automatic.ts --network sepolia
```

And to run the manual simple with private verification, you would paste this:

```
TENDERLY_PRIVATE_VERIFICATION=true \
TENDERLY_AUTOMATIC_VERIFICATION=false \
hardhat run scripts/greeter/manual-simple.ts --network sepolia
```

Don't worry, we generated [Run scripts](#run-scripts) to speed things up.

### Modes of verification: `public`, `private`, and `fork`

- To easily switch between private and public verification use `TENDERLY_PRIVATE_VERIFICATION`.
- Default: `false`, contracts are verified publicly.
- To run a private verification set `TENDERLY_PRIVATE_VERIFICATION=true`. Any other value is considered not true.

### Tenderly Plugin verification approaches: automatic and manual

- Tenderly Hardhat plugin runs with automatic verifications **enabled by default** unless explicitly configured otherwise.
- To control if you're automatic or manual verification, use `TENDERLY_AUTOMATIC_VERIFICATION`.
- By default, the `TENDERLY_AUTOMATIC_VERIFICATION` will not be set, so the automatic verification won't be turned on.
- To run an automatic verification set `TENDERLY_AUTOMATIC_VERIFICATION=true`

## Run scripts

The pre-populated (generated) scripts in package.json are there to help you quickly run a particular build (out of 18 possibilities), so you don't need to specify environment variables and the target deployment script every time you're trying stuff out.

You can choose

| category | Meaning | options |
| --------- | -------------------------------------- | ----------------------------------------------- |
| `example` | Smart contract to verify | `greeter`, `calculator` |
| `mode` | In one of 3 modes of verification | `public`, `private`, `fork` |
| `method` | Using one of 3 methods of verification | `automatic`, `manual-simple`, `manual-advanced` |

To run `private` verification of the `Greeter` using `manual-simple` method, you need to run the following:

```
yarn run private:greeter:manual-simple --network sepolia
yarn run fork:calculator:manual-advanced --network tenderly
```
39 changes: 39 additions & 0 deletions examples/contract-verification/ethers-v5/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as dotenv from "dotenv";
import { HardhatUserConfig } from "hardhat/types/config";

import "@nomicfoundation/hardhat-toolbox";
import * as tdly from "@tenderly/hardhat-tenderly";

dotenv.config();

const { TENDERLY_PRIVATE_VERIFICATION, TENDERLY_AUTOMATIC_VERIFICATION } =
process.env;

const privateVerification = TENDERLY_PRIVATE_VERIFICATION === "true";
const automaticVerifications = TENDERLY_AUTOMATIC_VERIFICATION === "true";

tdly.setup({ automaticVerifications });

console.log("Using private verification?", privateVerification);
console.log("Using automatic verification?", automaticVerifications);

const config: HardhatUserConfig = {
solidity: "0.8.23",
networks: {
tenderly: {
url: `${process.env.TENDERLY_FORK_RPC_URL ?? ""}`,
},
sepolia: {
url: `${process.env.SEPOLIA_URL ?? ""}`,
accounts: [process.env.SEPOLIA_PRIVATE_KEY ?? ""],
},
},
tenderly: {
project: process.env.TENDERLY_PROJECT ?? "",
username: process.env.TENDERLY_USERNAME ?? "",
privateVerification,
},
};

// eslint-disable-next-line import/no-default-export
export default config;
65 changes: 65 additions & 0 deletions examples/contract-verification/ethers-v5/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "hardhat-project",
"license": "SEE LICENSE IN LICENSE",
"files": [
"LICENSE"
],
"scripts": {
"lint:fix": "yarn run prettier --write && yarn run eslint --fix",
"eslint": "eslint 'scripts/**/*.ts'",
"prettier": "prettier \"**/*.{js,md,json}\"",
"build": "tsc -b",
"public:greeter:automatic": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/greeter/automatic.ts",
"public:greeter:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-simple.ts",
"public:greeter:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-advanced.ts",
"public:calculator:automatic": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/calculator/automatic.ts",
"public:calculator:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-simple.ts",
"public:calculator:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-advanced.ts",
"private:greeter:automatic": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/greeter/automatic.ts",
"private:greeter:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-simple.ts",
"private:greeter:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-advanced.ts",
"private:calculator:automatic": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/calculator/automatic.ts",
"private:calculator:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-simple.ts",
"private:calculator:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=true TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-advanced.ts",
"fork:greeter:automatic": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/greeter/automatic.ts",
"fork:greeter:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-simple.ts",
"fork:greeter:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/greeter/manual-advanced-fork.ts",
"fork:calculator:automatic": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=true npx hardhat run scripts/calculator/automatic.ts",
"fork:calculator:manual-simple": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-simple.ts",
"fork:calculator:manual-advanced": "TENDERLY_PRIVATE_VERIFICATION=false TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/calculator/manual-advanced-fork.ts"
},
"devDependencies": {
"@types/node": "^20.5.7",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"eslint": "^8.23.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.7.1",
"ts-node": "^10.9.1"
},
"dependencies": {
"@ethersproject/abi": "5.7.0",
"@ethersproject/providers": "^5.7.2",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.1.8",
"@tenderly/hardhat-tenderly": "^1.8.0",
"@typechain/ethers-v5": "^10.2.1",
"@typechain/hardhat": "^6.1.6",
"@types/chai": "^4.2.0",
"@types/mocha": ">=9.1.0",
"chai": "^4.2.0",
"dotenv": "^16.0.1",
"ethers": "^5.7.2",
"global": "^4.4.0",
"global-tunnel-ng": "^2.7.1",
"hardhat": "^2.19.0",
"hardhat-gas-reporter": "^1.0.8",
"solidity-coverage": "^0.8.1",
"typechain": "^8.3.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ export async function main() {
},
// solidity format compiler with a little modification at libraries param
compiler: {
version: "0.8.17",
version: "0.8.23",
settings: {
optimizer: {
enabled: false,
runs: 200,
},
evmVersion: "paris",
libraries: {
"contracts/libraries/Maths.sol": {
// WARNING: Beware of the addresses parameter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ export async function main() {
},
// solidity format compiler with a little modification at libraries param
compiler: {
version: "0.8.17",
version: "0.8.23",
settings: {
optimizer: {
enabled: false,
runs: 200,
},
evmVersion: "paris",
libraries: {
"contracts/libraries/Maths.sol": {
// WARNING: Beware of the addresses parameter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// File: scripts/maths/maths-deployment-ethers.ts
import { ethers } from "hardhat";

export async function deployMaths() {
console.log("📐[ethers] Deploying Maths library");

const Maths = await ethers.getContractFactory("Maths");
let maths = await Maths.deploy();
maths = await maths.deployed();

console.log("📐[ethers] {Maths} deployed to", await maths.address);

return maths.address;
}

export async function deployCalculator(mathsAddress: string) {
console.log("🧮[ethers] Deploying Calculator smart contract");
const Calculator = await ethers.getContractFactory("Calculator", {
libraries: {
Maths: mathsAddress,
},
});

let calculator = await Calculator.deploy();
calculator = await calculator.deployed();

console.log(
"🧮[ethers] {Calculator} deployed to",
await calculator.address,
);
return calculator.address;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// File: scripts/greeter/automatic.ts
import { ethers } from "hardhat";

export async function main() {
console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");

const Greeter = await ethers.getContractFactory("Greeter");
let greeter = await Greeter.deploy("Hello, Hardhat!");

greeter = await greeter.deployed();

const greeterAddress = await greeter.address;
console.log("{Greeter} deployed to", greeterAddress);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { readFileSync } from "fs";
import { network, ethers, tenderly } from "hardhat";
import { HttpNetworkConfig } from "hardhat/types";

export async function main() {
const forkID =
`${(network.config as HttpNetworkConfig).url}`.split("/").pop() ?? "";

console.log("🖖🏽[ethers] Deploying and Verifying Greeter in Tenderly");

const Greeter = await ethers.getContractFactory("Greeter");
let greeter = await Greeter.deploy("Hello, Manual Hardhat on Fork !");
greeter = await greeter.deployed();

const greeterAddress = await greeter.address;
console.log("Manual Advanced (fork): {Greeter} deployed to", greeterAddress);

await tenderly.verifyForkMultiCompilerAPI(
{
contracts: [
{
contractToVerify: "Greeter",
sources: {
"contracts/Greeter.sol": {
name: "Greeter",
code: readFileSync("contracts/Greeter.sol", "utf-8").toString(),
},
"hardhat/console.sol": {
name: "console",
code: readFileSync(
"node_modules/hardhat/console.sol",
"utf-8",
).toString(),
},
},
// solidity format compiler with a little modification at libraries param
compiler: {
version: "0.8.23",
settings: {
optimizer: {
enabled: false,
runs: 200,
},
evmVersion: "paris",
},
},
networks: {
[forkID]: {
address: greeterAddress,
},
},
},
],
},
process.env.TENDERLY_PROJECT ?? "",
process.env.TENDERLY_USERNAME ?? "",
forkID,
);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Loading

0 comments on commit 2485b9c

Please sign in to comment.