Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples/contract-verification/ethers-5 examples to the repo #184

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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