Skip to content
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,7 @@ test/hardhat-ethers-project/artifacts
test/hardhat-ethers-project/cache
test/hardhat-waffle-project/artifacts
test/hardhat-waffle-project/cache
test/hardhat-viem-project/artifacts
test/hardhat-viem-project/cache
dist/

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import "hardhat-gas-reporter"

**Looking for buidler-gas-reporter docs?** [They moved here...][1]

> **Note:** If you import `@nomicfoundation/hardhat-toolbox-viem` in the config, make sure to put it after importing `hardhat-gas-reporter`.

## Configuration
Configuration is optional.
```js
Expand Down
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@
"@nomiclabs/hardhat-truffle5": "^2.0.0",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@nomicfoundation/hardhat-viem": "^1.0.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.9",
"@nomicfoundation/hardhat-toolbox-viem": "^1.0.0",
"@types/chai": "^4.2.14",
"@types/fs-extra": "^5.0.4",
"@types/mocha": "7",
"@types/node": "^8.10.38",
"@types/chai-as-promised": "^7.1.7",
"chai": "^4.2.0",
"dotenv": "^6.2.0",
"ethereum-waffle": "^3.2.1",
Expand All @@ -52,8 +56,10 @@
"tslint": "^5.16.0",
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.0.1",
"typescript": "4.7.4",
"web3": "^1.3.0"
"typescript": "~5.0.4",
"web3": "^1.3.0",
"viem": "^1.18.0",
"chai-as-promised": "^7.1.1"
},
"peerDependencies": {
"hardhat": "^2.0.2"
Expand Down
7 changes: 7 additions & 0 deletions scripts/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,17 @@ npx mocha test/ethers.ts --timeout 100000 --exit
# Waffle + HardhatEVM
npx mocha test/waffle.ts --timeout 100000 --exit

# Viem + HardhatEVM
npx mocha test/viem.ts --timeout 100000 --exit

# Ethers + Hardhat Node
start_hardhatevm
npx mocha test/hardhatevm.node.ts --timeout 100000 --exit

# Waffle + Hardhat Node
npx mocha test/waffle.ts --timeout 100000 --exit

# Viem + Hardhat Node
npx mocha test/viem.ts --timeout 100000 --exit

cleanup
35 changes: 25 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import fs from "fs"
import path from "path"
import { TASK_TEST_RUN_MOCHA_TESTS } from "hardhat/builtin-tasks/task-names";
import { task, subtask } from "hardhat/config";
import { task, subtask, extendEnvironment } from "hardhat/config";
import { HARDHAT_NETWORK_NAME, HardhatPluginError } from "hardhat/plugins";

import type { EGRAsyncApiProvider as EGRAsyncApiProviderT } from "./providers";
import type { EGRAsyncApiProvider as EGRAsyncApiProviderT, SnifferProvider as SnifferProviderT } from "./providers";

import {
HardhatArguments,
Expand All @@ -21,6 +21,7 @@ import { EthGasReporterConfig, EthGasReporterOutput, RemoteContract } from "./ty
import { TASK_GAS_REPORTER_MERGE, TASK_GAS_REPORTER_MERGE_REPORTS } from "./task-names";
import { mergeReports } from "./merge-reports";

let snifferProvider: SnifferProviderT;
let mochaConfig;
let resolvedQualifiedNames: string[]
let resolvedRemoteContracts: RemoteContract[] = [];
Expand Down Expand Up @@ -145,7 +146,7 @@ async function getResolvedRemoteContracts(
provider: EGRAsyncApiProviderT,
remoteContracts: RemoteContract[] = []
) : Promise <RemoteContract[]> {
const { defualt : sha1 } = await import("sha1");
const { default : sha1 } = await import("sha1");
for (const contract of remoteContracts){
let code;
try {
Expand All @@ -160,6 +161,21 @@ async function getResolvedRemoteContracts(
return remoteContracts;
}

extendEnvironment(function (hre) {
const {
BackwardsCompatibilityProviderAdapter
} = require("hardhat/internal/core/providers/backwards-compatibility")

const {
SnifferProvider
} = require("./providers");

snifferProvider = new SnifferProvider(hre.network.provider);
const backwardCompatibilityProvider = new BackwardsCompatibilityProviderAdapter(snifferProvider);

hre.network.provider = backwardCompatibilityProvider;
});

/**
* Overrides TASK_TEST_RUN_MOCHA_TEST to (conditionally) use eth-gas-reporter as
* the mocha test reporter and passes mocha relevant options. These are listed
Expand Down Expand Up @@ -197,16 +213,15 @@ subtask(TASK_TEST_RUN_MOCHA_TESTS).setAction(
if (hre.network.name === HARDHAT_NETWORK_NAME || options.fast){

const {
BackwardsCompatibilityProviderAdapter
} = await import("hardhat/internal/core/providers/backwards-compatibility")

const {
EGRDataCollectionProvider,
EGRAsyncApiProvider
} = await import("./providers");

const wrappedDataProvider= new EGRDataCollectionProvider(hre.network.provider,mochaConfig);
hre.network.provider = new BackwardsCompatibilityProviderAdapter(wrappedDataProvider);
const {
createEGRDataCollectionSniffer
} = await import("./sniffers");

const egrDataCollectionSniffer = createEGRDataCollectionSniffer(mochaConfig);
snifferProvider.addSniffer(egrDataCollectionSniffer);

const asyncProvider = new EGRAsyncApiProvider(hre.network.provider);
resolvedRemoteContracts = await getResolvedRemoteContracts(
Expand Down
85 changes: 32 additions & 53 deletions src/providers.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,43 @@
import { ProviderWrapper } from "hardhat/internal/core/providers/wrapper"
import { EthereumProvider, EIP1193Provider, RequestArguments } from "hardhat/types";
import { ProviderWrapper } from "hardhat/internal/core/providers/wrapper";
import {
EthereumProvider,
EIP1193Provider,
RequestArguments,
} from "hardhat/types";

export type Sniffer = (request: {
args: RequestArguments;
result: Promise<unknown>;
provider: EIP1193Provider;
}) => Promise<void> | void;

/**
* Wrapped provider which collects tx data
* Wrapped provider which sniffs requests
*/
export class EGRDataCollectionProvider extends ProviderWrapper {
private mochaConfig: any;
export class SnifferProvider extends ProviderWrapper {
private sniffers: Sniffer[] = [];

constructor(provider: EIP1193Provider, mochaConfig) {
constructor(provider: EIP1193Provider) {
super(provider);
this.mochaConfig = mochaConfig
}

public async request(args: RequestArguments): Promise<unknown> {
// Truffle
if (args.method === "eth_getTransactionReceipt") {
const receipt: any = await this._wrappedProvider.request(args);
if (receipt?.status && receipt?.transactionHash){
const tx = await this._wrappedProvider.request({
method: "eth_getTransactionByHash",
params: [receipt.transactionHash]
});
await this.mochaConfig.attachments.recordTransaction(receipt, tx);
}
return receipt;

// Ethers: will get run twice for deployments (e.g both receipt and txhash are fetched)
} else if (args.method === 'eth_getTransactionByHash'){
const receipt: any = await this._wrappedProvider.request({
method: "eth_getTransactionReceipt",
params: args.params
})
const tx = await this._wrappedProvider.request(args)
if (receipt?.status){
await this.mochaConfig.attachments.recordTransaction(receipt, tx)
}
return tx;

// Waffle: This is necessary when using Waffle wallets. eth_sendTransaction fetches the
// transactionHash as part of its flow, eth_sendRawTransaction *does not*.
} else if (args.method === 'eth_sendRawTransaction') {
const txHash = await this._wrappedProvider.request(args);

if (typeof txHash === 'string'){
const tx = await this._wrappedProvider.request({
method: "eth_getTransactionByHash",
params: [txHash]
});
const receipt : any = await this._wrappedProvider.request({
method: "eth_getTransactionReceipt",
params: [txHash]
});
public addSniffer(sniffer: Sniffer) {
this.sniffers.push(sniffer);
}

if (receipt?.status){
await this.mochaConfig.attachments.recordTransaction(receipt, tx)
}
}
return txHash;
}
return this._wrappedProvider.request(args);
public async request(args: RequestArguments): Promise<unknown> {
const result = (async () => await this._wrappedProvider.request(args))();
await Promise.all(
this.sniffers.map(
async (sniffer) =>
await sniffer({
args,
provider: this._wrappedProvider,
result,
})
)
);
return await result;
}
}

Expand Down
72 changes: 72 additions & 0 deletions src/sniffers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { Sniffer } from "./providers";

export function createEGRDataCollectionSniffer(mochaConfig: any): Sniffer {
return async function({ args, provider, result }) {
// Truffle
if (args.method === "eth_getTransactionReceipt") {
const receipt: any = await result;
if (receipt?.status && receipt?.transactionHash) {
const tx = await provider.request({
method: "eth_getTransactionByHash",
params: [receipt.transactionHash],
});
await mochaConfig.attachments.recordTransaction(receipt, tx);
}

// Ethers: will get run twice for deployments (e.g both receipt and txhash are fetched)
} else if (args.method === "eth_getTransactionByHash") {
const receipt: any = await provider.request({
method: "eth_getTransactionReceipt",
params: args.params,
});
const tx = await result;
if (receipt?.status) {
await mochaConfig.attachments.recordTransaction(receipt, tx);
}

// Waffle: This is necessary when using Waffle wallets. eth_sendTransaction fetches the
// transactionHash as part of its flow, eth_sendRawTransaction *does not*.
} else if (args.method === "eth_sendRawTransaction") {
const txHash = await result;

if (typeof txHash === "string") {
const tx = await provider.request({
method: "eth_getTransactionByHash",
params: [txHash],
});
const receipt: any = await provider.request({
method: "eth_getTransactionReceipt",
params: [txHash],
});

if (receipt?.status) {
await mochaConfig.attachments.recordTransaction(
receipt,
tx
);
}
}
// Viem
} else if (args.method === "eth_sendTransaction") {
const txHash = await result;

if (typeof txHash === "string") {
const tx = await provider.request({
method: "eth_getTransactionByHash",
params: [txHash],
});
const receipt: any = await provider.request({
method: "eth_getTransactionReceipt",
params: [txHash],
});

if (receipt?.status) {
await mochaConfig.attachments.recordTransaction(
receipt,
tx
);
}
}
}
};
}
24 changes: 24 additions & 0 deletions test/hardhat-viem-project/contracts/Greeter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity ^0.5.1;

contract Greeter {
string public greeting;

constructor(string memory _greeting) public {
greeting = _greeting;
}

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

function setGreeting(string memory _greeting) public {
greeting = _greeting;
}

function asOther() public {}

function throwAnError(string memory message) public {
greeting = "goodbye";
require(false, message);
}
}
10 changes: 10 additions & 0 deletions test/hardhat-viem-project/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// We load the plugin here.
import { HardhatUserConfig } from "hardhat/types";
import "../../src/index";
import "@nomicfoundation/hardhat-viem";

const config: HardhatUserConfig = {
solidity: "0.5.8",
};

export default config;
Loading