From 585eae5b1cc9ba28386b8ca5c1f3abd68d520b38 Mon Sep 17 00:00:00 2001 From: chris anatalio Date: Mon, 8 May 2023 10:40:19 -0700 Subject: [PATCH 01/95] Add Infura Sepolia Faucet #3906 --- docs/src/content/tutorial/deploying-to-a-live-network.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/content/tutorial/deploying-to-a-live-network.md b/docs/src/content/tutorial/deploying-to-a-live-network.md index 088f044b51..6125dd1808 100644 --- a/docs/src/content/tutorial/deploying-to-a-live-network.md +++ b/docs/src/content/tutorial/deploying-to-a-live-network.md @@ -121,7 +121,8 @@ To deploy on Sepolia you need to send some Sepolia ether to the address that's g - [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) - [Coinbase Sepolia Faucet](https://coinbase.com/faucets/ethereum-sepolia-faucet) (only works if you are using the Coinbase Wallet) - +- [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia) +- You'll have to change your wallet's network to Sepolia before transacting. :::tip From c6dd8d5e625b96fd3429ae811e9b780dcde451f7 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Mon, 8 May 2023 10:57:04 -0700 Subject: [PATCH 02/95] Update docs/src/content/tutorial/deploying-to-a-live-network.md --- docs/src/content/tutorial/deploying-to-a-live-network.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/content/tutorial/deploying-to-a-live-network.md b/docs/src/content/tutorial/deploying-to-a-live-network.md index 6125dd1808..49ed2699c9 100644 --- a/docs/src/content/tutorial/deploying-to-a-live-network.md +++ b/docs/src/content/tutorial/deploying-to-a-live-network.md @@ -122,7 +122,6 @@ To deploy on Sepolia you need to send some Sepolia ether to the address that's g - [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) - [Coinbase Sepolia Faucet](https://coinbase.com/faucets/ethereum-sepolia-faucet) (only works if you are using the Coinbase Wallet) - [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia) -- You'll have to change your wallet's network to Sepolia before transacting. :::tip From 90c2f5db6cbd5a5a3c5dd484999385a05558ffae Mon Sep 17 00:00:00 2001 From: chris anatalio Date: Mon, 8 May 2023 10:58:04 -0700 Subject: [PATCH 03/95] Add new line --- docs/src/content/tutorial/deploying-to-a-live-network.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/content/tutorial/deploying-to-a-live-network.md b/docs/src/content/tutorial/deploying-to-a-live-network.md index 49ed2699c9..372337934c 100644 --- a/docs/src/content/tutorial/deploying-to-a-live-network.md +++ b/docs/src/content/tutorial/deploying-to-a-live-network.md @@ -122,6 +122,7 @@ To deploy on Sepolia you need to send some Sepolia ether to the address that's g - [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) - [Coinbase Sepolia Faucet](https://coinbase.com/faucets/ethereum-sepolia-faucet) (only works if you are using the Coinbase Wallet) - [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia) + You'll have to change your wallet's network to Sepolia before transacting. :::tip From e9c0511f35cf4e1c46e8a3d8dc52b264e431322b Mon Sep 17 00:00:00 2001 From: Marin Petrunic Date: Tue, 9 May 2023 16:18:23 +0200 Subject: [PATCH 04/95] update hardhat-web3 web3 version to 4.x Signed-off-by: Marin Petrunic --- packages/hardhat-truffle5/test/tests.ts | 10 +- packages/hardhat-web3/.gitignore | 2 + packages/hardhat-web3/.mocharc.json | 2 +- packages/hardhat-web3/package.json | 8 +- packages/hardhat-web3/src/index.ts | 7 +- packages/hardhat-web3/src/type-extensions.ts | 4 +- .../hardhat-web3/src/web3-provider-adapter.ts | 102 ------- .../hardhat-project/contracts/Greeter.sol | 22 ++ packages/hardhat-web3/test/helpers.ts | 4 +- packages/hardhat-web3/test/index.ts | 55 ++++ .../test/web3-provider-adapter.ts | 145 ---------- .../when-accessing-web3-class.js | 2 +- .../when-accessing-web3-object.js | 2 +- yarn.lock | 267 ++++++++++++++++-- 14 files changed, 348 insertions(+), 284 deletions(-) delete mode 100644 packages/hardhat-web3/src/web3-provider-adapter.ts create mode 100644 packages/hardhat-web3/test/fixture-projects/hardhat-project/contracts/Greeter.sol create mode 100644 packages/hardhat-web3/test/index.ts delete mode 100644 packages/hardhat-web3/test/web3-provider-adapter.ts diff --git a/packages/hardhat-truffle5/test/tests.ts b/packages/hardhat-truffle5/test/tests.ts index 74d4d43cc7..1c4ee06c2a 100644 --- a/packages/hardhat-truffle5/test/tests.ts +++ b/packages/hardhat-truffle5/test/tests.ts @@ -244,7 +244,10 @@ describe("Gas multiplier", function () { const gasLimit = tx.gas; - assert.equal(gasLimit, Math.floor(web3Estimation * multiplier)); + assert.equal( + gasLimit, + String(Math.floor(Number(web3Estimation) * multiplier)) + ); } async function assertItWorksForFunctions( @@ -280,7 +283,10 @@ describe("Gas multiplier", function () { const tx = await env.web3.eth.getTransaction(txResult.tx); const gasLimit = tx.gas; - assert.equal(gasLimit, Math.floor(web3Estimation * multiplier)); + assert.equal( + gasLimit, + String(Math.floor(Number(web3Estimation) * multiplier)) + ); } describe("When it's set in the network", function () { diff --git a/packages/hardhat-web3/.gitignore b/packages/hardhat-web3/.gitignore index c00d7e7296..bc1256a4fe 100644 --- a/packages/hardhat-web3/.gitignore +++ b/packages/hardhat-web3/.gitignore @@ -93,3 +93,5 @@ typings/ # DynamoDB Local files .dynamodb/ +artifacts +cache \ No newline at end of file diff --git a/packages/hardhat-web3/.mocharc.json b/packages/hardhat-web3/.mocharc.json index 775e35460d..7ee95ee997 100644 --- a/packages/hardhat-web3/.mocharc.json +++ b/packages/hardhat-web3/.mocharc.json @@ -1,6 +1,6 @@ { "require": "ts-node/register/files", - "file": "../common/run-with-ganache", + "file": "../common/run-with-ganache.js", "ignore": ["test/fixture-projects/**/*"], "timeout": 10000 } diff --git a/packages/hardhat-web3/package.json b/packages/hardhat-web3/package.json index 99ffc8bf24..0793a80531 100644 --- a/packages/hardhat-web3/package.json +++ b/packages/hardhat-web3/package.json @@ -39,6 +39,7 @@ "@typescript-eslint/eslint-plugin": "5.53.0", "@typescript-eslint/parser": "5.53.0", "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", "eslint": "^7.29.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-import": "2.24.1", @@ -50,13 +51,10 @@ "rimraf": "^3.0.2", "ts-node": "^10.8.0", "typescript": "~4.7.4", - "web3": "^1.0.0-beta.36" + "web3": "^4.0.1-rc.1" }, "peerDependencies": { "hardhat": "^2.0.0", - "web3": "^1.0.0-beta.36" - }, - "dependencies": { - "@types/bignumber.js": "^5.0.0" + "web3": ">=4.0.1" } } diff --git a/packages/hardhat-web3/src/index.ts b/packages/hardhat-web3/src/index.ts index 66519fe9f8..4b27f5bb17 100644 --- a/packages/hardhat-web3/src/index.ts +++ b/packages/hardhat-web3/src/index.ts @@ -2,12 +2,11 @@ import { extendEnvironment } from "hardhat/config"; import { lazyFunction, lazyObject } from "hardhat/plugins"; import "./type-extensions"; -import { Web3HTTPProviderAdapter } from "./web3-provider-adapter"; extendEnvironment((env) => { - env.Web3 = lazyFunction(() => require("web3")); + env.Web3 = lazyFunction(() => require("web3").Web3); env.web3 = lazyObject(() => { - const Web3 = require("web3"); - return new Web3(new Web3HTTPProviderAdapter(env.network.provider)); + const Web3 = require("web3").Web3; + return new Web3(env.network.provider); }); }); diff --git a/packages/hardhat-web3/src/type-extensions.ts b/packages/hardhat-web3/src/type-extensions.ts index af8c9558bb..4353372f1a 100644 --- a/packages/hardhat-web3/src/type-extensions.ts +++ b/packages/hardhat-web3/src/type-extensions.ts @@ -1,10 +1,10 @@ -import type Web3 from "web3"; +import type * as Web3 from "web3"; import "hardhat/types/runtime"; declare module "hardhat/types/runtime" { interface HardhatRuntimeEnvironment { Web3: typeof Web3; - web3: Web3; + web3: Web3.Web3; } } diff --git a/packages/hardhat-web3/src/web3-provider-adapter.ts b/packages/hardhat-web3/src/web3-provider-adapter.ts deleted file mode 100644 index d76c9abbd2..0000000000 --- a/packages/hardhat-web3/src/web3-provider-adapter.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { EthereumProvider } from "hardhat/types"; -import util from "util"; - -export interface JsonRpcRequest { - jsonrpc: string; - method: string; - params: any[]; - id: number; -} - -export interface JsonRpcResponse { - jsonrpc: string; - id: number; - result?: any; - error?: { - code: number; - message: string; - data?: any; - }; -} - -export class Web3HTTPProviderAdapter { - private readonly _provider: EthereumProvider; - - constructor(provider: EthereumProvider) { - this._provider = provider; - // We bind everything here because some test suits break otherwise - this.send = this.send.bind(this) as any; - this.isConnected = this.isConnected.bind(this) as any; - this._sendJsonRpcRequest = this._sendJsonRpcRequest.bind(this) as any; - } - - public send( - payload: JsonRpcRequest, - callback: (error: Error | null, response?: JsonRpcResponse) => void - ): void; - public send( - payload: JsonRpcRequest[], - callback: (error: Error | null, response?: JsonRpcResponse[]) => void - ): void; - public send( - payload: JsonRpcRequest | JsonRpcRequest[], - callback: (error: Error | null, response?: any) => void - ): void { - if (!Array.isArray(payload)) { - util.callbackify(() => this._sendJsonRpcRequest(payload))(callback); - return; - } - - util.callbackify(async () => { - const responses: JsonRpcResponse[] = []; - - for (const request of payload) { - const response = await this._sendJsonRpcRequest(request); - - responses.push(response); - - if (response.error !== undefined) { - break; - } - } - - return responses; - })(callback); - } - - public isConnected(): boolean { - return true; - } - - private async _sendJsonRpcRequest( - request: JsonRpcRequest - ): Promise { - const response: JsonRpcResponse = { - id: request.id, - jsonrpc: "2.0", - }; - - try { - const result = await this._provider.send(request.method, request.params); - response.result = result; - } catch (error: any) { - if (error.code === undefined) { - throw error; - } - - response.error = { - // This might be a mistake, but I'm leaving it as is just in case, - // because it's not obvious what we should do here. - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - code: error.code ? +error.code : 404, - message: error.message, - data: { - stack: error.stack, - name: error.name, - }, - }; - } - - return response; - } -} diff --git a/packages/hardhat-web3/test/fixture-projects/hardhat-project/contracts/Greeter.sol b/packages/hardhat-web3/test/fixture-projects/hardhat-project/contracts/Greeter.sol new file mode 100644 index 0000000000..d7c9b9490c --- /dev/null +++ b/packages/hardhat-web3/test/fixture-projects/hardhat-project/contracts/Greeter.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.5.1; + +contract Greeter { + + string greeting; + + event GreetingUpdated(string greeting); + + constructor() public { + greeting = "Hi"; + } + + function setGreeting(string memory _greeting) public { + greeting = _greeting; + emit GreetingUpdated(_greeting); + } + + function greet() public view returns (string memory) { + return greeting; + } + +} diff --git a/packages/hardhat-web3/test/helpers.ts b/packages/hardhat-web3/test/helpers.ts index 394785e400..c3781481ee 100644 --- a/packages/hardhat-web3/test/helpers.ts +++ b/packages/hardhat-web3/test/helpers.ts @@ -1,5 +1,6 @@ import { resetHardhatContext } from "hardhat/plugins-testing"; import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { TASK_COMPILE } from "hardhat/builtin-tasks/task-names"; import path from "path"; declare module "mocha" { @@ -12,11 +13,12 @@ export function useEnvironment( fixtureProjectName: string, networkName = "localhost" ) { - beforeEach("Loading hardhat environment", function () { + beforeEach("Loading hardhat environment", async function () { process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName)); process.env.HARDHAT_NETWORK = networkName; this.env = require("hardhat"); + await this.env.run(TASK_COMPILE); }); afterEach("Resetting hardhat", function () { diff --git a/packages/hardhat-web3/test/index.ts b/packages/hardhat-web3/test/index.ts new file mode 100644 index 0000000000..5ba0f81e9f --- /dev/null +++ b/packages/hardhat-web3/test/index.ts @@ -0,0 +1,55 @@ +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; + +import { Contract } from "web3"; +import { useEnvironment } from "./helpers"; + +chai.use(chaiAsPromised); + +describe("Web3 plugin", function () { + describe("ganache", function () { + useEnvironment("hardhat-project", "localhost"); + + describe("contracts", function () { + it("should deploy", async function () { + const artifact = this.env.artifacts.readArtifactSync("Greeter"); + const Greeter = new Contract(artifact.abi, this.env.web3); + const response = Greeter.deploy({ + data: artifact.bytecode, + }).send({ + from: (await this.env.web3.eth.getAccounts())[0], + }); + await Promise.all([ + response.on("error", (...args) => console.log("error", args)), + response.on("transactionHash", (...args) => + console.log("transactionHash", args) + ), + response.on("receipt", (...args) => console.log("receipt", args)), + ]); + }); + }); + }); + describe("hardhat", function () { + useEnvironment("hardhat-project", "hardhat"); + + describe("contract", function () { + it("should deploy", async function () { + const artifact = this.env.artifacts.readArtifactSync("Greeter"); + const Greeter = new Contract(artifact.abi, this.env.web3); + const from = (await this.env.web3.eth.getAccounts())[0]; + const response = Greeter.deploy({ + data: artifact.bytecode, + }).send({ + from, + }); + await Promise.all([ + response.on("error", (...args) => console.log("error", args)), + response.on("transactionHash", (...args) => + console.log("transactionHash", args) + ), + response.on("receipt", (...args) => console.log("receipt", args)), + ]); + }); + }); + }); +}); diff --git a/packages/hardhat-web3/test/web3-provider-adapter.ts b/packages/hardhat-web3/test/web3-provider-adapter.ts deleted file mode 100644 index 044142d49b..0000000000 --- a/packages/hardhat-web3/test/web3-provider-adapter.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* eslint-disable @typescript-eslint/strict-boolean-expressions */ -import { assert } from "chai"; -import Web3 from "web3"; - -import { - JsonRpcRequest, - JsonRpcResponse, - Web3HTTPProviderAdapter, -} from "../src/web3-provider-adapter"; - -import { useEnvironment } from "./helpers"; - -let nextId = 1; - -function createJsonRpcRequest( - method: string, - params: any[] = [] -): JsonRpcRequest { - return { - id: nextId++, - jsonrpc: "2.0", - method, - params, - }; -} - -describe("Web3 provider adapter", function () { - let realWeb3Provider: any; - let adaptedProvider: Web3HTTPProviderAdapter; - - useEnvironment("hardhat-project"); - - beforeEach(function () { - realWeb3Provider = new Web3.providers.HttpProvider("http://127.0.0.1:8545"); - adaptedProvider = new Web3HTTPProviderAdapter(this.env.network.provider); - }); - - it("Should always return true when isConnected is called", function () { - assert.isTrue(adaptedProvider.isConnected()); - }); - - it("Should return the same as the real provider for sigle requests", function (done) { - const request = createJsonRpcRequest("eth_accounts"); - realWeb3Provider.send( - request, - (error: Error | null, response?: JsonRpcResponse) => { - adaptedProvider.send(request, (error2, response2) => { - assert.deepEqual(error2, error); - assert.deepEqual(response2, response); - done(); - }); - } - ); - }); - - it("Should return the same as the real provider for batched requests", function (done) { - const requests = [ - createJsonRpcRequest("eth_accounts"), - createJsonRpcRequest("net_version"), - createJsonRpcRequest("eth_accounts"), - ]; - - realWeb3Provider.send( - requests, - (error: Error | null, response?: JsonRpcResponse[]) => { - adaptedProvider.send(requests, (error2, response2) => { - assert.deepEqual(error2, error); - assert.deepEqual(response2, response); - done(); - }); - } - ); - }); - - it("Should return the same on error", function (done) { - // We disable this test for RskJ - // See: https://github.com/rsksmart/rskj/issues/876 - this.env.network.provider - .send("web3_clientVersion") - .then((version) => { - if (version.includes("RskJ")) { - done(); - return; - } - - const request = createJsonRpcRequest("error_please"); - - return realWeb3Provider.send( - request, - (error: Error | null, response?: JsonRpcResponse) => { - adaptedProvider.send(request, (error2, response2) => { - assert.deepEqual(error2, error); - assert.equal(response2!.error!.message, response!.error!.message); - done(); - }); - } - ); - }) - .then( - () => {}, - () => {} - ); - }); - - it("Should let all requests complete, even if one of them fails", function (done) { - const requests = [ - createJsonRpcRequest("eth_accounts"), - createJsonRpcRequest("error_please"), - createJsonRpcRequest("eth_accounts"), - ]; - - realWeb3Provider.send( - requests, - (error: Error | null, response?: JsonRpcResponse[]) => { - adaptedProvider.send(requests, (error2, response2) => { - assert.deepEqual(error2, error); - assert.deepEqual(response2![0], response![0]); - assert.equal( - response2![1].error!.message, - response![1].error!.message - ); - - // Ganache doesn't return a value for requests after the failing one, - // so we don't either. Otherwise, this should be tested. - // assert.lengthOf(response2!, response!.length); - // assert.isUndefined(responseFromAdapted![2]);![2]); - - // We disable this test for RskJ - // See: https://github.com/rsksmart/rskj/issues/876 - this.env.network.provider - .send("web3_clientVersion") - .then((version) => { - if (version.includes("RskJ")) { - assert.equal( - response2![1].error!.message, - response![1].error!.message - ); - } - }) - .then(done, done); - }); - } - ); - }); -}); diff --git a/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-class.js b/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-class.js index 08adc79cd1..83656c3640 100644 --- a/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-class.js +++ b/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-class.js @@ -1,6 +1,6 @@ const { lazyFunction, lazyObject } = require("hardhat/plugins"); -global.Web3 = lazyFunction(() => require("web3")); +global.Web3 = lazyFunction(() => require("web3").Web3); global.web3 = lazyObject(() => new global.Web3()); console.log(Web3.version); diff --git a/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-object.js b/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-object.js index 6160b1fced..82d7f4a09f 100644 --- a/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-object.js +++ b/packages/hardhat-web3/web3-lazy-object-tests/when-accessing-web3-object.js @@ -1,6 +1,6 @@ const { lazyFunction, lazyObject } = require("hardhat/plugins"); -global.Web3 = lazyFunction(() => require("web3")); +global.Web3 = lazyFunction(() => require("web3").Web3); global.web3 = lazyObject(() => new global.Web3()); console.log(global.web3.eth.getAccounts.name); diff --git a/yarn.lock b/yarn.lock index 8f15159e61..d47aea39fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@^1.8.8": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" + integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" @@ -529,6 +534,11 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.5" +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + "@ethereumjs/tx@3.3.2": version "3.3.2" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.2.tgz#348d4624bf248aaab6c44fec2ae67265efe3db00" @@ -1555,13 +1565,6 @@ resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== -"@types/bignumber.js@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-5.0.0.tgz#d9f1a378509f3010a3255e9cc822ad0eeb4ab969" - integrity sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA== - dependencies: - bignumber.js "*" - "@types/bn.js@^4.11.3": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -2143,7 +2146,7 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: +ajv@^8.0.1, ajv@^8.11.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -2219,10 +2222,15 @@ ansi-styles@~1.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" integrity sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA== -antlr4@4.7.1, antlr4@^4.11.0, antlr4@~4.8.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" - integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== +antlr4@^4.11.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.12.0.tgz#e2323fbb057c77068a174914b0533398aeaba56a" + integrity sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ== + +antlr4@~4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.8.0.tgz#f938ec171be7fc2855cd3a533e87647185b32b6a" + integrity sha512-en/MxQ4OkPgGJQ3wD/muzj1uDnFSzdFIhc2+c6bHZokWkuBb6RRvFjpWhPxWLbgQvaEzldJZ0GSQpfSAaE3hqg== antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" @@ -2465,16 +2473,16 @@ bigint-mod-arith@^3.1.0: resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== -bignumber.js@*, bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2: - version "9.1.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" - integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== - bignumber.js@^7.2.1: version "7.2.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f" integrity sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ== +bignumber.js@^9.0.0, bignumber.js@^9.0.1, bignumber.js@^9.0.2: + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== + "bignumber.js@git+https://github.com/frozeman/bignumber.js-nolookahead.git": version "2.0.7" resolved "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" @@ -3245,7 +3253,7 @@ cosmiconfig@^8.0.0: parse-json "^5.0.0" path-type "^4.0.0" -crc-32@^1.2.0: +crc-32@^1.2.0, crc-32@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== @@ -3278,7 +3286,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^3.1.4: +cross-fetch@^3.1.4, cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -4122,7 +4130,7 @@ ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereum-cryptography@^1.0.3: +ethereum-cryptography@^1.0.3, ethereum-cryptography@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== @@ -5625,6 +5633,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -9208,6 +9221,28 @@ web3-core@1.8.2: web3-core-requestmanager "1.8.2" web3-utils "1.8.2" +web3-core@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.0.1-rc.1.tgz#680bac30b8a2e819f651d181bc865de880fc37a3" + integrity sha512-Sf9lKbkOPsTVN9HwWEmirX1X3tcjThQFyNxEIOKnxTwnUg/eza1j8m+c//xRCe7EBP0EWmqrjsXLkeMdPnV9VA== + dependencies: + web3-errors "^1.0.0-rc.1" + web3-eth-iban "^4.0.1-rc.1" + web3-providers-http "^4.0.1-rc.1" + web3-providers-ws "^4.0.1-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + optionalDependencies: + web3-providers-ipc "^4.0.1-rc.1" + +web3-errors@^1.0.0-rc.1: + version "1.0.0-rc.1" + resolved "https://registry.yarnpkg.com/web3-errors/-/web3-errors-1.0.0-rc.1.tgz#55d2ef3c6890bfbacf1d4d6f036b417e9a56fe99" + integrity sha512-0okx1ZAECh+BvtaN6UShSP8z3tt36wRQzbcEbfe8g/qFfcSPVeQk+VJ69iE+wGQya4NzWelYxkxwbwUsUkm8cA== + dependencies: + web3-types "^1.0.0-rc.1" + web3-eth-abi@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz#16e1e9be40e2527404f041a4745111211488f31a" @@ -9216,6 +9251,17 @@ web3-eth-abi@1.8.2: "@ethersproject/abi" "^5.6.3" web3-utils "1.8.2" +web3-eth-abi@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-4.0.1-rc.1.tgz#b719d07c5b2bcdb3d9b798af7e267dba62c3a6f1" + integrity sha512-VKudlBkQb6JUauRjAJikjzXq93yyz6Y5jyVbp57nS9Oz4zklpjwWR/n5bfykjAPL7VxzSeO27rfAOsvsA0NUdg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-eth-accounts@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz#b894f5d5158fcae429da42de75d96520d0712971" @@ -9232,6 +9278,19 @@ web3-eth-accounts@1.8.2: web3-core-method "1.8.2" web3-utils "1.8.2" +web3-eth-accounts@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-4.0.1-rc.1.tgz#7a0b9675c811c67aa115a3797365fbe2210317a9" + integrity sha512-Ipimuf5v53m/NGqkPamIrLCgBPB9jfvfpEhftjkzr3HmmU8cCZuYZWYiM/XV8ZnoEATCnGkIR21QpiIq8GTFyg== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + crc-32 "^1.2.2" + ethereum-cryptography "^1.1.2" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-eth-contract@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz#5388b7130923d2b790c09a420391a81312a867fb" @@ -9246,6 +9305,19 @@ web3-eth-contract@1.8.2: web3-eth-abi "1.8.2" web3-utils "1.8.2" +web3-eth-contract@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-4.0.1-rc.1.tgz#70b525621255226073b6301901161ecd7050a5ac" + integrity sha512-v88K4dWS1xbtfBPCcHJv/Kff+oYD7ulIabvg3CUG9hxf2GxorV1wWoJ7F/kYoKXP1uZy+cQoZYe/UDwloWdQRg== + dependencies: + web3-core "^4.0.1-rc.1" + web3-errors "^1.0.0-rc.1" + web3-eth "^4.0.1-rc.1" + web3-eth-abi "^4.0.1-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-eth-ens@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz#0a086ad4d919102e28b9fd3036df246add9df22a" @@ -9260,6 +9332,21 @@ web3-eth-ens@1.8.2: web3-eth-contract "1.8.2" web3-utils "1.8.2" +web3-eth-ens@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-4.0.1-rc.1.tgz#5f1e61affbc6e0adeed7e7c5f96c0a9f3df74faa" + integrity sha512-Z2avvDK9fO7DDi4iCb3/L7J6AHHCeBVSUN4zr0Wza0saL3m8oC+m5UB5ZOtnsQAoey51eYo3K46KS5AQuimwKw== + dependencies: + "@adraffy/ens-normalize" "^1.8.8" + web3-core "^4.0.1-rc.1" + web3-errors "^1.0.0-rc.1" + web3-eth "^4.0.1-rc.1" + web3-eth-contract "^4.0.1-rc.1" + web3-net "^4.0.1-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-eth-iban@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz#5cb3022234b13986f086353b53f0379a881feeaf" @@ -9268,6 +9355,16 @@ web3-eth-iban@1.8.2: bn.js "^5.2.1" web3-utils "1.8.2" +web3-eth-iban@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-4.0.1-rc.1.tgz#1b1f0dd3ae94b81159058de3979719277b03b837" + integrity sha512-dwiFpj7EsXGpiVvS8bAk++xptHmVpqGDoWx/jVdWoc3WaeylZudd9khEbJ1w8KLtRFofLZ5E4yLAYA68K6TWkQ== + dependencies: + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-eth-personal@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz#3526c1ebaa4e7bf3a0a8ec77e34f067cc9a750b2" @@ -9280,6 +9377,18 @@ web3-eth-personal@1.8.2: web3-net "1.8.2" web3-utils "1.8.2" +web3-eth-personal@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-4.0.1-rc.1.tgz#1f2cb84bfa058b94264bb5eac64cc60e4128532a" + integrity sha512-AmEGgXuqBh1IP+mnIuCqv/+r7HhCKhGULxDg9QIWQHQmN/9+debkUQaYU6RU0TftlcsKk8q5jwGdEInTCbMTZA== + dependencies: + web3-core "^4.0.1-rc.1" + web3-eth "^4.0.1-rc.1" + web3-rpc-methods "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-eth@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.8.2.tgz#8562287ae1803c30eb54dc7d832092e5739ce06a" @@ -9298,6 +9407,23 @@ web3-eth@1.8.2: web3-net "1.8.2" web3-utils "1.8.2" +web3-eth@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-4.0.1-rc.1.tgz#33031523a0a7792022da9c3604c50c55eb4626a6" + integrity sha512-O6Grd8W0UEGPM1vO0o0c/N3Lb0mcgOvXumPP4nlIvEXljBGvnaW/iyj6LuOjAMoj4HZOe0pLeC4g1Xt96gOtoA== + dependencies: + setimmediate "^1.0.5" + web3-core "^4.0.1-rc.1" + web3-errors "^1.0.0-rc.1" + web3-eth-abi "^4.0.1-rc.1" + web3-eth-accounts "^4.0.1-rc.1" + web3-net "^4.0.1-rc.1" + web3-providers-ws "^4.0.1-rc.1" + web3-rpc-methods "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + web3-net@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.8.2.tgz#97e1e0015fabc4cda31017813e98d0b5468dd04f" @@ -9307,6 +9433,16 @@ web3-net@1.8.2: web3-core-method "1.8.2" web3-utils "1.8.2" +web3-net@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-4.0.1-rc.1.tgz#d1a1ef284c3b8beb77c8ffcdce44455af071258d" + integrity sha512-NOkgw0htSF5S0RAmfgkB8BVwdFsRd4X8Z7gIOdjLPL/IBVxi1u2XEt924MEkodJslu8f3UE62m09tKkbMgRQHw== + dependencies: + web3-core "^4.0.1-rc.1" + web3-rpc-methods "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-providers-http@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.8.2.tgz#fbda3a3bbc8db004af36e91bec35f80273b37885" @@ -9317,6 +9453,16 @@ web3-providers-http@1.8.2: es6-promise "^4.2.8" web3-core-helpers "1.8.2" +web3-providers-http@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-4.0.1-rc.1.tgz#5af0adf2e19a2014fd158bdd701ffab9fa9baf68" + integrity sha512-pYenobNL3fv83uKqumnvfS7vymBo4qJkmvsAPF+bVCNtS9zjd1OG1ylsQu6B04V/y8IQVvy3LKRX0kwxUiYdrA== + dependencies: + cross-fetch "^3.1.5" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-providers-ipc@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz#e52a7250f40c83b99a2482ec5b4cf2728377ae5c" @@ -9325,6 +9471,15 @@ web3-providers-ipc@1.8.2: oboe "2.1.5" web3-core-helpers "1.8.2" +web3-providers-ipc@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-4.0.1-rc.1.tgz#257750f22e4163115b54156ebe15fa3c19e646bd" + integrity sha512-R86g4CNPIYoqktPXqAfLWBVTVyt5Een0jpqFy0vSsdGdoR9g1v03o+sx5/++BCWYNRAg/fFmscYGjbjZWbhg5Q== + dependencies: + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-providers-ws@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz#56a2b701387011aca9154ca4bc06ea4b5f27e4ef" @@ -9334,6 +9489,26 @@ web3-providers-ws@1.8.2: web3-core-helpers "1.8.2" websocket "^1.0.32" +web3-providers-ws@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-4.0.1-rc.1.tgz#4c4e6ecef0170e91a68e3ff110ea551b9cd6882a" + integrity sha512-xGtqErSxXJPwLX2DY98HGITdX6zdABEvrBmkoha5LHdGy1SfUuiPQ9/60Qlli8LmyxhJxwB6J4082HZQwBSPZA== + dependencies: + isomorphic-ws "^5.0.0" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + ws "^8.8.1" + +web3-rpc-methods@^1.0.0-rc.1: + version "1.0.0-rc.1" + resolved "https://registry.yarnpkg.com/web3-rpc-methods/-/web3-rpc-methods-1.0.0-rc.1.tgz#f1dd716d64ba753d212d9b02132a89e8c7d87bf6" + integrity sha512-5Xev86E5jCPDJAW4BEfOpMj7y/vB021xLCC0Xz5+Ggl4AyU/0yUInnO5NN/ZLFoZrPzCG8aT+M8Pgc2+hYFLrQ== + dependencies: + web3-core "^4.0.1-rc.1" + web3-types "^1.0.0-rc.1" + web3-validator "^1.0.0-rc.1" + web3-shh@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.8.2.tgz#217a417f0d6e243dd4d441848ffc2bd164cea8a0" @@ -9344,6 +9519,11 @@ web3-shh@1.8.2: web3-core-subscriptions "1.8.2" web3-net "1.8.2" +web3-types@^1.0.0-rc.1: + version "1.0.0-rc.1" + resolved "https://registry.yarnpkg.com/web3-types/-/web3-types-1.0.0-rc.1.tgz#307a45a9ee6f0f75a37739ec7f9f46fda4353626" + integrity sha512-yqoCkP8VTYxiCDhL0u/VQxBZXUXRcWq5tuw2fZD8VCr21w5EPDJ1wvwODlcGbrBT/Bacqeoi9kNb6FXYiUe7pA== + web3-utils@1.8.2, web3-utils@^1.0.0-beta.31, web3-utils@^1.3.6: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.2.tgz#c32dec5e9b955acbab220eefd7715bc540b75cc9" @@ -9357,6 +9537,26 @@ web3-utils@1.8.2, web3-utils@^1.0.0-beta.31, web3-utils@^1.3.6: randombytes "^2.1.0" utf8 "3.0.0" +web3-utils@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-4.0.1-rc.1.tgz#ed12679595194ad7773b07ef5907e7c0d7a8d15a" + integrity sha512-LLu3X63paQUhtv4+UlGdmGKnwqDmdq+UzRTHecCdGKNPukiho5um5O2fS/9I+l21OXIgQPLqPSc49DuAkO57jg== + dependencies: + ethereum-cryptography "^1.1.2" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-validator "^1.0.0-rc.1" + +web3-validator@^1.0.0-rc.1: + version "1.0.0-rc.1" + resolved "https://registry.yarnpkg.com/web3-validator/-/web3-validator-1.0.0-rc.1.tgz#e07266b0efbfb5014c6ca015bbad05c009229dcc" + integrity sha512-a6hgW4ZXkDzy22axDPnD8eW0RwYVWHedw0Un+uLsGcvZxqIh5+EKFPmo57wK6wPq+8/OgdVzxQtzDwX5S43Kmg== + dependencies: + ajv "^8.11.0" + ethereum-cryptography "^1.1.2" + web3-errors "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3@0.20.6: version "0.20.6" resolved "https://registry.yarnpkg.com/web3/-/web3-0.20.6.tgz#3e97306ae024fb24e10a3d75c884302562215120" @@ -9392,6 +9592,28 @@ web3@^0.20.0: xhr2-cookies "^1.1.0" xmlhttprequest "*" +web3@^4.0.1-rc.1: + version "4.0.1-rc.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-4.0.1-rc.1.tgz#838e6c0d7dfe28a613d2e6772d7e007b82272ae2" + integrity sha512-86ot77U+Dxwc3kx8WNDYFB020mf8TCy9R0CXlOGPzmMWSEonBrE1VLwJxECDICMPxXhlmxpXYbvmOojBzMzIbw== + dependencies: + web3-core "^4.0.1-rc.1" + web3-errors "^1.0.0-rc.1" + web3-eth "^4.0.1-rc.1" + web3-eth-abi "^4.0.1-rc.1" + web3-eth-accounts "^4.0.1-rc.1" + web3-eth-contract "^4.0.1-rc.1" + web3-eth-ens "^4.0.1-rc.1" + web3-eth-iban "^4.0.1-rc.1" + web3-eth-personal "^4.0.1-rc.1" + web3-net "^4.0.1-rc.1" + web3-providers-http "^4.0.1-rc.1" + web3-providers-ws "^4.0.1-rc.1" + web3-rpc-methods "^1.0.0-rc.1" + web3-types "^1.0.0-rc.1" + web3-utils "^4.0.1-rc.1" + web3-validator "^1.0.0-rc.1" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -9576,6 +9798,11 @@ ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^8.8.1: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + wsrun@^5.2.2: version "5.2.4" resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-5.2.4.tgz#6eb6c3ccd3327721a8df073a5e3578fb0dea494e" From aa900fae03fc3512060bc4b5e13e867e52b0ae80 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 10 May 2023 10:57:34 +0200 Subject: [PATCH 05/95] Use alchemy instead of infura in fork tests --- .../workflows/test-recent-mainnet-block.yml | 2 +- .../scripts/test-recent-mainnet-block.ts | 4 +-- .../hardhat.config.js | 2 +- .../hardhat.config.js | 2 +- .../hardhat-network/helpers/providers.ts | 16 ++++++------ .../hardhat-network/provider/baseFeePerGas.ts | 6 ++--- .../provider/fork/ForkBlockchain.ts | 6 ++--- .../provider/fork/ForkStateManager.ts | 6 ++--- .../provider/forked-provider.ts | 6 ++--- .../provider/hardhat-network-options.ts | 4 +-- .../provider/interval-mining-provider.ts | 4 +-- .../hardhat-network/provider/modules/debug.ts | 10 +++---- .../eth/methods/getTransactionByHash.ts | 8 +++--- .../provider/modules/hardhat.ts | 18 ++++++------- .../internal/hardhat-network/provider/node.ts | 26 +++++++++---------- 15 files changed, 60 insertions(+), 60 deletions(-) diff --git a/.github/workflows/test-recent-mainnet-block.yml b/.github/workflows/test-recent-mainnet-block.yml index 2d22215aea..209d2f18a2 100644 --- a/.github/workflows/test-recent-mainnet-block.yml +++ b/.github/workflows/test-recent-mainnet-block.yml @@ -24,7 +24,7 @@ jobs: run: yarn build - name: Run test env: - INFURA_URL: ${{ secrets.INFURA_URL }} + ALCHEMY_URL: ${{ secrets.ALCHEMY_URL }} run: yarn ts-node scripts/test-recent-mainnet-block.ts - name: Notify failures if: failure() diff --git a/packages/hardhat-core/scripts/test-recent-mainnet-block.ts b/packages/hardhat-core/scripts/test-recent-mainnet-block.ts index d7c64ebab0..d677218f9c 100644 --- a/packages/hardhat-core/scripts/test-recent-mainnet-block.ts +++ b/packages/hardhat-core/scripts/test-recent-mainnet-block.ts @@ -4,11 +4,11 @@ import { makeForkClient } from "../src/internal/hardhat-network/provider/utils/m import { runFullBlock } from "../test/internal/hardhat-network/provider/utils/runFullBlock"; async function main() { - const rpcUrl = process.env.INFURA_URL; + const rpcUrl = process.env.ALCHEMY_URL; if (rpcUrl === undefined || rpcUrl === "") { console.error( - "[test-recent-mainnet-block] Missing INFURA_URL environment variable" + "[test-recent-mainnet-block] Missing ALCHEMY_URL environment variable" ); process.exit(1); } diff --git a/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-from-old-block/hardhat.config.js b/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-from-old-block/hardhat.config.js index e8832e44ec..41ddc2d38c 100644 --- a/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-from-old-block/hardhat.config.js +++ b/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-from-old-block/hardhat.config.js @@ -2,7 +2,7 @@ module.exports = { networks: { hardhat: { forking: { - url: process.env.INFURA_URL, + url: process.env.ALCHEMY_URL, blockNumber: 2463000, }, }, diff --git a/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-tangerine-whistle/hardhat.config.js b/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-tangerine-whistle/hardhat.config.js index 6f610736cc..ea9c1f0cd4 100644 --- a/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-tangerine-whistle/hardhat.config.js +++ b/packages/hardhat-core/test/fixture-projects/hardhat-network-fork-tangerine-whistle/hardhat.config.js @@ -3,7 +3,7 @@ module.exports = { hardhat: { hardfork: "tangerineWhistle", forking: { - url: process.env.INFURA_URL, + url: process.env.ALCHEMY_URL, }, }, }, diff --git a/packages/hardhat-core/test/internal/hardhat-network/helpers/providers.ts b/packages/hardhat-core/test/internal/hardhat-network/helpers/providers.ts index 3719c67d6d..cb37eb70e3 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/helpers/providers.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/helpers/providers.ts @@ -126,11 +126,11 @@ export const FORKED_PROVIDERS: Array<{ useProvider: (options?: UseProviderOptions) => void; }> = []; -if (INFURA_URL !== undefined) { - const url = INFURA_URL; +if (ALCHEMY_URL !== undefined) { + const url = ALCHEMY_URL; PROVIDERS.push({ - name: "Infura Forked", + name: "Alchemy Forked", isFork: true, isJsonRpc: false, networkId: DEFAULT_NETWORK_ID, @@ -146,7 +146,7 @@ if (INFURA_URL !== undefined) { }); INTERVAL_MINING_PROVIDERS.push({ - name: "Infura Forked", + name: "Alchemy Forked", isFork: true, isJsonRpc: false, useProvider: (options: UseProviderOptions = {}) => { @@ -165,7 +165,7 @@ if (INFURA_URL !== undefined) { }); FORKED_PROVIDERS.push({ - rpcProvider: "Infura", + rpcProvider: "Alchemy", jsonRpcUrl: url, useProvider: (options: UseProviderOptions = {}) => { useProvider({ @@ -178,11 +178,11 @@ if (INFURA_URL !== undefined) { }); } -if (ALCHEMY_URL !== undefined) { - const url = ALCHEMY_URL; +if (INFURA_URL !== undefined) { + const url = INFURA_URL; FORKED_PROVIDERS.push({ - rpcProvider: "Alchemy", + rpcProvider: "Infura", jsonRpcUrl: url, useProvider: (options: UseProviderOptions = {}) => { useProvider({ diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/baseFeePerGas.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/baseFeePerGas.ts index 7e013b3ad5..2c5bd0a8ad 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/baseFeePerGas.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/baseFeePerGas.ts @@ -10,7 +10,7 @@ import { } from "../../../../src/internal/core/jsonrpc/types/base-types"; import { EthereumProvider } from "../../../../src/types"; import { makeForkClient } from "../../../../src/internal/hardhat-network/provider/utils/makeForkClient"; -import { INFURA_URL } from "../../../setup"; +import { ALCHEMY_URL } from "../../../setup"; import { rpcToBlockData } from "../../../../src/internal/hardhat-network/provider/fork/rpcToBlockData"; async function getLatestBaseFeePerGas(provider: EthereumProvider) { @@ -102,14 +102,14 @@ describe("Block's baseFeePerGas", function () { useProvider(); it("Should use the same base fee as the one remote networks's forked block", async function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); return; } const blockNumber = await this.provider.send("eth_blockNumber"); const { forkClient } = await makeForkClient({ - jsonRpcUrl: INFURA_URL!, + jsonRpcUrl: ALCHEMY_URL!, }); const remoteLatestBlockBaseFeePerGas = diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkBlockchain.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkBlockchain.ts index 9c6927946c..30f37b6a28 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkBlockchain.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkBlockchain.ts @@ -11,7 +11,7 @@ import { JsonRpcClient } from "../../../../../src/internal/hardhat-network/jsonr import { ForkBlockchain } from "../../../../../src/internal/hardhat-network/provider/fork/ForkBlockchain"; import { randomHashBuffer } from "../../../../../src/internal/hardhat-network/provider/utils/random"; import { makeForkClient } from "../../../../../src/internal/hardhat-network/provider/utils/makeForkClient"; -import { INFURA_URL } from "../../../../setup"; +import { ALCHEMY_URL } from "../../../../setup"; import { createTestLog, createTestReceipt, @@ -45,14 +45,14 @@ describe("ForkBlockchain", () => { } before(async function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); return; } }); beforeEach(async () => { - const clientResult = await makeForkClient({ jsonRpcUrl: INFURA_URL! }); + const clientResult = await makeForkClient({ jsonRpcUrl: ALCHEMY_URL! }); client = clientResult.forkClient; forkBlockNumber = clientResult.forkBlockNumber; diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkStateManager.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkStateManager.ts index f133a082db..c5b4688013 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkStateManager.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkStateManager.ts @@ -17,7 +17,7 @@ import { } from "../../../../../src/internal/hardhat-network/provider/utils/random"; import { makeForkClient } from "../../../../../src/internal/hardhat-network/provider/utils/makeForkClient"; import { keccak256 } from "../../../../../src/internal/util/keccak"; -import { INFURA_URL } from "../../../../setup"; +import { ALCHEMY_URL } from "../../../../setup"; import { DAI_ADDRESS, DAI_TOTAL_SUPPLY_STORAGE_POSITION, @@ -32,14 +32,14 @@ describe("ForkStateManager", () => { let fsm: ForkStateManager; before(async function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); return; } }); beforeEach(async () => { - const clientResult = await makeForkClient({ jsonRpcUrl: INFURA_URL! }); + const clientResult = await makeForkClient({ jsonRpcUrl: ALCHEMY_URL! }); client = clientResult.forkClient; forkBlockNumber = clientResult.forkBlockNumber; diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/forked-provider.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/forked-provider.ts index 9606e5e8b7..fcdbe19bc7 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/forked-provider.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/forked-provider.ts @@ -9,7 +9,7 @@ import { } from "../../../../src/internal/core/jsonrpc/types/base-types"; import { InvalidInputError } from "../../../../src/internal/core/providers/errors"; import { LegacyRpcTransactionOutput } from "../../../../src/internal/hardhat-network/provider/output"; -import { INFURA_URL } from "../../../setup"; +import { ALCHEMY_URL } from "../../../setup"; import { workaroundWindowsCiFailures } from "../../../utils/workaround-windows-ci-failures"; import { assertQuantity, @@ -485,14 +485,14 @@ describe("Forked provider", function () { describe("blocks timestamps", () => { it("should use a timestamp relative to the forked block timestamp", async function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); } await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: 11565019, // first block of 2021 }, }, diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/hardhat-network-options.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/hardhat-network-options.ts index f1cf6b534c..2d25a991cc 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/hardhat-network-options.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/hardhat-network-options.ts @@ -10,7 +10,7 @@ import { HardhatNetworkConfig } from "../../../../src/types"; import { useEnvironment } from "../../../helpers/environment"; import { expectErrorAsync } from "../../../helpers/errors"; import { useFixtureProject } from "../../../helpers/project"; -import { INFURA_URL } from "../../../setup"; +import { ALCHEMY_URL } from "../../../setup"; describe("Hardhat Network special options", function () { describe("allowUnlimitedContractSize", function () { @@ -111,7 +111,7 @@ describe("Hardhat Network special options", function () { }); describe("When forking", function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { return; } diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/interval-mining-provider.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/interval-mining-provider.ts index 200efbbfed..755132b951 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/interval-mining-provider.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/interval-mining-provider.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import sinon from "sinon"; import { rpcQuantityToNumber } from "../../../../src/internal/core/jsonrpc/types/base-types"; -import { INFURA_URL } from "../../../setup"; +import { ALCHEMY_URL } from "../../../setup"; import { workaroundWindowsCiFailures } from "../../../utils/workaround-windows-ci-failures"; import { setCWD } from "../helpers/cwd"; import { INTERVAL_MINING_PROVIDERS } from "../helpers/providers"; @@ -69,7 +69,7 @@ describe("Interval mining provider", function () { await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/debug.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/debug.ts index e422038e64..55a88c8050 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/debug.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/debug.ts @@ -13,7 +13,7 @@ import { trace as mainnetReturnsDataTrace } from "../../../../fixture-debug-trac import { trace as mainnetReturnsDataTraceGeth } from "../../../../fixture-debug-traces/mainnetReturnsDataTraceGeth"; import { trace as mainnetRevertTrace } from "../../../../fixture-debug-traces/mainnetRevertTrace"; import { trace as modifiesStateTrace } from "../../../../fixture-debug-traces/modifiesStateTrace"; -import { INFURA_URL } from "../../../../setup"; +import { ALCHEMY_URL } from "../../../../setup"; import { assertInvalidInputError } from "../../helpers/assertions"; import { FORK_TESTS_CACHE_PATH } from "../../helpers/constants"; import { EXAMPLE_CONTRACT } from "../../helpers/contracts"; @@ -191,11 +191,11 @@ describe.skip("Debug module", function () { let provider: EthereumProvider; beforeEach(function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); } const forkConfig: ForkConfig = { - jsonRpcUrl: INFURA_URL!, + jsonRpcUrl: ALCHEMY_URL!, blockNumber: 11_954_000, }; @@ -315,11 +315,11 @@ describe.skip("Debug module", function () { let provider: EthereumProvider; beforeEach(function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); } const forkConfig: ForkConfig = { - jsonRpcUrl: INFURA_URL!, + jsonRpcUrl: ALCHEMY_URL!, blockNumber: 15_204_358, }; diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/getTransactionByHash.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/getTransactionByHash.ts index 02533498d1..efc07c2a5e 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/getTransactionByHash.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/getTransactionByHash.ts @@ -19,7 +19,7 @@ import { EIP1559RpcTransactionOutput, LegacyRpcTransactionOutput, } from "../../../../../../../src/internal/hardhat-network/provider/output"; -import { INFURA_URL } from "../../../../../../setup"; +import { ALCHEMY_URL } from "../../../../../../setup"; import { workaroundWindowsCiFailures } from "../../../../../../utils/workaround-windows-ci-failures"; import { assertAccessListTransaction, @@ -324,13 +324,13 @@ describe("Eth module", function () { }); it("should get an existing transaction from goerli", async function () { - if (!isFork || INFURA_URL === undefined) { + if (!isFork || ALCHEMY_URL === undefined) { this.skip(); } - const goerliUrl = INFURA_URL.replace("mainnet", "goerli"); + const goerliUrl = ALCHEMY_URL.replace("mainnet", "goerli"); // If "mainnet" is not present the replacement failed so we skip the test - if (goerliUrl === INFURA_URL) { + if (goerliUrl === ALCHEMY_URL) { this.skip(); } diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts index 3f3e06a385..5e63e06746 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts @@ -11,7 +11,7 @@ import { } from "../../../../../src/internal/core/jsonrpc/types/base-types"; import { CompilerOutputContract } from "../../../../../src/types/artifacts"; import { expectErrorAsync } from "../../../../helpers/errors"; -import { INFURA_URL } from "../../../../setup"; +import { ALCHEMY_URL } from "../../../../setup"; import { workaroundWindowsCiFailures } from "../../../../utils/workaround-windows-ci-failures"; import { assertInternalError, @@ -1305,7 +1305,7 @@ describe("Hardhat module", function () { describe("hardhat_reset", function () { before(function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); } }); @@ -1334,7 +1334,7 @@ describe("Hardhat module", function () { await assertInvalidArgumentsError(this.provider, "hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: "0", }, }, @@ -1345,7 +1345,7 @@ describe("Hardhat module", function () { const result = await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, @@ -1435,7 +1435,7 @@ describe("Hardhat module", function () { await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, @@ -1448,13 +1448,13 @@ describe("Hardhat module", function () { await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, ]); await this.provider.send("hardhat_reset", [ - { forking: { jsonRpcUrl: INFURA_URL } }, + { forking: { jsonRpcUrl: ALCHEMY_URL } }, ]); // This condition is rather loose as Infura can sometimes return @@ -1483,7 +1483,7 @@ describe("Hardhat module", function () { await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, @@ -1495,7 +1495,7 @@ describe("Hardhat module", function () { await this.provider.send("hardhat_reset", [ { forking: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: safeBlockInThePast, }, }, diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts index 1914b7010a..32d753e9c0 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts @@ -23,7 +23,7 @@ import { HardhatNetworkChainConfig, HardhatNetworkChainsConfig, } from "../../../../src/types"; -import { INFURA_URL } from "../../../setup"; +import { ALCHEMY_URL } from "../../../setup"; import { assertQuantity } from "../helpers/assertions"; import { EMPTY_ACCOUNT_ADDRESS, @@ -694,7 +694,7 @@ describe("HardhatNode", () => { }); describe("full block", function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { return; } @@ -703,43 +703,43 @@ describe("HardhatNode", () => { // its receipts contain the state root, and we can't compute it { networkName: "mainnet", - url: INFURA_URL, + url: ALCHEMY_URL, blockToRun: 4370001n, chainId: 1, }, { networkName: "mainnet", - url: INFURA_URL, + url: ALCHEMY_URL, blockToRun: 7280001n, chainId: 1, }, { networkName: "mainnet", - url: INFURA_URL, + url: ALCHEMY_URL, blockToRun: 9069001n, chainId: 1, }, { networkName: "mainnet", - url: INFURA_URL, + url: ALCHEMY_URL, blockToRun: 9300077n, chainId: 1, }, { networkName: "mainnet", - url: INFURA_URL, + url: ALCHEMY_URL, blockToRun: 17_050_001n, // post-shanghai chainId: 1, }, { networkName: "goerli", - url: INFURA_URL.replace("mainnet", "goerli"), + url: ALCHEMY_URL.replace("mainnet", "goerli"), blockToRun: 7728449n, // this block has both EIP-2930 and EIP-1559 txs chainId: 5, }, { networkName: "sepolia", - url: INFURA_URL.replace("mainnet", "sepolia"), + url: ALCHEMY_URL.replace("mainnet", "sepolia"), blockToRun: 3095000n, // this block is post-shanghai chainId: 11155111, }, @@ -871,7 +871,7 @@ describe("HardhatNode", () => { describe("should run calls in the right hardfork context", async function () { this.timeout(10000); before(function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); return; } @@ -890,7 +890,7 @@ describe("HardhatNode", () => { networkId: 1, hardfork: "london", forkConfig: { - jsonRpcUrl: INFURA_URL!, + jsonRpcUrl: ALCHEMY_URL!, blockNumber: Number(eip1559ActivationBlock), }, forkCachePath: FORK_TESTS_CACHE_PATH, @@ -1046,7 +1046,7 @@ describe("HardhatNode", () => { }); it("should support a historical call in the context of a block added via mineBlocks()", async function () { - if (INFURA_URL === undefined) { + if (ALCHEMY_URL === undefined) { this.skip(); return; } @@ -1056,7 +1056,7 @@ describe("HardhatNode", () => { networkId: 1, hardfork: "london", forkConfig: { - jsonRpcUrl: INFURA_URL, + jsonRpcUrl: ALCHEMY_URL, blockNumber: 12965000, // eip1559ActivationBlock }, forkCachePath: FORK_TESTS_CACHE_PATH, From 843f788a7dde1bd47eea13abfcd184a721d40496 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 10 May 2023 11:35:20 +0200 Subject: [PATCH 06/95] Fix alchemy url for sepolia --- .../test/internal/hardhat-network/provider/node.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts index 32d753e9c0..9a59f18583 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts @@ -739,7 +739,8 @@ describe("HardhatNode", () => { }, { networkName: "sepolia", - url: ALCHEMY_URL.replace("mainnet", "sepolia"), + url: ALCHEMY_URL.replace("alchemyapi.io", "g.alchemy.com") // temporary fix until we fix our github secret + .replace("mainnet", "sepolia"), blockToRun: 3095000n, // this block is post-shanghai chainId: 11155111, }, From 145545961cc06de6b1ec6435f960f379f4bb0912 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 11 May 2023 13:41:54 +0200 Subject: [PATCH 07/95] Use node 18.15 in CI --- .github/workflows/hardhat-chai-matchers-ci.yml | 2 +- .github/workflows/hardhat-core-ci.yml | 2 +- .github/workflows/hardhat-ethers-ci.yml | 2 +- .github/workflows/hardhat-foundry-ci.yml | 2 +- .github/workflows/hardhat-network-helpers-ci.yml | 2 +- .github/workflows/hardhat-network-tracing-all-solc-versions.yml | 2 +- .github/workflows/hardhat-network-tracing-ci.yml | 2 +- .github/workflows/hardhat-shorthand-ci.yml | 2 +- .github/workflows/hardhat-solhint-ci.yml | 2 +- .github/workflows/hardhat-solpp-ci.yml | 2 +- .github/workflows/hardhat-toolbox-ci.yml | 2 +- .github/workflows/hardhat-truffle4-ci.yml | 2 +- .github/workflows/hardhat-truffle5-ci.yml | 2 +- .github/workflows/hardhat-verify-ci.yml | 2 +- .github/workflows/hardhat-vyper-ci.yml | 2 +- .github/workflows/hardhat-web3-ci.yml | 2 +- .github/workflows/hardhat-web3-legacy-ci.yml | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/hardhat-chai-matchers-ci.yml b/.github/workflows/hardhat-chai-matchers-ci.yml index 35e720e80a..34deb7b24d 100644 --- a/.github/workflows/hardhat-chai-matchers-ci.yml +++ b/.github/workflows/hardhat-chai-matchers-ci.yml @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-core-ci.yml b/.github/workflows/hardhat-core-ci.yml index 75a5c3ef26..b7699630c3 100644 --- a/.github/workflows/hardhat-core-ci.yml +++ b/.github/workflows/hardhat-core-ci.yml @@ -69,7 +69,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-ethers-ci.yml b/.github/workflows/hardhat-ethers-ci.yml index 457743ec24..f7dadcbd13 100644 --- a/.github/workflows/hardhat-ethers-ci.yml +++ b/.github/workflows/hardhat-ethers-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-foundry-ci.yml b/.github/workflows/hardhat-foundry-ci.yml index f52e14fc2b..1809eda2ac 100644 --- a/.github/workflows/hardhat-foundry-ci.yml +++ b/.github/workflows/hardhat-foundry-ci.yml @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-network-helpers-ci.yml b/.github/workflows/hardhat-network-helpers-ci.yml index c2bc454b93..6c5922aa4e 100644 --- a/.github/workflows/hardhat-network-helpers-ci.yml +++ b/.github/workflows/hardhat-network-helpers-ci.yml @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-network-tracing-all-solc-versions.yml b/.github/workflows/hardhat-network-tracing-all-solc-versions.yml index 0704096987..b2b2257b3d 100644 --- a/.github/workflows/hardhat-network-tracing-all-solc-versions.yml +++ b/.github/workflows/hardhat-network-tracing-all-solc-versions.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-network-tracing-ci.yml b/.github/workflows/hardhat-network-tracing-ci.yml index c5c8f07963..d8286209a2 100644 --- a/.github/workflows/hardhat-network-tracing-ci.yml +++ b/.github/workflows/hardhat-network-tracing-ci.yml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-shorthand-ci.yml b/.github/workflows/hardhat-shorthand-ci.yml index f07472ab0a..4584da6fa2 100644 --- a/.github/workflows/hardhat-shorthand-ci.yml +++ b/.github/workflows/hardhat-shorthand-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-solhint-ci.yml b/.github/workflows/hardhat-solhint-ci.yml index b548aae14e..bd4da9dc37 100644 --- a/.github/workflows/hardhat-solhint-ci.yml +++ b/.github/workflows/hardhat-solhint-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-solpp-ci.yml b/.github/workflows/hardhat-solpp-ci.yml index ac5f545700..d838e5f964 100644 --- a/.github/workflows/hardhat-solpp-ci.yml +++ b/.github/workflows/hardhat-solpp-ci.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-toolbox-ci.yml b/.github/workflows/hardhat-toolbox-ci.yml index d10cddefc0..a41ddca032 100644 --- a/.github/workflows/hardhat-toolbox-ci.yml +++ b/.github/workflows/hardhat-toolbox-ci.yml @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-truffle4-ci.yml b/.github/workflows/hardhat-truffle4-ci.yml index 46b7d5d003..871a3040ec 100644 --- a/.github/workflows/hardhat-truffle4-ci.yml +++ b/.github/workflows/hardhat-truffle4-ci.yml @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-truffle5-ci.yml b/.github/workflows/hardhat-truffle5-ci.yml index 70e873cc04..b013591b4d 100644 --- a/.github/workflows/hardhat-truffle5-ci.yml +++ b/.github/workflows/hardhat-truffle5-ci.yml @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-verify-ci.yml b/.github/workflows/hardhat-verify-ci.yml index a16b39cdf1..34f0cc51c7 100644 --- a/.github/workflows/hardhat-verify-ci.yml +++ b/.github/workflows/hardhat-verify-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-vyper-ci.yml b/.github/workflows/hardhat-vyper-ci.yml index 528e027713..736f51031e 100644 --- a/.github/workflows/hardhat-vyper-ci.yml +++ b/.github/workflows/hardhat-vyper-ci.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-web3-ci.yml b/.github/workflows/hardhat-web3-ci.yml index 33a8ead269..f01d13f3ac 100644 --- a/.github/workflows/hardhat-web3-ci.yml +++ b/.github/workflows/hardhat-web3-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/.github/workflows/hardhat-web3-legacy-ci.yml b/.github/workflows/hardhat-web3-legacy-ci.yml index 221110aa34..79af94c5be 100644 --- a/.github/workflows/hardhat-web3-legacy-ci.yml +++ b/.github/workflows/hardhat-web3-legacy-ci.yml @@ -65,7 +65,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [14, 16, 18.15] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 From ad5d50bbd19bb93df0d07cca3b2855d8d8f44384 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 12 May 2023 16:44:30 +0200 Subject: [PATCH 08/95] Check that all supported hardforks have a history entry --- .../internal/core/config/default-config.ts | 23 +++++++++++++------ .../internal/core/config/default-config.ts | 23 +++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 packages/hardhat-core/test/internal/core/config/default-config.ts diff --git a/packages/hardhat-core/src/internal/core/config/default-config.ts b/packages/hardhat-core/src/internal/core/config/default-config.ts index ec014daf62..b4f2a90e9a 100644 --- a/packages/hardhat-core/src/internal/core/config/default-config.ts +++ b/packages/hardhat-core/src/internal/core/config/default-config.ts @@ -60,13 +60,22 @@ export const defaultHardhatNetworkParams: Omit< 1, // mainnet { hardforkHistory: new Map([ - [HardforkName.BYZANTIUM, 4370000], - [HardforkName.CONSTANTINOPLE, 7280000], - [HardforkName.PETERSBURG, 7280000], - [HardforkName.ISTANBUL, 9069000], - [HardforkName.MUIR_GLACIER, 9200000], - [HardforkName.BERLIN, 12244000], - [HardforkName.LONDON, 12965000], + [HardforkName.FRONTIER, 0], + [HardforkName.HOMESTEAD, 1_150_000], + [HardforkName.DAO, 1_920_000], + [HardforkName.TANGERINE_WHISTLE, 2_463_000], + [HardforkName.SPURIOUS_DRAGON, 2_675_000], + [HardforkName.BYZANTIUM, 4_370_000], + [HardforkName.CONSTANTINOPLE, 7_280_000], + [HardforkName.PETERSBURG, 7_280_000], + [HardforkName.ISTANBUL, 9_069_000], + [HardforkName.MUIR_GLACIER, 9_200_000], + [HardforkName.BERLIN, 1_2244_000], + [HardforkName.LONDON, 12_965_000], + [HardforkName.ARROW_GLACIER, 13_773_000], + [HardforkName.GRAY_GLACIER, 15_050_000], + [HardforkName.MERGE, 15_537_394], + [HardforkName.SHANGHAI, 17_034_870], ]), }, ], diff --git a/packages/hardhat-core/test/internal/core/config/default-config.ts b/packages/hardhat-core/test/internal/core/config/default-config.ts new file mode 100644 index 0000000000..9aa9ed455c --- /dev/null +++ b/packages/hardhat-core/test/internal/core/config/default-config.ts @@ -0,0 +1,23 @@ +import { assert } from "chai"; + +import { defaultHardhatNetworkParams } from "../../../../src/internal/core/config/default-config"; +import { HardforkName } from "../../../../src/internal/util/hardforks"; + +describe("Default config", function () { + it("should include block numbers for all hardforks", async function () { + const mainnetChainConfig = defaultHardhatNetworkParams.chains.get(1); + + if (mainnetChainConfig === undefined) { + assert.fail("Mainnet entry should exist"); + } + + for (const hardfork of Object.values(HardforkName)) { + const hardforkHistoryEntry = + mainnetChainConfig.hardforkHistory.get(hardfork); + assert.isDefined( + hardforkHistoryEntry, + `No hardfork history entry for ${hardfork}` + ); + } + }); +}); From a5b0033d312a045968647d83f28a910664e46493 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 12 May 2023 18:45:40 +0200 Subject: [PATCH 09/95] Add support for ethers v6 --- config/eslint/eslintrc.js | 2 +- packages/hardhat-chai-matchers/.eslintrc.js | 3 + packages/hardhat-chai-matchers/package.json | 12 +- .../src/internal/changeEtherBalance.ts | 52 +- .../src/internal/changeEtherBalances.ts | 51 +- .../src/internal/changeTokenBalance.ts | 91 +- .../src/internal/constants.ts | 1 + .../src/internal/emit.ts | 88 +- .../src/internal/errors.ts | 20 +- .../src/internal/misc/account.ts | 23 +- .../src/internal/misc/balance.ts | 14 +- .../src/internal/reverted/panic.ts | 26 +- .../src/internal/reverted/reverted.ts | 11 +- .../src/internal/reverted/revertedWith.ts | 12 +- .../reverted/revertedWithCustomError.ts | 166 ++- .../internal/reverted/revertedWithPanic.ts | 34 +- .../reverted/revertedWithoutReason.ts | 9 +- .../src/internal/reverted/utils.ts | 32 +- .../src/internal/utils.ts | 12 + .../src/internal/withArgs.ts | 56 +- .../hardhat-chai-matchers/test/bigNumber.ts | 17 +- .../test/changeEtherBalance.ts | 144 +-- .../test/changeEtherBalances.ts | 38 +- .../test/changeTokenBalance.ts | 117 +- .../hardhat-chai-matchers/test/contracts.ts | 127 ++ packages/hardhat-chai-matchers/test/events.ts | 57 +- .../hardhat-project/hardhat.config.js | 3 + .../hardhat-chai-matchers/test/helpers.ts | 8 +- packages/hardhat-chai-matchers/test/panic.ts | 4 +- .../test/reverted/reverted.ts | 25 +- .../test/reverted/revertedWith.ts | 31 +- .../test/reverted/revertedWithCustomError.ts | 36 +- .../test/reverted/revertedWithPanic.ts | 38 +- .../test/reverted/revertedWithoutReason.ts | 19 +- packages/hardhat-ethers/.eslintrc.js | 3 + packages/hardhat-ethers/package.json | 6 +- .../src/dist/src/signer-with-address.ts | 2 +- .../src/internal/custom-ethers-provider.ts | 683 +++++++++++ .../hardhat-ethers/src/internal/errors.ts | 35 + .../src/internal/ethers-provider-wrapper.ts | 34 - .../src/internal/ethers-utils.ts | 459 ++++++++ .../hardhat-ethers/src/internal/helpers.ts | 247 ++-- packages/hardhat-ethers/src/internal/index.ts | 33 +- .../src/internal/provider-proxy.ts | 33 - .../src/internal/updatable-target-proxy.ts | 106 -- packages/hardhat-ethers/src/signers.ts | 299 ++++- packages/hardhat-ethers/src/types/index.ts | 47 +- .../test/custom-ethers-provider.ts | 1043 +++++++++++++++++ .../test/custom-ethers-signer.ts | 299 +++++ .../test/ethers-provider-wrapper.ts | 51 - .../hardhat-ethers/test/example-contracts.ts | 58 + .../hardhat-project-with-gas-auto/.gitignore | 2 + .../hardhat.config.js | 10 + .../minimal-project/hardhat.config.js | 5 + packages/hardhat-ethers/test/helpers.ts | 44 +- packages/hardhat-ethers/test/index.ts | 741 ++++++------ packages/hardhat-ethers/test/no-accounts.ts | 42 +- .../test/updatable-target-proxy.ts | 201 ---- yarn.lock | 53 + 59 files changed, 4310 insertions(+), 1605 deletions(-) create mode 100644 packages/hardhat-chai-matchers/src/internal/constants.ts create mode 100644 packages/hardhat-chai-matchers/src/internal/utils.ts create mode 100644 packages/hardhat-chai-matchers/test/contracts.ts create mode 100644 packages/hardhat-ethers/src/internal/custom-ethers-provider.ts create mode 100644 packages/hardhat-ethers/src/internal/errors.ts delete mode 100644 packages/hardhat-ethers/src/internal/ethers-provider-wrapper.ts create mode 100644 packages/hardhat-ethers/src/internal/ethers-utils.ts delete mode 100644 packages/hardhat-ethers/src/internal/provider-proxy.ts delete mode 100644 packages/hardhat-ethers/src/internal/updatable-target-proxy.ts create mode 100644 packages/hardhat-ethers/test/custom-ethers-provider.ts create mode 100644 packages/hardhat-ethers/test/custom-ethers-signer.ts delete mode 100644 packages/hardhat-ethers/test/ethers-provider-wrapper.ts create mode 100644 packages/hardhat-ethers/test/example-contracts.ts create mode 100644 packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/.gitignore create mode 100644 packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/hardhat.config.js create mode 100644 packages/hardhat-ethers/test/fixture-projects/minimal-project/hardhat.config.js delete mode 100644 packages/hardhat-ethers/test/updatable-target-proxy.ts diff --git a/config/eslint/eslintrc.js b/config/eslint/eslintrc.js index 0d563e5981..f33ff32f2c 100644 --- a/config/eslint/eslintrc.js +++ b/config/eslint/eslintrc.js @@ -191,7 +191,7 @@ module.exports = { "no-cond-assign": "error", "no-debugger": "error", "no-duplicate-case": "error", - "no-duplicate-imports": "error", + "@typescript-eslint/no-duplicate-imports": "error", "no-eval": "error", "no-extra-bind": "error", "no-new-func": "error", diff --git a/packages/hardhat-chai-matchers/.eslintrc.js b/packages/hardhat-chai-matchers/.eslintrc.js index 44ed8ed6d5..7f3a838a47 100644 --- a/packages/hardhat-chai-matchers/.eslintrc.js +++ b/packages/hardhat-chai-matchers/.eslintrc.js @@ -4,4 +4,7 @@ module.exports = { project: `${__dirname}/src/tsconfig.json`, sourceType: "module", }, + rules: { + "@typescript-eslint/no-non-null-assertion": "error" + } }; diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index a3732936d3..6427bd7ddc 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-chai-matchers", - "version": "1.0.6", + "version": "2.0.0", "description": "Hardhat utils for testing", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-chai-matchers", "repository": "github:nomicfoundation/hardhat", @@ -19,7 +19,7 @@ "lint:fix": "yarn prettier --write && yarn eslint --fix", "eslint": "eslint 'src/**/*.ts' 'test/**/*.ts'", "prettier": "prettier \"**/*.{js,md,json}\"", - "test": "mocha --recursive \"test/**/*.ts\" --exit --reporter dot", + "test": "mocha --recursive \"test/**/*.ts\" --exit", "test:ci": "yarn test && node scripts/check-subpath-exports.js", "build": "tsc --build .", "prepublishOnly": "yarn build", @@ -37,7 +37,7 @@ "README.md" ], "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-ethers": "^3.0.0", "@types/bn.js": "^5.1.0", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", @@ -52,7 +52,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^5.0.0", + "ethers": "^6.1.0", "get-port": "^5.1.1", "hardhat": "^2.9.4", "mocha": "^10.0.0", @@ -62,9 +62,9 @@ "typescript": "~4.7.4" }, "peerDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-ethers": "^3.0.0", "chai": "^4.2.0", - "ethers": "^5.0.0", + "ethers": "^6.1.0", "hardhat": "^2.9.4" }, "dependencies": { diff --git a/packages/hardhat-chai-matchers/src/internal/changeEtherBalance.ts b/packages/hardhat-chai-matchers/src/internal/changeEtherBalance.ts index 50def56b7f..e0383d29ec 100644 --- a/packages/hardhat-chai-matchers/src/internal/changeEtherBalance.ts +++ b/packages/hardhat-chai-matchers/src/internal/changeEtherBalance.ts @@ -1,33 +1,40 @@ -import type { BigNumberish, providers } from "ethers"; +import type { + Addressable, + BigNumberish, + TransactionResponse, + default as EthersT, +} from "ethers"; import { buildAssert } from "../utils"; import { ensure } from "./calledOnContract/utils"; -import { Account, getAddressOf } from "./misc/account"; +import { getAddressOf } from "./misc/account"; import { BalanceChangeOptions } from "./misc/balance"; +import { assertIsNotNull } from "./utils"; export function supportChangeEtherBalance(Assertion: Chai.AssertionStatic) { Assertion.addMethod( "changeEtherBalance", function ( this: any, - account: Account | string, + account: Addressable | string, balanceChange: BigNumberish, options?: BalanceChangeOptions ) { - const { BigNumber } = require("ethers"); - + const { toBigInt } = require("ethers") as typeof EthersT; // capture negated flag before async code executes; see buildAssert's jsdoc const negated = this.__flags.negate; const subject = this._obj; const checkBalanceChange = ([actualChange, address]: [ - typeof BigNumber, + bigint, string ]) => { const assert = buildAssert(negated, checkBalanceChange); + const expectedChange = toBigInt(balanceChange); + assert( - actualChange.eq(BigNumber.from(balanceChange)), + actualChange === expectedChange, `Expected the ether balance of "${address}" to change by ${balanceChange.toString()} wei, but it changed by ${actualChange.toString()} wei`, `Expected the ether balance of "${address}" NOT to change by ${balanceChange.toString()} wei, but it did` ); @@ -47,19 +54,16 @@ export function supportChangeEtherBalance(Assertion: Chai.AssertionStatic) { export async function getBalanceChange( transaction: - | providers.TransactionResponse - | Promise - | (() => - | Promise - | providers.TransactionResponse), - account: Account | string, + | TransactionResponse + | Promise + | (() => Promise | TransactionResponse), + account: Addressable | string, options?: BalanceChangeOptions -) { - const { BigNumber } = await import("ethers"); +): Promise { const hre = await import("hardhat"); const provider = hre.network.provider; - let txResponse: providers.TransactionResponse; + let txResponse: TransactionResponse; if (typeof transaction === "function") { txResponse = await transaction(); @@ -68,6 +72,7 @@ export async function getBalanceChange( } const txReceipt = await txResponse.wait(); + assertIsNotNull(txReceipt, "txReceipt"); const txBlockNumber = txReceipt.blockNumber; const block = await provider.send("eth_getBlockByHash", [ @@ -83,23 +88,26 @@ export async function getBalanceChange( const address = await getAddressOf(account); - const balanceAfter = await provider.send("eth_getBalance", [ + const balanceAfterHex = await provider.send("eth_getBalance", [ address, `0x${txBlockNumber.toString(16)}`, ]); - const balanceBefore = await provider.send("eth_getBalance", [ + const balanceBeforeHex = await provider.send("eth_getBalance", [ address, `0x${(txBlockNumber - 1).toString(16)}`, ]); + const balanceAfter = BigInt(balanceAfterHex); + const balanceBefore = BigInt(balanceBeforeHex); + if (options?.includeFee !== true && address === txResponse.from) { - const gasPrice = txReceipt.effectiveGasPrice ?? txResponse.gasPrice; + const gasPrice = txReceipt.gasPrice; const gasUsed = txReceipt.gasUsed; - const txFee = gasPrice.mul(gasUsed); + const txFee = gasPrice * gasUsed; - return BigNumber.from(balanceAfter).add(txFee).sub(balanceBefore); + return balanceAfter + txFee - balanceBefore; } else { - return BigNumber.from(balanceAfter).sub(balanceBefore); + return balanceAfter - balanceBefore; } } diff --git a/packages/hardhat-chai-matchers/src/internal/changeEtherBalances.ts b/packages/hardhat-chai-matchers/src/internal/changeEtherBalances.ts index e2be028cfd..2c972591f5 100644 --- a/packages/hardhat-chai-matchers/src/internal/changeEtherBalances.ts +++ b/packages/hardhat-chai-matchers/src/internal/changeEtherBalances.ts @@ -1,25 +1,26 @@ -import type { BigNumber, BigNumberish, providers } from "ethers"; +import type EthersT from "ethers"; +import type { Addressable, BigNumberish, TransactionResponse } from "ethers"; import ordinal from "ordinal"; import { buildAssert } from "../utils"; -import { getAddressOf, Account } from "./misc/account"; +import { getAddressOf } from "./misc/account"; import { BalanceChangeOptions, getAddresses, getBalances, } from "./misc/balance"; +import { assertIsNotNull } from "./utils"; export function supportChangeEtherBalances(Assertion: Chai.AssertionStatic) { Assertion.addMethod( "changeEtherBalances", function ( this: any, - accounts: Array, + accounts: Array, balanceChanges: BigNumberish[], options?: BalanceChangeOptions ) { - const { BigNumber } = require("ethers"); - + const { toBigInt } = require("ethers") as typeof EthersT; // capture negated flag before async code executes; see buildAssert's jsdoc const negated = this.__flags.negate; @@ -29,19 +30,19 @@ export function supportChangeEtherBalances(Assertion: Chai.AssertionStatic) { } const checkBalanceChanges = ([actualChanges, accountAddresses]: [ - Array, + bigint[], string[] ]) => { const assert = buildAssert(negated, checkBalanceChanges); assert( - actualChanges.every((change, ind) => - change.eq(BigNumber.from(balanceChanges[ind])) + actualChanges.every( + (change, ind) => change === toBigInt(balanceChanges[ind]) ), () => { const lines: string[] = []; - actualChanges.forEach((change: BigNumber, i) => { - if (!change.eq(BigNumber.from(balanceChanges[i]))) { + actualChanges.forEach((change: bigint, i) => { + if (change !== toBigInt(balanceChanges[i])) { lines.push( `Expected the ether balance of ${ accountAddresses[i] @@ -57,8 +58,8 @@ export function supportChangeEtherBalances(Assertion: Chai.AssertionStatic) { }, () => { const lines: string[] = []; - actualChanges.forEach((change: BigNumber, i) => { - if (change.eq(BigNumber.from(balanceChanges[i]))) { + actualChanges.forEach((change: bigint, i) => { + if (change === toBigInt(balanceChanges[i])) { lines.push( `Expected the ether balance of ${ accountAddresses[i] @@ -88,15 +89,14 @@ export function supportChangeEtherBalances(Assertion: Chai.AssertionStatic) { } export async function getBalanceChanges( - transaction: - | providers.TransactionResponse - | Promise, - accounts: Array, + transaction: TransactionResponse | Promise, + accounts: Array, options?: BalanceChangeOptions -) { +): Promise { const txResponse = await transaction; const txReceipt = await txResponse.wait(); + assertIsNotNull(txReceipt, "txReceipt"); const txBlockNumber = txReceipt.blockNumber; const balancesAfter = await getBalances(accounts, txBlockNumber); @@ -104,16 +104,16 @@ export async function getBalanceChanges( const txFees = await getTxFees(accounts, txResponse, options); - return balancesAfter.map((balance, ind) => - balance.add(txFees[ind]).sub(balancesBefore[ind]) + return balancesAfter.map( + (balance, ind) => balance + txFees[ind] - balancesBefore[ind] ); } async function getTxFees( - accounts: Array, - txResponse: providers.TransactionResponse, + accounts: Array, + txResponse: TransactionResponse, options?: BalanceChangeOptions -) { +): Promise { return Promise.all( accounts.map(async (account) => { if ( @@ -121,14 +121,15 @@ async function getTxFees( (await getAddressOf(account)) === txResponse.from ) { const txReceipt = await txResponse.wait(); - const gasPrice = txReceipt.effectiveGasPrice ?? txResponse.gasPrice; + assertIsNotNull(txReceipt, "txReceipt"); + const gasPrice = txReceipt.gasPrice ?? txResponse.gasPrice; const gasUsed = txReceipt.gasUsed; - const txFee = gasPrice.mul(gasUsed); + const txFee = gasPrice * gasUsed; return txFee; } - return 0; + return 0n; }) ); } diff --git a/packages/hardhat-chai-matchers/src/internal/changeTokenBalance.ts b/packages/hardhat-chai-matchers/src/internal/changeTokenBalance.ts index 7def041206..17a006ffba 100644 --- a/packages/hardhat-chai-matchers/src/internal/changeTokenBalance.ts +++ b/packages/hardhat-chai-matchers/src/internal/changeTokenBalance.ts @@ -1,14 +1,29 @@ import type EthersT from "ethers"; +import type { + Addressable, + BaseContract, + BaseContractMethod, + BigNumberish, + ContractTransactionResponse, +} from "ethers"; import { buildAssert } from "../utils"; import { ensure } from "./calledOnContract/utils"; -import { Account, getAddressOf } from "./misc/account"; - -type TransactionResponse = EthersT.providers.TransactionResponse; - -interface Token extends EthersT.Contract { - balanceOf(address: string, overrides?: any): Promise; -} +import { getAddressOf } from "./misc/account"; +import { assertIsNotNull } from "./utils"; + +type TransactionResponse = EthersT.TransactionResponse; + +export type Token = BaseContract & { + balanceOf: BaseContractMethod<[string], bigint, bigint>; + name: BaseContractMethod<[], string, string>; + transfer: BaseContractMethod< + [string, BigNumberish], + boolean, + ContractTransactionResponse + >; + symbol: BaseContractMethod<[], string, string>; +}; export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { Assertion.addMethod( @@ -16,7 +31,7 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { function ( this: any, token: Token, - account: Account | string, + account: Addressable | string, balanceChange: EthersT.BigNumberish ) { const ethers = require("ethers") as typeof EthersT; @@ -32,14 +47,14 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { checkToken(token, "changeTokenBalance"); const checkBalanceChange = ([actualChange, address, tokenDescription]: [ - EthersT.BigNumber, + bigint, string, string ]) => { const assert = buildAssert(negated, checkBalanceChange); assert( - actualChange.eq(ethers.BigNumber.from(balanceChange)), + actualChange === ethers.toBigInt(balanceChange), `Expected the balance of ${tokenDescription} tokens for "${address}" to change by ${balanceChange.toString()}, but it changed by ${actualChange.toString()}`, `Expected the balance of ${tokenDescription} tokens for "${address}" NOT to change by ${balanceChange.toString()}, but it did` ); @@ -63,7 +78,7 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { function ( this: any, token: Token, - accounts: Array, + accounts: Array, balanceChanges: EthersT.BigNumberish[] ) { const ethers = require("ethers") as typeof EthersT; @@ -76,13 +91,7 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { subject = subject(); } - checkToken(token, "changeTokenBalances"); - - if (accounts.length !== balanceChanges.length) { - throw new Error( - `The number of accounts (${accounts.length}) is different than the number of expected balance changes (${balanceChanges.length})` - ); - } + validateInput(this._obj, token, accounts, balanceChanges); const balanceChangesPromise = Promise.all( accounts.map((account) => getBalanceChange(subject, token, account)) @@ -93,12 +102,12 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { actualChanges, addresses, tokenDescription, - ]: [EthersT.BigNumber[], string[], string]) => { + ]: [bigint[], string[], string]) => { const assert = buildAssert(negated, checkBalanceChanges); assert( - actualChanges.every((change, ind) => - change.eq(ethers.BigNumber.from(balanceChanges[ind])) + actualChanges.every( + (change, ind) => change === ethers.toBigInt(balanceChanges[ind]) ), `Expected the balances of ${tokenDescription} tokens for ${ addresses as any @@ -127,12 +136,34 @@ export function supportChangeTokenBalance(Assertion: Chai.AssertionStatic) { ); } +function validateInput( + obj: any, + token: Token, + accounts: Array, + balanceChanges: EthersT.BigNumberish[] +) { + try { + checkToken(token, "changeTokenBalances"); + + if (accounts.length !== balanceChanges.length) { + throw new Error( + `The number of accounts (${accounts.length}) is different than the number of expected balance changes (${balanceChanges.length})` + ); + } + } catch (e) { + // if the input validation fails, we discard the subject since it could + // potentially be a rejected promise + Promise.resolve(obj).catch(() => {}); + throw e; + } +} + function checkToken(token: unknown, method: string) { - if (typeof token !== "object" || token === null || !("functions" in token)) { + if (typeof token !== "object" || token === null || !("interface" in token)) { throw new Error( `The first argument of ${method} must be the contract instance of the token` ); - } else if ((token as any).functions.balanceOf === undefined) { + } else if ((token as any).interface.getFunction("balanceOf") === null) { throw new Error("The given contract instance is not an ERC20 token"); } } @@ -140,7 +171,7 @@ function checkToken(token: unknown, method: string) { export async function getBalanceChange( transaction: TransactionResponse | Promise, token: Token, - account: Account | string + account: Addressable | string ) { const ethers = require("ethers") as typeof EthersT; const hre = await import("hardhat"); @@ -149,6 +180,7 @@ export async function getBalanceChange( const txResponse = await transaction; const txReceipt = await txResponse.wait(); + assertIsNotNull(txReceipt, "txReceipt"); const txBlockNumber = txReceipt.blockNumber; const block = await provider.send("eth_getBlockByHash", [ @@ -172,7 +204,7 @@ export async function getBalanceChange( blockTag: txBlockNumber - 1, }); - return ethers.BigNumber.from(balanceAfter).sub(balanceBefore); + return ethers.toBigInt(balanceAfter) - balanceBefore; } let tokenDescriptionsCache: Record = {}; @@ -182,8 +214,9 @@ let tokenDescriptionsCache: Record = {}; * exist, the address of the token is used. */ async function getTokenDescription(token: Token): Promise { - if (tokenDescriptionsCache[token.address] === undefined) { - let tokenDescription = ``; + const tokenAddress = await token.getAddress(); + if (tokenDescriptionsCache[tokenAddress] === undefined) { + let tokenDescription = ``; try { tokenDescription = await token.symbol(); } catch (e) { @@ -192,10 +225,10 @@ async function getTokenDescription(token: Token): Promise { } catch (e2) {} } - tokenDescriptionsCache[token.address] = tokenDescription; + tokenDescriptionsCache[tokenAddress] = tokenDescription; } - return tokenDescriptionsCache[token.address]; + return tokenDescriptionsCache[tokenAddress]; } // only used by tests diff --git a/packages/hardhat-chai-matchers/src/internal/constants.ts b/packages/hardhat-chai-matchers/src/internal/constants.ts new file mode 100644 index 0000000000..da752e9b4e --- /dev/null +++ b/packages/hardhat-chai-matchers/src/internal/constants.ts @@ -0,0 +1 @@ +export const ASSERTION_ABORTED = "hh-chai-matchers-assertion-aborted"; diff --git a/packages/hardhat-chai-matchers/src/internal/emit.ts b/packages/hardhat-chai-matchers/src/internal/emit.ts index d6ea26791c..3dbd68842b 100644 --- a/packages/hardhat-chai-matchers/src/internal/emit.ts +++ b/packages/hardhat-chai-matchers/src/internal/emit.ts @@ -1,18 +1,17 @@ -import type { - providers, - utils as EthersUtils, - Contract, - Transaction, -} from "ethers"; +import type EthersT from "ethers"; +import type { Contract, Transaction } from "ethers"; import { AssertionError } from "chai"; import util from "util"; import ordinal from "ordinal"; import { AssertWithSsfi, buildAssert, Ssfi } from "../utils"; +import { ASSERTION_ABORTED } from "./constants"; +import { assertIsNotNull } from "./utils"; +import { HardhatChaiMatchersAssertionError } from "./errors"; -type EventFragment = EthersUtils.EventFragment; -type Interface = EthersUtils.Interface; -type Provider = providers.Provider; +type EventFragment = EthersT.EventFragment; +type Interface = EthersT.Interface; +type Provider = EthersT.Provider; export const EMIT_CALLED = "emitAssertionCalled"; @@ -20,7 +19,7 @@ async function waitForPendingTransaction( tx: Promise | Transaction | string, provider: Provider ) { - let hash: string | undefined; + let hash: string | null; if (tx instanceof Promise) { ({ hash } = await tx); } else if (typeof tx === "string") { @@ -28,10 +27,10 @@ async function waitForPendingTransaction( } else { ({ hash } = tx); } - if (hash === undefined) { + if (hash === null) { throw new Error(`${JSON.stringify(tx)} is not a valid transaction`); } - return provider.waitForTransaction(hash); + return provider.getTransactionReceipt(hash); } export function supportEmit( @@ -47,28 +46,39 @@ export function supportEmit( const promise = this.then === undefined ? Promise.resolve() : this; - const onSuccess = (receipt: providers.TransactionReceipt) => { + const onSuccess = (receipt: EthersT.TransactionReceipt) => { + // abort if the assertion chain was aborted, for example because + // a `.not` was combined with a `.withArgs` + if (chaiUtils.flag(this, ASSERTION_ABORTED) === true) { + return; + } + const assert = buildAssert(negated, onSuccess); - let eventFragment: EventFragment | undefined; + let eventFragment: EventFragment | null = null; try { eventFragment = contract.interface.getEvent(eventName); } catch (e) { // ignore error } - if (eventFragment === undefined) { + if (eventFragment === null) { throw new AssertionError( `Event "${eventName}" doesn't exist in the contract` ); } - const topic = contract.interface.getEventTopic(eventFragment); + const topic = eventFragment.topicHash; + const contractAddress = contract.target; + if (typeof contractAddress !== "string") { + throw new HardhatChaiMatchersAssertionError( + `The contract target should be a string` + ); + } this.logs = receipt.logs .filter((log) => log.topics.includes(topic)) .filter( - (log) => - log.address.toLowerCase() === contract.address.toLowerCase() + (log) => log.address.toLowerCase() === contractAddress.toLowerCase() ); assert( @@ -80,9 +90,26 @@ export function supportEmit( chaiUtils.flag(this, "contract", contract); }; - const derivedPromise = promise - .then(() => waitForPendingTransaction(tx, contract.provider)) - .then(onSuccess); + const derivedPromise = promise.then(() => { + // abort if the assertion chain was aborted, for example because + // a `.not` was combined with a `.withArgs` + if (chaiUtils.flag(this, ASSERTION_ABORTED) === true) { + return; + } + + if (contract.runner === null || contract.runner.provider === null) { + throw new HardhatChaiMatchersAssertionError( + "contract.runner.provider shouldn't be null" + ); + } + + return waitForPendingTransaction(tx, contract.runner.provider).then( + (receipt) => { + assertIsNotNull(receipt, "receipt"); + return onSuccess(receipt); + } + ); + }); chaiUtils.flag(this, EMIT_CALLED, true); @@ -124,11 +151,12 @@ function assertArgsArraysEqual( assert: AssertWithSsfi, ssfi: Ssfi ) { - const { utils } = require("ethers") as { utils: typeof EthersUtils }; - - const actualArgs = ( + const ethers = require("ethers") as typeof EthersT; + const parsedLog = ( chaiUtils.flag(context, "contract").interface as Interface - ).parseLog(log).args; + ).parseLog(log); + assertIsNotNull(parsedLog, "parsedLog"); + const actualArgs = parsedLog.args; const eventName = chaiUtils.flag(context, "eventName"); assert( actualArgs.length === expectedArgs.length, @@ -159,7 +187,7 @@ function assertArgsArraysEqual( } } else if (expectedArgs[index] instanceof Uint8Array) { new Assertion(actualArgs[index], undefined, ssfi, true).equal( - utils.hexlify(expectedArgs[index]) + ethers.hexlify(expectedArgs[index]) ); } else if ( expectedArgs[index]?.length !== undefined && @@ -195,10 +223,10 @@ function assertArgsArraysEqual( expectedArgs[index], "The actual value was an indexed and hashed value of the event argument. The expected value provided to the assertion should be the actual event argument (the pre-image of the hash). You provided the hash itself. Please supply the the actual event argument (the pre-image of the hash) instead." ); - const expectedArgBytes = utils.isHexString(expectedArgs[index]) - ? utils.arrayify(expectedArgs[index]) - : utils.toUtf8Bytes(expectedArgs[index]); - const expectedHash = utils.keccak256(expectedArgBytes); + const expectedArgBytes = ethers.isHexString(expectedArgs[index]) + ? ethers.getBytes(expectedArgs[index]) + : ethers.toUtf8Bytes(expectedArgs[index]); + const expectedHash = ethers.keccak256(expectedArgBytes); new Assertion(actualArgs[index].hash, undefined, ssfi, true).to.equal( expectedHash, `The actual value was an indexed and hashed value of the event argument. The expected value provided to the assertion was hashed to produce ${expectedHash}. The actual hash and the expected hash did not match` diff --git a/packages/hardhat-chai-matchers/src/internal/errors.ts b/packages/hardhat-chai-matchers/src/internal/errors.ts index c6f141cb69..87665ce845 100644 --- a/packages/hardhat-chai-matchers/src/internal/errors.ts +++ b/packages/hardhat-chai-matchers/src/internal/errors.ts @@ -1,9 +1,25 @@ -import { CustomError } from "hardhat/common"; +import { NomicLabsHardhatPluginError } from "hardhat/plugins"; -export class HardhatChaiMatchersDecodingError extends CustomError { +export class HardhatChaiMatchersError extends NomicLabsHardhatPluginError { + constructor(message: string, parent?: Error) { + super("@nomicfoundation/hardhat-chai-matchers", message, parent); + } +} + +export class HardhatChaiMatchersDecodingError extends HardhatChaiMatchersError { constructor(encodedData: string, type: string, parent: Error) { const message = `There was an error decoding '${encodedData}' as a ${type}`; super(message, parent); } } + +/** + * This class is used to assert assumptions in our implementation. Chai's + * AssertionError should be used for user assertions. + */ +export class HardhatChaiMatchersAssertionError extends HardhatChaiMatchersError { + constructor(message: string) { + super(`Assertion error: ${message}`); + } +} diff --git a/packages/hardhat-chai-matchers/src/internal/misc/account.ts b/packages/hardhat-chai-matchers/src/internal/misc/account.ts index ca77d3f87b..c4d7e536ce 100644 --- a/packages/hardhat-chai-matchers/src/internal/misc/account.ts +++ b/packages/hardhat-chai-matchers/src/internal/misc/account.ts @@ -1,21 +1,24 @@ -import type { Contract, Signer, Wallet } from "ethers"; +import type { Addressable } from "ethers"; import assert from "assert"; -export type Account = Signer | Contract; +import { HardhatChaiMatchersAssertionError } from "../errors"; -export function isAccount(account: Account): account is Contract | Wallet { - const ethers = require("ethers"); - return account instanceof ethers.Contract || account instanceof ethers.Wallet; -} +export async function getAddressOf( + account: Addressable | string +): Promise { + const { isAddressable } = await import("ethers"); -export async function getAddressOf(account: Account | string) { if (typeof account === "string") { assert(/^0x[0-9a-fA-F]{40}$/.test(account), `Invalid address ${account}`); return account; - } else if (isAccount(account)) { - return account.address; - } else { + } + + if (isAddressable(account)) { return account.getAddress(); } + + throw new HardhatChaiMatchersAssertionError( + `Expected string or addressable, got ${account as any}` + ); } diff --git a/packages/hardhat-chai-matchers/src/internal/misc/balance.ts b/packages/hardhat-chai-matchers/src/internal/misc/balance.ts index b70f6460e3..9bd93f6827 100644 --- a/packages/hardhat-chai-matchers/src/internal/misc/balance.ts +++ b/packages/hardhat-chai-matchers/src/internal/misc/balance.ts @@ -1,18 +1,20 @@ -import { Account, getAddressOf } from "./account"; +import type { Addressable } from "ethers"; + +import { getAddressOf } from "./account"; export interface BalanceChangeOptions { includeFee?: boolean; } -export function getAddresses(accounts: Array) { +export function getAddresses(accounts: Array) { return Promise.all(accounts.map((account) => getAddressOf(account))); } export async function getBalances( - accounts: Array, + accounts: Array, blockNumber?: number -) { - const { BigNumber } = await import("ethers"); +): Promise { + const { toBigInt } = await import("ethers"); const hre = await import("hardhat"); const provider = hre.ethers.provider; @@ -23,7 +25,7 @@ export async function getBalances( address, `0x${blockNumber?.toString(16) ?? 0}`, ]); - return BigNumber.from(result); + return toBigInt(result); }) ); } diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/panic.ts b/packages/hardhat-chai-matchers/src/internal/reverted/panic.ts index e94c5508fd..d64b7074ba 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/panic.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/panic.ts @@ -1,5 +1,3 @@ -import type { BigNumber } from "ethers"; - export const PANIC_CODES = { ASSERTION_ERROR: 0x1, ARITHMETIC_UNDER_OR_OVERFLOW: 0x11, @@ -13,27 +11,25 @@ export const PANIC_CODES = { }; // copied from hardhat-core -export function panicErrorCodeToReason( - errorCode: BigNumber -): string | undefined { - switch (errorCode.toNumber()) { - case 0x1: +export function panicErrorCodeToReason(errorCode: bigint): string | undefined { + switch (errorCode) { + case 0x1n: return "Assertion error"; - case 0x11: + case 0x11n: return "Arithmetic operation underflowed or overflowed outside of an unchecked block"; - case 0x12: + case 0x12n: return "Division or modulo division by zero"; - case 0x21: + case 0x21n: return "Tried to convert a value into an enum, but the value was too big or negative"; - case 0x22: + case 0x22n: return "Incorrectly encoded storage byte array"; - case 0x31: + case 0x31n: return ".pop() was called on an empty array"; - case 0x32: + case 0x32n: return "Array accessed at an out-of-bounds or negative index"; - case 0x41: + case 0x41n: return "Too much memory was allocated, or an array was created that is too large"; - case 0x51: + case 0x51n: return "Called a zero-initialized variable of internal function type"; } } diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/reverted.ts b/packages/hardhat-chai-matchers/src/internal/reverted/reverted.ts index 105dcdb445..57ba59340a 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/reverted.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/reverted.ts @@ -1,4 +1,7 @@ +import type EthersT from "ethers"; + import { buildAssert } from "../../utils"; +import { assertIsNotNull } from "../utils"; import { decodeReturnData, getReturnDataFromError } from "./utils"; export function supportReverted(Assertion: Chai.AssertionStatic) { @@ -27,6 +30,7 @@ export function supportReverted(Assertion: Chai.AssertionStatic) { const receipt = await getTransactionReceipt(hash); + assertIsNotNull(receipt, "receipt"); assert( receipt.status === 0, "Expected transaction to be reverted", @@ -52,6 +56,7 @@ export function supportReverted(Assertion: Chai.AssertionStatic) { }; const onError = (error: any) => { + const { toBeHex } = require("ethers") as typeof EthersT; const assert = buildAssert(negated, onError); const returnData = getReturnDataFromError(error); const decodedReturnData = decodeReturnData(returnData); @@ -73,9 +78,9 @@ export function supportReverted(Assertion: Chai.AssertionStatic) { assert( true, undefined, - `Expected transaction NOT to be reverted, but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })` + `Expected transaction NOT to be reverted, but it reverted with panic code ${toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})` ); } else { const _exhaustiveCheck: never = decodedReturnData; diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWith.ts b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWith.ts index 4b8d903405..4bd50ea865 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWith.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWith.ts @@ -1,3 +1,5 @@ +import type EthersT from "ethers"; + import { buildAssert } from "../../utils"; import { decodeReturnData, getReturnDataFromError } from "./utils"; @@ -13,6 +15,9 @@ export function supportRevertedWith(Assertion: Chai.AssertionStatic) { !(expectedReason instanceof RegExp) && typeof expectedReason !== "string" ) { + // if the input validation fails, we discard the subject since it could + // potentially be a rejected promise + Promise.resolve(this._obj).catch(() => {}); throw new TypeError( "Expected the revert reason to be a string or a regular expression" ); @@ -33,6 +38,7 @@ export function supportRevertedWith(Assertion: Chai.AssertionStatic) { }; const onError = (error: any) => { + const { toBeHex } = require("ethers") as typeof EthersT; const assert = buildAssert(negated, onError); const returnData = getReturnDataFromError(error); @@ -57,9 +63,9 @@ export function supportRevertedWith(Assertion: Chai.AssertionStatic) { } else if (decodedReturnData.kind === "Panic") { assert( false, - `Expected transaction to be reverted with reason '${expectedReasonString}', but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })` + `Expected transaction to be reverted with reason '${expectedReasonString}', but it reverted with panic code ${toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})` ); } else if (decodedReturnData.kind === "Custom") { assert( diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithCustomError.ts b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithCustomError.ts index f5e0ea26fd..afe5c66aa9 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithCustomError.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithCustomError.ts @@ -1,15 +1,23 @@ +import type EthersT from "ethers"; + import { AssertionError } from "chai"; import ordinal from "ordinal"; +import { ASSERTION_ABORTED } from "../constants"; +import { assertIsNotNull } from "../utils"; import { buildAssert, Ssfi } from "../../utils"; -import { decodeReturnData, getReturnDataFromError } from "./utils"; +import { + decodeReturnData, + getReturnDataFromError, + resultToArray, +} from "./utils"; export const REVERTED_WITH_CUSTOM_ERROR_CALLED = "customErrorAssertionCalled"; interface CustomErrorAssertionData { - contractInterface: any; + contractInterface: EthersT.Interface; returnData: string; - customError: CustomError; + customError: EthersT.ErrorFragment; } export function supportRevertedWithCustomError( @@ -18,38 +26,25 @@ export function supportRevertedWithCustomError( ) { Assertion.addMethod( "revertedWithCustomError", - function (this: any, contract: any, expectedCustomErrorName: string) { + function ( + this: any, + contract: EthersT.BaseContract, + expectedCustomErrorName: string + ) { // capture negated flag before async code executes; see buildAssert's jsdoc const negated = this.__flags.negate; - // check the case where users forget to pass the contract as the first - // argument - if (typeof contract === "string" || contract?.interface === undefined) { - throw new TypeError( - "The first argument of .revertedWithCustomError must be the contract that defines the custom error" - ); - } - - // validate custom error name - if (typeof expectedCustomErrorName !== "string") { - throw new TypeError("Expected the custom error name to be a string"); - } - - const iface: any = contract.interface; - - const expectedCustomError = findCustomErrorByName( - iface, + const { iface, expectedCustomError } = validateInput( + this._obj, + contract, expectedCustomErrorName ); - // check that interface contains the given custom error - if (expectedCustomError === undefined) { - throw new Error( - `The given contract doesn't have a custom error named '${expectedCustomErrorName}'` - ); - } - const onSuccess = () => { + if (utils.flag(this, ASSERTION_ABORTED) === true) { + return; + } + const assert = buildAssert(negated, onSuccess); assert( @@ -59,6 +54,12 @@ export function supportRevertedWithCustomError( }; const onError = (error: any) => { + if (utils.flag(this, ASSERTION_ABORTED) === true) { + return; + } + + const { toBeHex } = require("ethers") as typeof EthersT; + const assert = buildAssert(negated, onError); const returnData = getReturnDataFromError(error); @@ -77,12 +78,12 @@ export function supportRevertedWithCustomError( } else if (decodedReturnData.kind === "Panic") { assert( false, - `Expected transaction to be reverted with custom error '${expectedCustomErrorName}', but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })` + `Expected transaction to be reverted with custom error '${expectedCustomErrorName}', but it reverted with panic code ${toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})` ); } else if (decodedReturnData.kind === "Custom") { - if (decodedReturnData.id === expectedCustomError.id) { + if (decodedReturnData.id === expectedCustomError.selector) { // add flag with the data needed for .withArgs const customErrorAssertionData: CustomErrorAssertionData = { contractInterface: iface, @@ -99,12 +100,9 @@ export function supportRevertedWithCustomError( } else { // try to decode the actual custom error // this will only work when the error comes from the given contract - const actualCustomError = findCustomErrorById( - iface, - decodedReturnData.id - ); + const actualCustomError = iface.getError(decodedReturnData.id); - if (actualCustomError === undefined) { + if (actualCustomError === null) { assert( false, `Expected transaction to be reverted with custom error '${expectedCustomErrorName}', but it reverted with a different custom error` @@ -138,10 +136,49 @@ export function supportRevertedWithCustomError( ); } +function validateInput( + obj: any, + contract: EthersT.BaseContract, + expectedCustomErrorName: string +): { iface: EthersT.Interface; expectedCustomError: EthersT.ErrorFragment } { + try { + // check the case where users forget to pass the contract as the first + // argument + if (typeof contract === "string" || contract?.interface === undefined) { + // discard subject since it could potentially be a rejected promise + throw new TypeError( + "The first argument of .revertedWithCustomError must be the contract that defines the custom error" + ); + } + + // validate custom error name + if (typeof expectedCustomErrorName !== "string") { + throw new TypeError("Expected the custom error name to be a string"); + } + + const iface = contract.interface; + const expectedCustomError = iface.getError(expectedCustomErrorName); + + // check that interface contains the given custom error + if (expectedCustomError === null) { + throw new Error( + `The given contract doesn't have a custom error named '${expectedCustomErrorName}'` + ); + } + + return { iface, expectedCustomError }; + } catch (e) { + // if the input validation fails, we discard the subject since it could + // potentially be a rejected promise + Promise.resolve(obj).catch(() => {}); + throw e; + } +} + export async function revertedWithCustomErrorWithArgs( context: any, Assertion: Chai.AssertionStatic, - utils: Chai.ChaiUtils, + _utils: Chai.ChaiUtils, expectedArgs: any[], ssfi: Ssfi ) { @@ -160,9 +197,10 @@ export async function revertedWithCustomErrorWithArgs( const { contractInterface, customError, returnData } = customErrorAssertionData; - const errorFragment = contractInterface.errors[customError.signature]; + const errorFragment = contractInterface.getError(customError.name); + assertIsNotNull(errorFragment, "errorFragment"); // We transform ether's Array-like object into an actual array as it's safer - const actualArgs = Array.from( + const actualArgs = resultToArray( contractInterface.decodeErrorResult(errorFragment, returnData) ); @@ -210,51 +248,3 @@ export async function revertedWithCustomErrorWithArgs( } } } - -interface CustomError { - name: string; - id: string; - signature: string; -} - -function findCustomErrorByName( - iface: any, - name: string -): CustomError | undefined { - const ethers = require("ethers"); - - const customErrorEntry = Object.entries(iface.errors).find( - ([, fragment]: any) => fragment.name === name - ); - - if (customErrorEntry === undefined) { - return undefined; - } - - const [customErrorSignature] = customErrorEntry; - const customErrorId = ethers.utils.id(customErrorSignature).slice(0, 10); - - return { - id: customErrorId, - name, - signature: customErrorSignature, - }; -} - -function findCustomErrorById(iface: any, id: string): CustomError | undefined { - const ethers = require("ethers"); - - const customErrorEntry: any = Object.entries(iface.errors).find( - ([signature]: any) => ethers.utils.id(signature).slice(0, 10) === id - ); - - if (customErrorEntry === undefined) { - return undefined; - } - - return { - id, - name: customErrorEntry[1].name, - signature: customErrorEntry[0], - }; -} diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithPanic.ts b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithPanic.ts index 9ec6050d3d..022e3ab561 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithPanic.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithPanic.ts @@ -1,4 +1,4 @@ -import type { BigNumber } from "ethers"; +import type EthersT from "ethers"; import { normalizeToBigInt } from "hardhat/common"; @@ -10,33 +10,37 @@ export function supportRevertedWithPanic(Assertion: Chai.AssertionStatic) { Assertion.addMethod( "revertedWithPanic", function (this: any, expectedCodeArg: any) { - const ethers = require("ethers"); + const ethers = require("ethers") as typeof EthersT; // capture negated flag before async code executes; see buildAssert's jsdoc const negated = this.__flags.negate; - let expectedCode: BigNumber | undefined; + let expectedCode: bigint | undefined; try { if (expectedCodeArg !== undefined) { - const normalizedCode = normalizeToBigInt(expectedCodeArg); - expectedCode = ethers.BigNumber.from(normalizedCode); + expectedCode = normalizeToBigInt(expectedCodeArg); } } catch { + // if the input validation fails, we discard the subject since it could + // potentially be a rejected promise + Promise.resolve(this._obj).catch(() => {}); throw new TypeError( `Expected the given panic code to be a number-like value, but got '${expectedCodeArg}'` ); } - const code: number | undefined = expectedCode as any; + const code: bigint | undefined = expectedCode; let description: string | undefined; let formattedPanicCode: string; if (code === undefined) { formattedPanicCode = "some panic code"; } else { - const codeBN = ethers.BigNumber.from(code); + const codeBN = ethers.toBigInt(code); description = panicErrorCodeToReason(codeBN) ?? "unknown panic code"; - formattedPanicCode = `panic code ${codeBN.toHexString()} (${description})`; + formattedPanicCode = `panic code ${ethers.toBeHex( + codeBN + )} (${description})`; } const onSuccess = () => { @@ -67,19 +71,19 @@ export function supportRevertedWithPanic(Assertion: Chai.AssertionStatic) { } else if (decodedReturnData.kind === "Panic") { if (code !== undefined) { assert( - decodedReturnData.code.eq(code), - `Expected transaction to be reverted with ${formattedPanicCode}, but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })`, + decodedReturnData.code === code, + `Expected transaction to be reverted with ${formattedPanicCode}, but it reverted with panic code ${ethers.toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})`, `Expected transaction NOT to be reverted with ${formattedPanicCode}, but it was` ); } else { assert( true, undefined, - `Expected transaction NOT to be reverted with ${formattedPanicCode}, but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })` + `Expected transaction NOT to be reverted with ${formattedPanicCode}, but it reverted with panic code ${ethers.toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})` ); } } else if (decodedReturnData.kind === "Custom") { diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithoutReason.ts b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithoutReason.ts index f9a5286377..0a7da1a859 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithoutReason.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/revertedWithoutReason.ts @@ -1,3 +1,5 @@ +import type EthersT from "ethers"; + import { buildAssert } from "../../utils"; import { decodeReturnData, getReturnDataFromError } from "./utils"; @@ -16,6 +18,7 @@ export function supportRevertedWithoutReason(Assertion: Chai.AssertionStatic) { }; const onError = (error: any) => { + const { toBeHex } = require("ethers") as typeof EthersT; const assert = buildAssert(negated, onError); const returnData = getReturnDataFromError(error); @@ -35,9 +38,9 @@ export function supportRevertedWithoutReason(Assertion: Chai.AssertionStatic) { } else if (decodedReturnData.kind === "Panic") { assert( false, - `Expected transaction to be reverted without a reason, but it reverted with panic code ${decodedReturnData.code.toHexString()} (${ - decodedReturnData.description - })` + `Expected transaction to be reverted without a reason, but it reverted with panic code ${toBeHex( + decodedReturnData.code + )} (${decodedReturnData.description})` ); } else if (decodedReturnData.kind === "Custom") { assert( diff --git a/packages/hardhat-chai-matchers/src/internal/reverted/utils.ts b/packages/hardhat-chai-matchers/src/internal/reverted/utils.ts index 84d537ff7b..253ed71562 100644 --- a/packages/hardhat-chai-matchers/src/internal/reverted/utils.ts +++ b/packages/hardhat-chai-matchers/src/internal/reverted/utils.ts @@ -1,4 +1,4 @@ -import type { BigNumber } from "ethers"; +import type EthersT from "ethers"; import { AssertionError } from "chai"; @@ -51,7 +51,7 @@ type DecodedReturnData = } | { kind: "Panic"; - code: BigNumber; + code: bigint; description: string; } | { @@ -61,7 +61,9 @@ type DecodedReturnData = }; export function decodeReturnData(returnData: string): DecodedReturnData { - const { defaultAbiCoder: abi } = require("@ethersproject/abi"); + const { AbiCoder } = require("ethers") as typeof EthersT; + const abi = new AbiCoder(); + if (returnData === "0x") { return { kind: "Empty" }; } else if (returnData.startsWith(ERROR_STRING_PREFIX)) { @@ -79,7 +81,7 @@ export function decodeReturnData(returnData: string): DecodedReturnData { }; } else if (returnData.startsWith(PANIC_CODE_PREFIX)) { const encodedReason = returnData.slice(PANIC_CODE_PREFIX.length); - let code: BigNumber; + let code: bigint; try { code = abi.decode(["uint256"], `0x${encodedReason}`)[0]; } catch (e: any) { @@ -101,3 +103,25 @@ export function decodeReturnData(returnData: string): DecodedReturnData { data: `0x${returnData.slice(10)}`, }; } + +/** + * Takes an ethers result object and converts it into a (potentially nested) array. + * + * For example, given this error: + * + * struct Point(uint x, uint y) + * error MyError(string, Point) + * + * revert MyError("foo", Point(1, 2)) + * + * The resulting array will be: ["foo", [1n, 2n]] + */ +export function resultToArray(result: EthersT.Result): any[] { + return result + .toArray() + .map((x) => + typeof x === "object" && x !== null && "toArray" in x + ? resultToArray(x) + : x + ); +} diff --git a/packages/hardhat-chai-matchers/src/internal/utils.ts b/packages/hardhat-chai-matchers/src/internal/utils.ts new file mode 100644 index 0000000000..b3b672c2e4 --- /dev/null +++ b/packages/hardhat-chai-matchers/src/internal/utils.ts @@ -0,0 +1,12 @@ +import { HardhatChaiMatchersAssertionError } from "./errors"; + +export function assertIsNotNull( + value: T, + valueName: string +): asserts value is Exclude { + if (value === null) { + throw new HardhatChaiMatchersAssertionError( + `${valueName} should not be null` + ); + } +} diff --git a/packages/hardhat-chai-matchers/src/internal/withArgs.ts b/packages/hardhat-chai-matchers/src/internal/withArgs.ts index 856c055e59..29c3e3eda6 100644 --- a/packages/hardhat-chai-matchers/src/internal/withArgs.ts +++ b/packages/hardhat-chai-matchers/src/internal/withArgs.ts @@ -1,6 +1,7 @@ import { AssertionError } from "chai"; import { isBigNumber, normalizeToBigInt } from "hardhat/common"; +import { ASSERTION_ABORTED } from "./constants"; import { emitWithArgs, EMIT_CALLED } from "./emit"; import { @@ -51,24 +52,7 @@ export function supportWithArgs( utils: Chai.ChaiUtils ) { Assertion.addMethod("withArgs", function (this: any, ...expectedArgs: any[]) { - if (Boolean(this.__flags.negate)) { - throw new Error("Do not combine .not. with .withArgs()"); - } - - const emitCalled = utils.flag(this, EMIT_CALLED) === true; - const revertedWithCustomErrorCalled = - utils.flag(this, REVERTED_WITH_CUSTOM_ERROR_CALLED) === true; - - if (!emitCalled && !revertedWithCustomErrorCalled) { - throw new Error( - "withArgs can only be used in combination with a previous .emit or .revertedWithCustomError assertion" - ); - } - if (emitCalled && revertedWithCustomErrorCalled) { - throw new Error( - "withArgs called with both .emit and .revertedWithCustomError, but these assertions cannot be combined" - ); - } + const { emitCalled } = validateInput.call(this, utils); const promise = this.then === undefined ? Promise.resolve() : this; @@ -93,3 +77,39 @@ export function supportWithArgs( return this; }); } + +function validateInput( + this: any, + utils: Chai.ChaiUtils +): { emitCalled: boolean } { + try { + if (Boolean(this.__flags.negate)) { + throw new Error("Do not combine .not. with .withArgs()"); + } + + const emitCalled = utils.flag(this, EMIT_CALLED) === true; + const revertedWithCustomErrorCalled = + utils.flag(this, REVERTED_WITH_CUSTOM_ERROR_CALLED) === true; + + if (!emitCalled && !revertedWithCustomErrorCalled) { + throw new Error( + "withArgs can only be used in combination with a previous .emit or .revertedWithCustomError assertion" + ); + } + if (emitCalled && revertedWithCustomErrorCalled) { + throw new Error( + "withArgs called with both .emit and .revertedWithCustomError, but these assertions cannot be combined" + ); + } + + return { emitCalled }; + } catch (e) { + // signal that validation failed to allow the matchers to finish early + utils.flag(this, ASSERTION_ABORTED, true); + + // discard subject since it could potentially be a rejected promise + Promise.resolve(this._obj).catch(() => {}); + + throw e; + } +} diff --git a/packages/hardhat-chai-matchers/test/bigNumber.ts b/packages/hardhat-chai-matchers/test/bigNumber.ts index 2bfcff1967..7adb08c353 100644 --- a/packages/hardhat-chai-matchers/test/bigNumber.ts +++ b/packages/hardhat-chai-matchers/test/bigNumber.ts @@ -1,5 +1,4 @@ import { expect, AssertionError } from "chai"; -import { BigNumber as BigNumberEthers } from "ethers"; import { BigNumber as BigNumberJs } from "bignumber.js"; import BN from "bn.js"; @@ -7,11 +6,10 @@ import { HardhatError } from "hardhat/internal/core/errors"; import "../src/internal/add-chai-matchers"; -type SupportedNumber = number | bigint | BN | BigNumberEthers | BigNumberJs; +type SupportedNumber = number | bigint | BN | BigNumberJs; const numberToBigNumberConversions = [ (n: number) => BigInt(n), - (n: number) => BigNumberEthers.from(n), (n: number) => new BN(n), (n: number) => new BigNumberJs(n), ]; @@ -21,8 +19,6 @@ describe("BigNumber matchers", function () { if (typeof n === "object") { if (n instanceof BN) { return "BN"; - } else if (n instanceof BigNumberEthers) { - return "ethers.BigNumber"; } else if (n instanceof BigNumberJs) { return "bignumber.js"; } @@ -582,7 +578,6 @@ describe("BigNumber matchers", function () { // a few particular combinations of types don't work: if ( typeof convertedActual === "string" && - !BigNumberEthers.isBigNumber(convertedExpected) && !BN.isBN(convertedExpected) && !BigNumberJs.isBigNumber(convertedExpected) ) { @@ -1208,11 +1203,6 @@ describe("BigNumber matchers", function () { "custom message" ); - // number and ethers bignumber - expect(() => - expect(1).to.equal(BigNumberEthers.from(2), "custom message") - ).to.throw(AssertionError, "custom message"); - // same but for deep comparisons expect(() => expect([1]).to.equal([2], "custom message")).to.throw( AssertionError, @@ -1224,10 +1214,5 @@ describe("BigNumber matchers", function () { AssertionError, "custom message" ); - - // number and ethers bignumber - expect(() => - expect([1]).to.equal([BigNumberEthers.from(2)], "custom message") - ).to.throw(AssertionError, "custom message"); }); }); diff --git a/packages/hardhat-chai-matchers/test/changeEtherBalance.ts b/packages/hardhat-chai-matchers/test/changeEtherBalance.ts index 12fc629588..9c2647ff48 100644 --- a/packages/hardhat-chai-matchers/test/changeEtherBalance.ts +++ b/packages/hardhat-chai-matchers/test/changeEtherBalance.ts @@ -1,10 +1,10 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect, AssertionError } from "chai"; -import { BigNumber, Contract } from "ethers"; import path from "path"; import util from "util"; import "../src/internal/add-chai-matchers"; +import { ChangeEtherBalance } from "./contracts"; import { useEnvironment, useEnvironmentWithNode } from "./helpers"; describe("INTEGRATION: changeEtherBalance matcher", function () { @@ -14,7 +14,9 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { runTests(); }); - describe("connected to a hardhat node", function () { + // TODO re-enable this when + // https://github.com/ethers-io/ethers.js/issues/4014 is fixed + describe.skip("connected to a hardhat node", function () { useEnvironmentWithNode("hardhat-project"); runTests(); @@ -23,7 +25,7 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { function runTests() { let sender: SignerWithAddress; let receiver: SignerWithAddress; - let contract: Contract; + let contract: ChangeEtherBalance; let txGasFees: number; beforeEach(async function () { @@ -31,7 +33,9 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { sender = wallets[0]; receiver = wallets[1]; contract = await ( - await this.hre.ethers.getContractFactory("ChangeEtherBalance") + await this.hre.ethers.getContractFactory<[], ChangeEtherBalance>( + "ChangeEtherBalance" + ) ).deploy(); txGasFees = 1 * 21_000; await this.hre.network.provider.send( @@ -53,13 +57,22 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { it("Should fail when block contains more than one transaction", async function () { await this.hre.network.provider.send("evm_setAutomine", [false]); - await sender.sendTransaction({ to: receiver.address, value: 200 }); + + // we set a gas limit to avoid using the whole block gas limit + await sender.sendTransaction({ + to: receiver.address, + value: 200, + gasLimit: 30_000, + }); + await this.hre.network.provider.send("evm_setAutomine", [true]); + await expect( expect(() => sender.sendTransaction({ to: receiver.address, value: 200, + gasLimit: 30_000, }) ).to.changeEtherBalance(sender, -200, { includeFee: true }) ).to.be.eventually.rejectedWith( @@ -86,15 +99,6 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { ).to.changeEtherBalance(sender, BigInt("-200")); }); - it("Should pass when given an ethers BigNumber", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.changeEtherBalance(sender, BigNumber.from("-200")); - }); - it("Should pass when expected balance change is passed as int and is equal to an actual", async () => { await expect(() => sender.sendTransaction({ @@ -136,24 +140,6 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { ).to.changeEtherBalance(sender, -200); }); - it("Should pass when expected balance change is passed as BN and is equal to an actual", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.changeEtherBalance(receiver, BigNumber.from(200)); - }); - - it("Should pass on negative case when expected balance change is not equal to an actual", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.not.changeEtherBalance(receiver, BigNumber.from(300)); - }); - it("Should throw when fee was not calculated correctly", async () => { await expect( expect(() => @@ -206,7 +192,8 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { }); it("shouldn't run the transaction twice", async function () { - const receiverBalanceBefore = await receiver.getBalance(); + const receiverBalanceBefore: bigint = + await this.hre.ethers.provider.getBalance(receiver); await expect(() => sender.sendTransaction({ @@ -215,11 +202,12 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { }) ).to.changeEtherBalance(sender, -200); - const receiverBalanceChange = (await receiver.getBalance()).sub( - receiverBalanceBefore - ); + const receiverBalanceAfter: bigint = + await this.hre.ethers.provider.getBalance(receiver); + const receiverBalanceChange = + receiverBalanceAfter - receiverBalanceBefore; - expect(receiverBalanceChange.toNumber()).to.equal(200); + expect(receiverBalanceChange).to.equal(200n); }); }); @@ -227,7 +215,7 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { it("Should pass when expected balance change is passed as int and is equal to an actual", async () => { await expect(async () => sender.sendTransaction({ - to: contract.address, + to: contract, value: 200, }) ).to.changeEtherBalance(contract, 200); @@ -300,28 +288,6 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { ).to.changeEtherBalance(sender, -200); }); - it("Should pass when expected balance change is passed as BN and is equal to an actual", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - maxFeePerGas: 2, - maxPriorityFeePerGas: 1, - value: 200, - }) - ).to.changeEtherBalance(receiver, BigNumber.from(200)); - }); - - it("Should pass on negative case when expected balance change is not equal to an actual", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - maxFeePerGas: 2, - maxPriorityFeePerGas: 1, - value: 200, - }) - ).to.not.changeEtherBalance(receiver, BigNumber.from(300)); - }); - it("Should throw when fee was not calculated correctly", async () => { await expect( expect(() => @@ -377,7 +343,7 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { it("Should pass when expected balance change is passed as int and is equal to an actual", async () => { await expect(async () => sender.sendTransaction({ - to: contract.address, + to: contract, maxFeePerGas: 2, maxPriorityFeePerGas: 1, value: 200, @@ -387,17 +353,17 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { it("Should take into account transaction fee", async function () { const tx = { - to: contract.address, + to: contract, maxFeePerGas: 2, maxPriorityFeePerGas: 1, value: 200, }; - const gas = await this.hre.ethers.provider.estimateGas(tx); + const gas: bigint = await this.hre.ethers.provider.estimateGas(tx); await expect(() => sender.sendTransaction(tx)).to.changeEtherBalance( sender, - -gas.add(200).toNumber(), + -(gas + 200n), { includeFee: true, } @@ -416,7 +382,8 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { }); it("shouldn't run the transaction twice", async function () { - const receiverBalanceBefore = await receiver.getBalance(); + const receiverBalanceBefore: bigint = + await this.hre.ethers.provider.getBalance(receiver); await expect(() => sender.sendTransaction({ @@ -427,11 +394,12 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { }) ).to.changeEtherBalance(sender, -200); - const receiverBalanceChange = (await receiver.getBalance()).sub( - receiverBalanceBefore - ); + const receiverBalanceAfter: bigint = + await this.hre.ethers.provider.getBalance(receiver); + const receiverBalanceChange = + receiverBalanceAfter - receiverBalanceBefore; - expect(receiverBalanceChange.toNumber()).to.equal(200); + expect(receiverBalanceChange).to.equal(200n); }); }); @@ -455,24 +423,6 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { ).to.changeEtherBalance(receiver, 200); }); - it("Should pass when expected balance change is passed as BN and is equal to an actual", async () => { - await expect( - await sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.changeEtherBalance(sender, BigNumber.from(-200)); - }); - - it("Should pass on negative case when expected balance change is not equal to an actual", async () => { - await expect( - await sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.not.changeEtherBalance(receiver, BigNumber.from(300)); - }); - it("Should throw when expected balance change value was different from an actual", async () => { await expect( expect( @@ -506,7 +456,7 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { it("Should pass when expected balance change is passed as int and is equal to an actual", async () => { await expect( await sender.sendTransaction({ - to: contract.address, + to: contract, value: 200, }) ).to.changeEtherBalance(contract, 200); @@ -534,24 +484,6 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { ).to.changeEtherBalance(receiver, 200); }); - it("Should pass when expected balance change is passed as BN and is equal to an actual", async () => { - await expect( - sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.changeEtherBalance(sender, BigNumber.from(-200)); - }); - - it("Should pass on negative case when expected balance change is not equal to an actual", async () => { - await expect( - sender.sendTransaction({ - to: receiver.address, - value: 200, - }) - ).to.not.changeEtherBalance(receiver, BigNumber.from(300)); - }); - it("Should throw when expected balance change value was different from an actual", async () => { await expect( expect( diff --git a/packages/hardhat-chai-matchers/test/changeEtherBalances.ts b/packages/hardhat-chai-matchers/test/changeEtherBalances.ts index 3fbbde9a94..b88e48fead 100644 --- a/packages/hardhat-chai-matchers/test/changeEtherBalances.ts +++ b/packages/hardhat-chai-matchers/test/changeEtherBalances.ts @@ -1,10 +1,10 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect, AssertionError } from "chai"; -import { BigNumber, Contract } from "ethers"; import path from "path"; import util from "util"; import "../src/internal/add-chai-matchers"; +import { ChangeEtherBalance } from "./contracts"; import { useEnvironment, useEnvironmentWithNode } from "./helpers"; describe("INTEGRATION: changeEtherBalances matcher", function () { @@ -15,6 +15,7 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { }); describe("connected to a hardhat node", function () { + process.env.CHAIN_ID = "12345"; useEnvironmentWithNode("hardhat-project"); runTests(); @@ -23,7 +24,7 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { function runTests() { let sender: SignerWithAddress; let receiver: SignerWithAddress; - let contract: Contract; + let contract: ChangeEtherBalance; let txGasFees: number; beforeEach(async function () { @@ -31,7 +32,9 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { sender = wallets[0]; receiver = wallets[1]; contract = await ( - await this.hre.ethers.getContractFactory("ChangeEtherBalance") + await this.hre.ethers.getContractFactory<[], ChangeEtherBalance>( + "ChangeEtherBalance" + ) ).deploy(); txGasFees = 1 * 21_000; await this.hre.network.provider.send( @@ -45,7 +48,7 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { it("Should pass when all expected balance changes are equal to actual values", async () => { await expect(() => sender.sendTransaction({ - to: contract.address, + to: contract, value: 200, }) ).to.changeEtherBalances([sender, contract], [-200, 200]); @@ -100,19 +103,6 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { ); }); - it("Should pass when given ethers BigNumber", async () => { - await expect(() => - sender.sendTransaction({ - to: receiver.address, - gasPrice: 1, - value: 200, - }) - ).to.changeEtherBalances( - [sender, receiver], - [BigNumber.from("-200"), BigNumber.from(200)] - ); - }); - it("Should take into account transaction fee (legacy tx)", async () => { await expect(() => sender.sendTransaction({ @@ -213,7 +203,9 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { }); it("shouldn't run the transaction twice", async function () { - const receiverBalanceBefore = await receiver.getBalance(); + const receiverBalanceBefore = await this.hre.ethers.provider.getBalance( + receiver + ); await expect(() => sender.sendTransaction({ @@ -223,11 +215,13 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { }) ).to.changeEtherBalances([sender, receiver], [-200, 200]); - const receiverBalanceChange = (await receiver.getBalance()).sub( - receiverBalanceBefore + const receiverBalanceAfter = await this.hre.ethers.provider.getBalance( + receiver ); + const receiverBalanceChange = + receiverBalanceAfter - receiverBalanceBefore; - expect(receiverBalanceChange.toNumber()).to.equal(200); + expect(receiverBalanceChange).to.equal(200n); }); }); @@ -236,7 +230,7 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { it("Should pass when all expected balance changes are equal to actual values", async () => { await expect( await sender.sendTransaction({ - to: contract.address, + to: contract, value: 200, }) ).to.changeEtherBalances([sender, contract], [-200, 200]); diff --git a/packages/hardhat-chai-matchers/test/changeTokenBalance.ts b/packages/hardhat-chai-matchers/test/changeTokenBalance.ts index a180425095..51fc3088f4 100644 --- a/packages/hardhat-chai-matchers/test/changeTokenBalance.ts +++ b/packages/hardhat-chai-matchers/test/changeTokenBalance.ts @@ -1,16 +1,19 @@ +import type { TransactionResponse } from "ethers"; + import assert from "assert"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { AssertionError, expect } from "chai"; -import { BigNumber, Contract, providers } from "ethers"; import path from "path"; import util from "util"; import "../src/internal/add-chai-matchers"; -import { clearTokenDescriptionsCache } from "../src/internal/changeTokenBalance"; +import { + clearTokenDescriptionsCache, + Token, +} from "../src/internal/changeTokenBalance"; +import { MatchersContract } from "./contracts"; import { useEnvironment, useEnvironmentWithNode } from "./helpers"; -type TransactionResponse = providers.TransactionResponse; - describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", function () { describe("with the in-process hardhat network", function () { useEnvironment("hardhat-project"); @@ -31,21 +34,33 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun function runTests() { let sender: SignerWithAddress; let receiver: SignerWithAddress; - let mockToken: Contract; + let mockToken: Token; + let matchers: MatchersContract; beforeEach(async function () { const wallets = await this.hre.ethers.getSigners(); sender = wallets[0]; receiver = wallets[1]; - const MockToken = await this.hre.ethers.getContractFactory("MockToken"); + const MockToken = await this.hre.ethers.getContractFactory<[], Token>( + "MockToken" + ); mockToken = await MockToken.deploy(); + + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); + matchers = await Matchers.deploy(); }); describe("transaction that doesn't move tokens", () => { it("with a promise of a TxResponse", async function () { + const transactionResponse = sender.sendTransaction({ + to: receiver.address, + }); await runAllAsserts( - sender.sendTransaction({ to: receiver.address }), + transactionResponse, mockToken, [sender, receiver], [0, 0] @@ -232,11 +247,10 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun mockToken.transfer(receiver.address, 50) ).to.changeTokenBalance(mockToken, receiver, 50); - const receiverBalanceChange = ( - await mockToken.balanceOf(receiver.address) - ).sub(receiverBalanceBefore); + const receiverBalanceChange = + (await mockToken.balanceOf(receiver.address)) - receiverBalanceBefore; - expect(receiverBalanceChange.toNumber()).to.equal(50); + expect(receiverBalanceChange).to.equal(50n); }); it("changeTokenBalances shouldn't run the transaction twice", async function () { @@ -248,11 +262,10 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun mockToken.transfer(receiver.address, 50) ).to.changeTokenBalances(mockToken, [sender, receiver], [-50, 50]); - const receiverBalanceChange = ( - await mockToken.balanceOf(receiver.address) - ).sub(receiverBalanceBefore); + const receiverBalanceChange = + (await mockToken.balanceOf(receiver.address)) - receiverBalanceBefore; - expect(receiverBalanceChange.toNumber()).to.equal(50); + expect(receiverBalanceChange).to.equal(50n); }); it("negated", async function () { @@ -334,9 +347,10 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun }); it("uses the token name if the contract doesn't have a symbol", async function () { - const TokenWithOnlyName = await this.hre.ethers.getContractFactory( - "TokenWithOnlyName" - ); + const TokenWithOnlyName = await this.hre.ethers.getContractFactory< + [], + Token + >("TokenWithOnlyName"); const tokenWithOnlyName = await TokenWithOnlyName.deploy(); await expect( @@ -360,7 +374,7 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun it("uses the contract address if the contract doesn't have name or symbol", async function () { const TokenWithoutNameNorSymbol = - await this.hre.ethers.getContractFactory( + await this.hre.ethers.getContractFactory<[], Token>( "TokenWithoutNameNorSymbol" ); const tokenWithoutNameNorSymbol = @@ -429,13 +443,17 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun it("tx is not the only one in the block", async function () { await this.hre.network.provider.send("evm_setAutomine", [false]); - await sender.sendTransaction({ to: receiver.address }); + // we set a gas limit to avoid using the whole block gas limit + await sender.sendTransaction({ + to: receiver.address, + gasLimit: 30_000, + }); await this.hre.network.provider.send("evm_setAutomine", [true]); await expect( expect( - mockToken.transfer(receiver.address, 50) + mockToken.transfer(receiver.address, 50, { gasLimit: 100_000 }) ).to.changeTokenBalance(mockToken, sender, -50) ).to.be.rejectedWith(Error, "Multiple transactions found in block"); }); @@ -501,16 +519,33 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun ); }); + it("arrays have different length, subject is a rejected promise", async function () { + expect(() => + expect(matchers.revertsWithoutReason()).to.changeTokenBalances( + mockToken, + [sender], + [-50, 50] + ) + ).to.throw( + Error, + "The number of accounts (1) is different than the number of expected balance changes (2)" + ); + }); + it("tx is not the only one in the block", async function () { await this.hre.network.provider.send("evm_setAutomine", [false]); - await sender.sendTransaction({ to: receiver.address }); + // we set a gas limit to avoid using the whole block gas limit + await sender.sendTransaction({ + to: receiver.address, + gasLimit: 30_000, + }); await this.hre.network.provider.send("evm_setAutomine", [true]); await expect( expect( - mockToken.transfer(receiver.address, 50) + mockToken.transfer(receiver.address, 50, { gasLimit: 100_000 }) ).to.changeTokenBalances(mockToken, [sender, receiver], [-50, 50]) ).to.be.rejectedWith(Error, "Multiple transactions found in block"); }); @@ -543,38 +578,6 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun [BigInt(-50), BigInt(50)] ); }); - - it("ethers's bignumbers are accepted", async function () { - await expect( - mockToken.transfer(receiver.address, 50) - ).to.changeTokenBalance(mockToken, sender, BigNumber.from(-50)); - - await expect( - mockToken.transfer(receiver.address, 50) - ).to.changeTokenBalances( - mockToken, - [sender, receiver], - [BigNumber.from(-50), BigNumber.from(50)] - ); - }); - - it("mixed types are accepted", async function () { - await expect( - mockToken.transfer(receiver.address, 50) - ).to.changeTokenBalances( - mockToken, - [sender, receiver], - [BigInt(-50), BigNumber.from(50)] - ); - - await expect( - mockToken.transfer(receiver.address, 50) - ).to.changeTokenBalances( - mockToken, - [sender, receiver], - [BigNumber.from(-50), BigInt(50)] - ); - }); }); // smoke tests for stack traces @@ -638,9 +641,9 @@ async function runAllAsserts( | Promise | (() => TransactionResponse) | (() => Promise), - token: Contract, + token: Token, accounts: Array, - balances: Array + balances: Array ) { // changeTokenBalances works for the given arrays await expect(expr).to.changeTokenBalances(token, accounts, balances); diff --git a/packages/hardhat-chai-matchers/test/contracts.ts b/packages/hardhat-chai-matchers/test/contracts.ts new file mode 100644 index 0000000000..c955e55bcc --- /dev/null +++ b/packages/hardhat-chai-matchers/test/contracts.ts @@ -0,0 +1,127 @@ +import { + BaseContract, + BaseContractMethod, + ContractTransactionResponse, + BigNumberish, +} from "ethers"; + +export type MatchersContract = BaseContract & { + panicAssert: BaseContractMethod<[], void, ContractTransactionResponse>; + revertWithCustomErrorWithInt: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + revertWithCustomErrorWithPair: BaseContractMethod< + [BigNumberish, BigNumberish], + void, + ContractTransactionResponse + >; + revertWithCustomErrorWithUint: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + revertWithCustomErrorWithUintAndString: BaseContractMethod< + [BigNumberish, string], + void, + ContractTransactionResponse + >; + revertWithSomeCustomError: BaseContractMethod< + [], + void, + ContractTransactionResponse + >; + revertsWith: BaseContractMethod<[string], void, ContractTransactionResponse>; + revertsWithoutReason: BaseContractMethod< + [], + void, + ContractTransactionResponse + >; + succeeds: BaseContractMethod<[], void, ContractTransactionResponse>; +}; + +export type ChangeEtherBalance = BaseContract & { + returnHalf: BaseContractMethod<[], void, ContractTransactionResponse>; + transferTo: BaseContractMethod<[string], void, ContractTransactionResponse>; +}; + +export type EventsContract = BaseContract & { + doNotEmit: BaseContractMethod<[], void, ContractTransactionResponse>; + emitBytes32: BaseContractMethod<[string], void, ContractTransactionResponse>; + emitBytes32Array: BaseContractMethod< + [string, string], + void, + ContractTransactionResponse + >; + emitBytes: BaseContractMethod<[string], void, ContractTransactionResponse>; + emitIndexedBytes32: BaseContractMethod< + [string], + void, + ContractTransactionResponse + >; + emitIndexedBytes: BaseContractMethod< + [string], + void, + ContractTransactionResponse + >; + emitIndexedString: BaseContractMethod< + [string], + void, + ContractTransactionResponse + >; + emitInt: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + emitNestedUintFromAnotherContract: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + emitNestedUintFromSameContract: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + emitString: BaseContractMethod<[string], void, ContractTransactionResponse>; + emitStruct: BaseContractMethod< + [BigNumberish, BigNumberish], + void, + ContractTransactionResponse + >; + emitTwoUints: BaseContractMethod< + [BigNumberish, BigNumberish], + void, + ContractTransactionResponse + >; + emitTwoUintsAndTwoStrings: BaseContractMethod< + [BigNumberish, BigNumberish, string, string], + void, + ContractTransactionResponse + >; + emitUint: BaseContractMethod< + [BigNumberish], + void, + ContractTransactionResponse + >; + emitUintAndString: BaseContractMethod< + [BigNumberish, string], + void, + ContractTransactionResponse + >; + emitUintArray: BaseContractMethod< + [BigNumberish, BigNumberish], + void, + ContractTransactionResponse + >; + emitUintTwice: BaseContractMethod< + [BigNumberish, BigNumberish], + void, + ContractTransactionResponse + >; + emitWithoutArgs: BaseContractMethod<[], void, ContractTransactionResponse>; +}; + +export type AnotherContract = BaseContract & {}; diff --git a/packages/hardhat-chai-matchers/test/events.ts b/packages/hardhat-chai-matchers/test/events.ts index 7bd6dd7f6d..88392ccedf 100644 --- a/packages/hardhat-chai-matchers/test/events.ts +++ b/packages/hardhat-chai-matchers/test/events.ts @@ -1,15 +1,17 @@ import { expect, AssertionError } from "chai"; -import { BigNumber, Contract, ethers } from "ethers"; +import { ethers } from "ethers"; import { anyUint, anyValue } from "../src/withArgs"; import { useEnvironment, useEnvironmentWithNode } from "./helpers"; import "../src/internal/add-chai-matchers"; +import { AnotherContract, EventsContract, MatchersContract } from "./contracts"; describe(".to.emit (contract events)", () => { - let contract: Contract; - let otherContract: Contract; + let contract: EventsContract; + let otherContract: AnotherContract; + let matchers: MatchersContract; describe("with the in-process hardhat network", function () { useEnvironment("hardhat-project"); @@ -28,9 +30,18 @@ describe(".to.emit (contract events)", () => { otherContract = await ( await this.hre.ethers.getContractFactory("AnotherContract") ).deploy(); + contract = await ( - await this.hre.ethers.getContractFactory("Events") - ).deploy(otherContract.address); + await this.hre.ethers.getContractFactory<[string], EventsContract>( + "Events" + ) + ).deploy(await otherContract.getAddress()); + + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); + matchers = await Matchers.deploy(); }); it("Should fail when expecting an event that's not in the contract", async function () { @@ -82,6 +93,14 @@ describe(".to.emit (contract events)", () => { ).to.throw(Error, "Do not combine .not. with .withArgs()"); }); + it("Should fail when used with .not, subject is a rejected promise", async function () { + expect(() => + expect(matchers.revertsWithoutReason()) + .not.to.emit(contract, "WithUintArg") + .withArgs(1) + ).to.throw(Error, "Do not combine .not. with .withArgs()"); + }); + it("should fail if withArgs is called on its own", async function () { expect(() => expect(contract.emitUint(1)) @@ -124,13 +143,9 @@ describe(".to.emit (contract events)", () => { }); const string1 = "string1"; - const string1Bytes = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes(string1) - ); + const string1Bytes = ethers.hexlify(ethers.toUtf8Bytes(string1)); const string2 = "string2"; - const string2Bytes = ethers.utils.hexlify( - ethers.utils.toUtf8Bytes(string2) - ); + const string2Bytes = ethers.hexlify(ethers.toUtf8Bytes(string2)); // for abbreviating long strings in diff views like chai does: function abbrev(longString: string): string { @@ -138,7 +153,7 @@ describe(".to.emit (contract events)", () => { } function hash(s: string): string { - return ethers.utils.keccak256(s); + return ethers.keccak256(s); } describe("with a string argument", function () { @@ -264,8 +279,8 @@ describe(".to.emit (contract events)", () => { }); }); - const string1Bytes32 = ethers.utils.zeroPad(string1Bytes, 32); - const string2Bytes32 = ethers.utils.zeroPad(string2Bytes, 32); + const string1Bytes32 = ethers.zeroPadValue(string1Bytes, 32); + const string2Bytes32 = ethers.zeroPadValue(string2Bytes, 32); describe("with a bytes32 argument", function () { it("Should match the argument", async function () { await expect(contract.emitBytes32(string1Bytes32)) @@ -281,8 +296,8 @@ describe(".to.emit (contract events)", () => { ).to.be.eventually.rejectedWith( AssertionError, `expected '${abbrev( - ethers.utils.hexlify(string2Bytes32) - )}' to equal '${abbrev(ethers.utils.hexlify(string1Bytes32))}'` + ethers.hexlify(string2Bytes32) + )}' to equal '${abbrev(ethers.hexlify(string1Bytes32))}'` ); }); }); @@ -302,8 +317,8 @@ describe(".to.emit (contract events)", () => { ).to.be.eventually.rejectedWith( AssertionError, `expected '${abbrev( - ethers.utils.hexlify(string2Bytes32) - )}' to equal '${abbrev(ethers.utils.hexlify(string1Bytes32))}'` + ethers.hexlify(string2Bytes32) + )}' to equal '${abbrev(ethers.hexlify(string1Bytes32))}'` ); }); @@ -321,12 +336,6 @@ describe(".to.emit (contract events)", () => { .withArgs([1, 2]); }); - it("Should succeed when expectations are met with BigNumber", async function () { - await expect(contract.emitUintArray(1, 2)) - .to.emit(contract, "WithUintArray") - .withArgs([BigInt(1), BigNumber.from(2)]); - }); - it("Should fail when expectations are not met", async function () { await expect( expect(contract.emitUintArray(1, 2)) diff --git a/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js b/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js index 1940c36a74..10d1d15ed6 100644 --- a/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js +++ b/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js @@ -3,6 +3,9 @@ require("@nomiclabs/hardhat-ethers"); module.exports = { solidity: "0.8.4", networks: { + hardhat: { + chainId: Number(process.env.CHAIN_ID ?? "31337"), + }, localhost: { url: `http://127.0.0.1:${process.env.HARDHAT_NODE_PORT}`, }, diff --git a/packages/hardhat-chai-matchers/test/helpers.ts b/packages/hardhat-chai-matchers/test/helpers.ts index 1aa41438f0..de2dc7e889 100644 --- a/packages/hardhat-chai-matchers/test/helpers.ts +++ b/packages/hardhat-chai-matchers/test/helpers.ts @@ -118,8 +118,8 @@ export async function runSuccessfulAsserts({ }) { await successfulAssert(matchers[method](...args)); await successfulAssert(matchers[`${method}View`](...args)); - await successfulAssert(matchers.estimateGas[method](...args)); - await successfulAssert(matchers.callStatic[method](...args)); + await successfulAssert(matchers[method].estimateGas(...args)); + await successfulAssert(matchers[method].staticCall(...args)); } /** @@ -147,9 +147,9 @@ export async function runFailedAsserts({ failedAssert(matchers[`${method}View`](...args)) ).to.be.rejectedWith(AssertionError, failedAssertReason); await expect( - failedAssert(matchers.estimateGas[method](...args)) + failedAssert(matchers[method].estimateGas(...args)) ).to.be.rejectedWith(AssertionError, failedAssertReason); await expect( - failedAssert(matchers.callStatic[method](...args)) + failedAssert(matchers[method].staticCall(...args)) ).to.be.rejectedWith(AssertionError, failedAssertReason); } diff --git a/packages/hardhat-chai-matchers/test/panic.ts b/packages/hardhat-chai-matchers/test/panic.ts index 1f19ebe993..efb6549161 100644 --- a/packages/hardhat-chai-matchers/test/panic.ts +++ b/packages/hardhat-chai-matchers/test/panic.ts @@ -1,5 +1,5 @@ import { assert } from "chai"; -import { BigNumber } from "ethers"; +import { toBigInt } from "ethers"; import { PANIC_CODES, @@ -9,7 +9,7 @@ import { describe("panic codes", function () { it("all exported panic codes should have a description", async function () { for (const [key, code] of Object.entries(PANIC_CODES)) { - const description = panicErrorCodeToReason(BigNumber.from(code)); + const description = panicErrorCodeToReason(toBigInt(code)); assert.isDefined(description, `No description for panic code ${key}`); } }); diff --git a/packages/hardhat-chai-matchers/test/reverted/reverted.ts b/packages/hardhat-chai-matchers/test/reverted/reverted.ts index 18ab3b12dc..4d7a378536 100644 --- a/packages/hardhat-chai-matchers/test/reverted/reverted.ts +++ b/packages/hardhat-chai-matchers/test/reverted/reverted.ts @@ -11,6 +11,7 @@ import { } from "../helpers"; import "../../src/internal/add-chai-matchers"; +import { MatchersContract } from "../contracts"; describe("INTEGRATION: Reverted", function () { describe("with the in-process hardhat network", function () { @@ -27,9 +28,12 @@ describe("INTEGRATION: Reverted", function () { function runTests() { // deploy Matchers contract before each test - let matchers: any; + let matchers: MatchersContract; beforeEach("deploy matchers contract", async function () { - const Matchers = await this.hre.ethers.getContractFactory("Matchers"); + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); matchers = await Matchers.deploy(); }); @@ -189,9 +193,9 @@ describe("INTEGRATION: Reverted", function () { it("TxReceipt of a reverted transaction", async function () { const tx = await mineRevertedTransaction(this.hre); - const receipt = await this.hre.ethers.provider.waitForTransaction( + const receipt = await this.hre.ethers.provider.getTransactionReceipt( tx.hash - ); // tx.wait rejects, so we use provider.waitForTransaction + ); // tx.wait rejects, so we use provider.getTransactionReceipt await expect(receipt).to.be.reverted; await expectAssertionError( @@ -213,9 +217,9 @@ describe("INTEGRATION: Reverted", function () { it("promise of a TxReceipt of a reverted transaction", async function () { const tx = await mineRevertedTransaction(this.hre); - const receiptPromise = this.hre.ethers.provider.waitForTransaction( + const receiptPromise = this.hre.ethers.provider.getTransactionReceipt( tx.hash - ); // tx.wait rejects, so we use provider.waitForTransaction + ); // tx.wait rejects, so we use provider.getTransactionReceipt await expect(receiptPromise).to.be.reverted; await expectAssertionError( @@ -352,12 +356,15 @@ describe("INTEGRATION: Reverted", function () { randomPrivateKey, this.hre.ethers.provider ); + const matchersFromSenderWithoutFunds = matchers.connect( + signer + ) as MatchersContract; // this transaction will fail because of lack of funds, not because of a // revert await expect( expect( - matchers.connect(signer).revertsWithoutReason({ + matchersFromSenderWithoutFunds.revertsWithoutReason({ gasLimit: 1_000_000, }) ).to.not.be.reverted @@ -374,7 +381,9 @@ describe("INTEGRATION: Reverted", function () { try { await expect(matchers.succeeds()).to.be.reverted; } catch (e: any) { - expect(util.inspect(e)).to.include( + const errorString = util.inspect(e); + expect(errorString).to.include("Expected transaction to be reverted"); + expect(errorString).to.include( path.join("test", "reverted", "reverted.ts") ); diff --git a/packages/hardhat-chai-matchers/test/reverted/revertedWith.ts b/packages/hardhat-chai-matchers/test/reverted/revertedWith.ts index ca4257c6d7..02ffe4298c 100644 --- a/packages/hardhat-chai-matchers/test/reverted/revertedWith.ts +++ b/packages/hardhat-chai-matchers/test/reverted/revertedWith.ts @@ -11,6 +11,7 @@ import { } from "../helpers"; import "../../src/internal/add-chai-matchers"; +import { MatchersContract } from "../contracts"; describe("INTEGRATION: Reverted with", function () { describe("with the in-process hardhat network", function () { @@ -27,10 +28,13 @@ describe("INTEGRATION: Reverted with", function () { function runTests() { // deploy Matchers contract before each test - let matchers: any; + let matchers: MatchersContract; beforeEach("deploy matchers contract", async function () { - const Matchers = await this.hre.ethers.getContractFactory("Matchers"); + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); matchers = await Matchers.deploy(); }); @@ -213,6 +217,18 @@ describe("INTEGRATION: Reverted with", function () { ); }); + it("non-string as expectation, subject is a rejected promise", async function () { + const tx = matchers.revertsWithoutReason(); + + expect(() => + // @ts-expect-error + expect(tx).to.be.revertedWith(10) + ).to.throw( + TypeError, + "Expected the revert reason to be a string or a regular expression" + ); + }); + it("errors that are not related to a reverted transaction", async function () { // use an address that almost surely doesn't have balance const randomPrivateKey = @@ -221,12 +237,15 @@ describe("INTEGRATION: Reverted with", function () { randomPrivateKey, this.hre.ethers.provider ); + const matchersFromSenderWithoutFunds = matchers.connect( + signer + ) as MatchersContract; // this transaction will fail because of lack of funds, not because of a // revert await expect( expect( - matchers.connect(signer).revertsWithoutReason({ + matchersFromSenderWithoutFunds.revertsWithoutReason({ gasLimit: 1_000_000, }) ).to.not.be.revertedWith("some reason") @@ -243,7 +262,11 @@ describe("INTEGRATION: Reverted with", function () { try { await expect(matchers.revertsWith("bar")).to.be.revertedWith("foo"); } catch (e: any) { - expect(util.inspect(e)).to.include( + const errorString = util.inspect(e); + expect(errorString).to.include( + "Expected transaction to be reverted with reason 'foo', but it reverted with reason 'bar'" + ); + expect(errorString).to.include( path.join("test", "reverted", "revertedWith.ts") ); diff --git a/packages/hardhat-chai-matchers/test/reverted/revertedWithCustomError.ts b/packages/hardhat-chai-matchers/test/reverted/revertedWithCustomError.ts index e5a9d2a037..7df2848cd3 100644 --- a/packages/hardhat-chai-matchers/test/reverted/revertedWithCustomError.ts +++ b/packages/hardhat-chai-matchers/test/reverted/revertedWithCustomError.ts @@ -1,5 +1,4 @@ import { AssertionError, expect } from "chai"; -import { BigNumber } from "ethers"; import { ProviderError } from "hardhat/internal/core/providers/errors"; import path from "path"; import util from "util"; @@ -13,6 +12,7 @@ import { import "../../src/internal/add-chai-matchers"; import { anyUint, anyValue } from "../../src/withArgs"; +import { MatchersContract } from "../contracts"; describe("INTEGRATION: Reverted with custom error", function () { describe("with the in-process hardhat network", function () { @@ -29,9 +29,12 @@ describe("INTEGRATION: Reverted with custom error", function () { function runTests() { // deploy Matchers contract before each test - let matchers: any; + let matchers: MatchersContract; beforeEach("deploy matchers contract", async function () { - const Matchers = await this.hre.ethers.getContractFactory("Matchers"); + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); matchers = await Matchers.deploy(); }); @@ -368,20 +371,6 @@ describe("INTEGRATION: Reverted with custom error", function () { ); }); - it("should work with bigints and bignumbers", async function () { - await expect(matchers.revertWithCustomErrorWithUint(1)) - .to.be.revertedWithCustomError(matchers, "CustomErrorWithUint") - .withArgs(BigInt(1)); - - await expect(matchers.revertWithCustomErrorWithUint(1)) - .to.be.revertedWithCustomError(matchers, "CustomErrorWithUint") - .withArgs(BigNumber.from(1)); - - await expect(matchers.revertWithCustomErrorWithPair(1, 2)) - .to.be.revertedWithCustomError(matchers, "CustomErrorWithPair") - .withArgs([BigInt(1), BigNumber.from(2)]); - }); - it("should work with predicates", async function () { await expect(matchers.revertWithCustomErrorWithUint(1)) .to.be.revertedWithCustomError(matchers, "CustomErrorWithUint") @@ -460,12 +449,15 @@ describe("INTEGRATION: Reverted with custom error", function () { randomPrivateKey, this.hre.ethers.provider ); + const matchersFromSenderWithoutFunds = matchers.connect( + signer + ) as MatchersContract; // this transaction will fail because of lack of funds, not because of a // revert await expect( expect( - matchers.connect(signer).revertsWithoutReason({ + matchersFromSenderWithoutFunds.revertsWithoutReason({ gasLimit: 1_000_000, }) ).to.not.be.revertedWithCustomError(matchers, "SomeCustomError") @@ -481,10 +473,14 @@ describe("INTEGRATION: Reverted with custom error", function () { it("includes test file", async function () { try { await expect( - matchers.revertedWith("some reason") + matchers.revertsWith("some reason") ).to.be.revertedWithCustomError(matchers, "SomeCustomError"); } catch (e: any) { - expect(util.inspect(e)).to.include( + const errorString = util.inspect(e); + expect(errorString).to.include( + "Expected transaction to be reverted with custom error 'SomeCustomError', but it reverted with reason 'some reason'" + ); + expect(errorString).to.include( path.join("test", "reverted", "revertedWithCustomError.ts") ); diff --git a/packages/hardhat-chai-matchers/test/reverted/revertedWithPanic.ts b/packages/hardhat-chai-matchers/test/reverted/revertedWithPanic.ts index 82c3071dc7..0ca7e47a0d 100644 --- a/packages/hardhat-chai-matchers/test/reverted/revertedWithPanic.ts +++ b/packages/hardhat-chai-matchers/test/reverted/revertedWithPanic.ts @@ -1,11 +1,11 @@ import { AssertionError, expect } from "chai"; -import { BigNumber } from "ethers"; import { ProviderError } from "hardhat/internal/core/providers/errors"; import path from "path"; import util from "util"; import "../../src/internal/add-chai-matchers"; import { PANIC_CODES } from "../../src/panic"; +import { MatchersContract } from "../contracts"; import { runSuccessfulAsserts, runFailedAsserts, @@ -28,9 +28,12 @@ describe("INTEGRATION: Reverted with panic", function () { function runTests() { // deploy Matchers contract before each test - let matchers: any; + let matchers: MatchersContract; beforeEach("deploy matchers contract", async function () { - const Matchers = await this.hre.ethers.getContractFactory("Matchers"); + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); matchers = await Matchers.deploy(); }); @@ -269,15 +272,6 @@ describe("INTEGRATION: Reverted with panic", function () { successfulAssert: (x) => expect(x).not.to.be.revertedWithPanic("1"), }); }); - - it("ethers's BigNumber", async function () { - await runSuccessfulAsserts({ - matchers, - method: "succeeds", - successfulAssert: (x) => - expect(x).not.to.be.revertedWithPanic(BigNumber.from(1)), - }); - }); }); describe("invalid values", function () { @@ -296,6 +290,15 @@ describe("INTEGRATION: Reverted with panic", function () { ); }); + it("non-number as expectation, subject is a rejected promise", async function () { + const tx = matchers.revertsWithoutReason(); + + expect(() => expect(tx).to.be.revertedWithPanic("invalid")).to.throw( + TypeError, + "Expected the given panic code to be a number-like value, but got 'invalid'" + ); + }); + it("errors that are not related to a reverted transaction", async function () { // use an address that almost surely doesn't have balance const randomPrivateKey = @@ -304,12 +307,15 @@ describe("INTEGRATION: Reverted with panic", function () { randomPrivateKey, this.hre.ethers.provider ); + const matchersFromSenderWithoutFunds = matchers.connect( + signer + ) as MatchersContract; // this transaction will fail because of lack of funds, not because of a // revert await expect( expect( - matchers.connect(signer).revertsWithoutReason({ + matchersFromSenderWithoutFunds.revertsWithoutReason({ gasLimit: 1_000_000, }) ).to.not.be.revertedWithPanic() @@ -326,7 +332,11 @@ describe("INTEGRATION: Reverted with panic", function () { try { await expect(matchers.panicAssert()).to.not.be.revertedWithPanic(); } catch (e: any) { - expect(util.inspect(e)).to.include( + const errorString = util.inspect(e); + expect(errorString).to.include( + "Expected transaction NOT to be reverted with some panic code, but it reverted with panic code 0x01 (Assertion error)" + ); + expect(errorString).to.include( path.join("test", "reverted", "revertedWithPanic.ts") ); diff --git a/packages/hardhat-chai-matchers/test/reverted/revertedWithoutReason.ts b/packages/hardhat-chai-matchers/test/reverted/revertedWithoutReason.ts index 3fa8f7f425..8fcb3fd263 100644 --- a/packages/hardhat-chai-matchers/test/reverted/revertedWithoutReason.ts +++ b/packages/hardhat-chai-matchers/test/reverted/revertedWithoutReason.ts @@ -11,6 +11,7 @@ import { } from "../helpers"; import "../../src/internal/add-chai-matchers"; +import { MatchersContract } from "../contracts"; describe("INTEGRATION: Reverted without reason", function () { describe("with the in-process hardhat network", function () { @@ -27,9 +28,12 @@ describe("INTEGRATION: Reverted without reason", function () { function runTests() { // deploy Matchers contract before each test - let matchers: any; + let matchers: MatchersContract; beforeEach("deploy matchers contract", async function () { - const Matchers = await this.hre.ethers.getContractFactory("Matchers"); + const Matchers = await this.hre.ethers.getContractFactory< + [], + MatchersContract + >("Matchers"); matchers = await Matchers.deploy(); }); @@ -155,12 +159,15 @@ describe("INTEGRATION: Reverted without reason", function () { randomPrivateKey, this.hre.ethers.provider ); + const matchersFromSenderWithoutFunds = matchers.connect( + signer + ) as MatchersContract; // this transaction will fail because of lack of funds, not because of a // revert await expect( expect( - matchers.connect(signer).revertsWithoutReason({ + matchersFromSenderWithoutFunds.revertsWithoutReason({ gasLimit: 1_000_000, }) ).to.not.be.revertedWithoutReason() @@ -179,7 +186,11 @@ describe("INTEGRATION: Reverted without reason", function () { matchers.revertsWithoutReason() ).to.not.be.revertedWithoutReason(); } catch (e: any) { - expect(util.inspect(e)).to.include( + const errorString = util.inspect(e); + expect(errorString).to.include( + "Expected transaction NOT to be reverted without a reason, but it was" + ); + expect(errorString).to.include( path.join("test", "reverted", "revertedWithoutReason.ts") ); diff --git a/packages/hardhat-ethers/.eslintrc.js b/packages/hardhat-ethers/.eslintrc.js index 44ed8ed6d5..7f3a838a47 100644 --- a/packages/hardhat-ethers/.eslintrc.js +++ b/packages/hardhat-ethers/.eslintrc.js @@ -4,4 +4,7 @@ module.exports = { project: `${__dirname}/src/tsconfig.json`, sourceType: "module", }, + rules: { + "@typescript-eslint/no-non-null-assertion": "error" + } }; diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index 2e315938a1..eb6b0dbad2 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -1,6 +1,6 @@ { "name": "@nomiclabs/hardhat-ethers", - "version": "2.2.3", + "version": "3.0.0", "description": "Hardhat plugin for ethers", "homepage": "https://github.com/nomiclabs/hardhat/tree/main/packages/hardhat-ethers", "repository": "github:nomiclabs/hardhat", @@ -51,7 +51,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^5.0.0", + "ethers": "^6.1.0", "hardhat": "^2.0.0", "mocha": "^10.0.0", "prettier": "2.4.1", @@ -60,7 +60,7 @@ "typescript": "~4.7.4" }, "peerDependencies": { - "ethers": "^5.0.0", + "ethers": "^6.1.0", "hardhat": "^2.0.0" } } diff --git a/packages/hardhat-ethers/src/dist/src/signer-with-address.ts b/packages/hardhat-ethers/src/dist/src/signer-with-address.ts index 51cc2d2bfc..dbdd5440d3 100644 --- a/packages/hardhat-ethers/src/dist/src/signer-with-address.ts +++ b/packages/hardhat-ethers/src/dist/src/signer-with-address.ts @@ -1 +1 @@ -export { SignerWithAddress } from "../../signers"; +export { CustomEthersSigner as SignerWithAddress } from "../../signers"; diff --git a/packages/hardhat-ethers/src/internal/custom-ethers-provider.ts b/packages/hardhat-ethers/src/internal/custom-ethers-provider.ts new file mode 100644 index 0000000000..c7f97b5b83 --- /dev/null +++ b/packages/hardhat-ethers/src/internal/custom-ethers-provider.ts @@ -0,0 +1,683 @@ +import type { AddressLike } from "ethers/types/address"; +import type { + BlockTag, + TransactionRequest, + Filter, + FilterByBlockHash, + ProviderEvent, + PerformActionTransaction, + TransactionResponseParams, + BlockParams, + TransactionReceiptParams, + LogParams, + PerformActionFilter, +} from "ethers/types/providers"; +import type { Listener } from "ethers/types/utils"; + +import { + Block, + FeeData, + Log, + Network as EthersNetwork, + Transaction, + TransactionReceipt, + TransactionResponse, + ethers, + getBigInt, + isHexString, + resolveAddress, + toQuantity, +} from "ethers"; +import { EthereumProvider } from "hardhat/types"; +import { CustomEthersSigner } from "../signers"; +import { + copyRequest, + formatBlock, + formatLog, + formatTransactionReceipt, + formatTransactionResponse, + getRpcTransaction, +} from "./ethers-utils"; +import { + AccountIndexOutOfRange, + BroadcastedTxDifferentHash, + HardhatEthersError, + NonStringEventError, + NotImplementedError, +} from "./errors"; + +export class CustomEthersProvider implements ethers.Provider { + constructor( + private readonly _hardhatProvider: EthereumProvider, + private readonly _networkName: string + ) {} + + public get provider(): this { + return this; + } + + public destroy() {} + + public async send(method: string, params?: any[]): Promise { + return this._hardhatProvider.send(method, params); + } + + public async getSigner( + address?: number | string + ): Promise { + if (address === null || address === undefined) { + address = 0; + } + + const accountsPromise = this.send("eth_accounts", []); + + // Account index + if (typeof address === "number") { + const accounts: string[] = await accountsPromise; + if (address >= accounts.length) { + throw new AccountIndexOutOfRange(address, accounts.length); + } + return CustomEthersSigner.create(this, accounts[address]); + } + + if (typeof address === "string") { + return CustomEthersSigner.create(this, address); + } + + throw new HardhatEthersError(`Couldn't get account ${address as any}`); + } + + public async getBlockNumber(): Promise { + const blockNumber = await this._hardhatProvider.send("eth_blockNumber"); + + return Number(blockNumber); + } + + public async getNetwork(): Promise { + const chainId = await this._hardhatProvider.send("eth_chainId"); + return new EthersNetwork(this._networkName, Number(chainId)); + } + + public async getFeeData(): Promise { + let gasPrice: bigint | undefined; + let maxFeePerGas: bigint | undefined; + let maxPriorityFeePerGas: bigint | undefined; + + try { + gasPrice = BigInt(await this._hardhatProvider.send("eth_gasPrice")); + } catch {} + + const latestBlock = await this.getBlock("latest"); + const baseFeePerGas = latestBlock?.baseFeePerGas; + if (baseFeePerGas !== undefined && baseFeePerGas !== null) { + maxPriorityFeePerGas = 1_000_000_000n; + maxFeePerGas = 2n * baseFeePerGas + maxPriorityFeePerGas; + } + + return new FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas); + } + + public async getBalance( + address: AddressLike, + blockTag?: BlockTag | undefined + ): Promise { + const resolvedAddress = await this._getAddress(address); + const resolvedBlockTag = await this._getBlockTag(blockTag); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + const balance = await this._hardhatProvider.send("eth_getBalance", [ + resolvedAddress, + rpcBlockTag, + ]); + + return BigInt(balance); + } + + public async getTransactionCount( + address: AddressLike, + blockTag?: BlockTag | undefined + ): Promise { + const resolvedAddress = await this._getAddress(address); + const resolvedBlockTag = await this._getBlockTag(blockTag); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + const transactionCount = await this._hardhatProvider.send( + "eth_getTransactionCount", + [resolvedAddress, rpcBlockTag] + ); + + return Number(transactionCount); + } + + public async getCode( + address: AddressLike, + blockTag?: BlockTag | undefined + ): Promise { + const resolvedAddress = await this._getAddress(address); + const resolvedBlockTag = await this._getBlockTag(blockTag); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + return this._hardhatProvider.send("eth_getCode", [ + resolvedAddress, + rpcBlockTag, + ]); + } + + public async getStorage( + address: AddressLike, + position: ethers.BigNumberish, + blockTag?: BlockTag | undefined + ): Promise { + const resolvedAddress = await this._getAddress(address); + const resolvedPosition = getBigInt(position, "position"); + const resolvedBlockTag = await this._getBlockTag(blockTag); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + return this._hardhatProvider.send("eth_getStorageAt", [ + resolvedAddress, + `0x${resolvedPosition.toString(16)}`, + rpcBlockTag, + ]); + } + + public async estimateGas(tx: TransactionRequest): Promise { + const blockTag = + tx.blockTag === undefined ? "pending" : this._getBlockTag(tx.blockTag); + const [resolvedTx, resolvedBlockTag] = await Promise.all([ + this._getTransactionRequest(tx), + blockTag, + ]); + + const rpcTransaction = getRpcTransaction(resolvedTx); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + const gasEstimation = await this._hardhatProvider.send("eth_estimateGas", [ + rpcTransaction, + rpcBlockTag, + ]); + + return BigInt(gasEstimation); + } + + public async call(tx: TransactionRequest): Promise { + const [resolvedTx, resolvedBlockTag] = await Promise.all([ + this._getTransactionRequest(tx), + this._getBlockTag(tx.blockTag), + ]); + const rpcTransaction = getRpcTransaction(resolvedTx); + const rpcBlockTag = this._getRpcBlockTag(resolvedBlockTag); + + return this._hardhatProvider.send("eth_call", [ + rpcTransaction, + rpcBlockTag, + ]); + } + + public async broadcastTransaction( + signedTx: string + ): Promise { + const hashPromise = this._hardhatProvider.send("eth_sendRawTransaction", [ + signedTx, + ]); + + const [hash, blockNumber] = await Promise.all([ + hashPromise, + this.getBlockNumber(), + ]); + + const tx = Transaction.from(signedTx); + if (tx.hash === null) { + throw new HardhatEthersError( + "Assertion error: hash of signed tx shouldn't be null" + ); + } + + if (tx.hash !== hash) { + throw new BroadcastedTxDifferentHash(tx.hash, hash); + } + + return this._wrapTransactionResponse(tx as any).replaceableTransaction( + blockNumber + ); + } + + public async getBlock( + blockHashOrBlockTag: BlockTag, + prefetchTxs?: boolean | undefined + ): Promise { + const block = await this._getBlock( + blockHashOrBlockTag, + prefetchTxs ?? false + ); + + // eslint-disable-next-line eqeqeq + if (block == null) { + return null; + } + + return this._wrapBlock(block); + } + + public async getTransaction( + hash: string + ): Promise { + const transaction = await this._hardhatProvider.send( + "eth_getTransactionByHash", + [hash] + ); + + // eslint-disable-next-line eqeqeq + if (transaction == null) { + return null; + } + + return this._wrapTransactionResponse( + formatTransactionResponse(transaction) + ); + } + + public async getTransactionReceipt( + hash: string + ): Promise { + const receipt = await this._hardhatProvider.send( + "eth_getTransactionReceipt", + [hash] + ); + + // eslint-disable-next-line eqeqeq + if (receipt == null) { + return null; + } + + return this._wrapTransactionReceipt(receipt); + } + + public async getTransactionResult(_hash: string): Promise { + throw new NotImplementedError("CustomEthersProvider.getTransactionResult"); + } + + public async getLogs( + filter: Filter | FilterByBlockHash + ): Promise { + const resolvedFilter = await this._getFilter(filter); + + const logs = await this._hardhatProvider.send("eth_getLogs", [ + resolvedFilter, + ]); + + return logs.map((log: any) => this._wrapLog(formatLog(log))); + } + + public async resolveName(_ensName: string): Promise { + throw new NotImplementedError("CustomEthersProvider.resolveName"); + } + + public async lookupAddress(_address: string): Promise { + throw new NotImplementedError("CustomEthersProvider.lookupAddress"); + } + + public async waitForTransaction( + _hash: string, + _confirms?: number | undefined, + _timeout?: number | undefined + ): Promise { + throw new NotImplementedError("CustomEthersProvider.waitForTransaction"); + } + + public async waitForBlock( + _blockTag?: BlockTag | undefined + ): Promise { + throw new NotImplementedError("CustomEthersProvider.waitForBlock"); + } + + public async on(event: ProviderEvent, listener: Listener): Promise { + if (typeof event === "string") { + this._hardhatProvider.on(event, listener); + } else { + throw new NonStringEventError("on", event); + } + + return this; + } + + public async once(event: ProviderEvent, listener: Listener): Promise { + if (typeof event === "string") { + this._hardhatProvider.once(event, listener); + } else { + throw new NonStringEventError("once", event); + } + + return this; + } + + public async emit(event: ProviderEvent, ...args: any[]): Promise { + if (typeof event === "string") { + return this._hardhatProvider.emit(event, ...args); + } else { + throw new NonStringEventError("emit", event); + } + } + + public async listenerCount( + event?: ProviderEvent | undefined + ): Promise { + if (typeof event === "string") { + return this._hardhatProvider.listenerCount(event); + } else { + throw new NonStringEventError("listenerCount", event); + } + } + + public async listeners( + event?: ProviderEvent | undefined + ): Promise { + if (typeof event === "string") { + return this._hardhatProvider.listeners(event) as any; + } else { + throw new NonStringEventError("listeners", event); + } + } + + public async off( + event: ProviderEvent, + listener?: Listener | undefined + ): Promise { + if (typeof event === "string" && listener !== undefined) { + this._hardhatProvider.off(event, listener); + } else { + throw new NonStringEventError("off", event); + } + + return this; + } + + public async removeAllListeners( + event?: ProviderEvent | undefined + ): Promise { + if (event === undefined || typeof event === "string") { + this._hardhatProvider.removeAllListeners(event); + } else { + throw new NonStringEventError("removeAllListeners", event); + } + + return this; + } + + public async addListener( + event: ProviderEvent, + listener: Listener + ): Promise { + if (typeof event === "string") { + this._hardhatProvider.addListener(event, listener); + } else { + throw new NonStringEventError("addListener", event); + } + + return this; + } + + public async removeListener( + event: ProviderEvent, + listener: Listener + ): Promise { + if (typeof event === "string") { + this._hardhatProvider.removeListener(event, listener); + } else { + throw new NonStringEventError("removeListener", event); + } + + return this; + } + + public toJSON() { + return ""; + } + + private _getAddress(address: AddressLike): string | Promise { + return resolveAddress(address, this); + } + + private _getBlockTag(blockTag?: BlockTag): string | Promise { + // eslint-disable-next-line eqeqeq + if (blockTag == null) { + return "latest"; + } + + switch (blockTag) { + case "earliest": + return "0x0"; + case "latest": + case "pending": + case "safe": + case "finalized": + return blockTag; + } + + if (isHexString(blockTag)) { + if (isHexString(blockTag, 32)) { + return blockTag; + } + return toQuantity(blockTag); + } + + if (typeof blockTag === "number") { + if (blockTag >= 0) { + return toQuantity(blockTag); + } + return this.getBlockNumber().then((b) => toQuantity(b + blockTag)); + } + + throw new HardhatEthersError(`Invalid blockTag: ${blockTag}`); + } + + private _getTransactionRequest( + _request: TransactionRequest + ): PerformActionTransaction | Promise { + const request = copyRequest(_request) as PerformActionTransaction; + + const promises: Array> = []; + ["to", "from"].forEach((key) => { + if ( + (request as any)[key] === null || + (request as any)[key] === undefined + ) { + return; + } + + const addr = resolveAddress((request as any)[key]); + if (isPromise(addr)) { + promises.push( + (async function () { + (request as any)[key] = await addr; + })() + ); + } else { + (request as any)[key] = addr; + } + }); + + if (request.blockTag !== null && request.blockTag !== undefined) { + const blockTag = this._getBlockTag(request.blockTag); + if (isPromise(blockTag)) { + promises.push( + (async function () { + request.blockTag = await blockTag; + })() + ); + } else { + request.blockTag = blockTag; + } + } + + if (promises.length > 0) { + return (async function () { + await Promise.all(promises); + return request; + })(); + } + + return request; + } + + private _wrapTransactionResponse( + tx: TransactionResponseParams + ): TransactionResponse { + return new TransactionResponse(tx, this); + } + + private async _getBlock( + block: BlockTag | string, + includeTransactions: boolean + ): Promise { + if (isHexString(block, 32)) { + return this._hardhatProvider.send("eth_getBlockByHash", [ + block, + includeTransactions, + ]); + } + + let blockTag = this._getBlockTag(block); + if (typeof blockTag !== "string") { + blockTag = await blockTag; + } + + return this._hardhatProvider.send("eth_getBlockByNumber", [ + blockTag, + includeTransactions, + ]); + } + + private _wrapBlock(value: BlockParams): Block { + return new Block(formatBlock(value), this); + } + + private _wrapTransactionReceipt( + value: TransactionReceiptParams + ): TransactionReceipt { + return new TransactionReceipt(formatTransactionReceipt(value), this); + } + + private _getFilter( + filter: Filter | FilterByBlockHash + ): PerformActionFilter | Promise { + // Create a canonical representation of the topics + const topics = (filter.topics ?? []).map((topic) => { + // eslint-disable-next-line eqeqeq + if (topic == null) { + return null; + } + if (Array.isArray(topic)) { + return concisify(topic.map((t) => t.toLowerCase())); + } + return topic.toLowerCase(); + }); + + const blockHash = "blockHash" in filter ? filter.blockHash : undefined; + + const resolve = ( + _address: string[], + fromBlock?: string, + toBlock?: string + ) => { + let resolvedAddress: undefined | string | string[]; + switch (_address.length) { + case 0: + break; + case 1: + resolvedAddress = _address[0]; + break; + default: + _address.sort(); + resolvedAddress = _address; + } + + if (blockHash !== undefined) { + // eslint-disable-next-line eqeqeq + if (fromBlock != null || toBlock != null) { + throw new HardhatEthersError("invalid filter"); + } + } + + const resolvedFilter: any = {}; + if (resolvedAddress !== undefined) { + resolvedFilter.address = resolvedAddress; + } + if (topics.length > 0) { + resolvedFilter.topics = topics; + } + if (fromBlock !== undefined) { + resolvedFilter.fromBlock = fromBlock; + } + if (toBlock !== undefined) { + resolvedFilter.toBlock = toBlock; + } + if (blockHash !== undefined) { + resolvedFilter.blockHash = blockHash; + } + + return resolvedFilter; + }; + + // Addresses could be async (ENS names or Addressables) + const address: Array> = []; + if (filter.address !== undefined) { + if (Array.isArray(filter.address)) { + for (const addr of filter.address) { + address.push(this._getAddress(addr)); + } + } else { + address.push(this._getAddress(filter.address)); + } + } + + let resolvedFromBlock: undefined | string | Promise; + if ("fromBlock" in filter) { + resolvedFromBlock = this._getBlockTag(filter.fromBlock); + } + + let resolvedToBlock: undefined | string | Promise; + if ("toBlock" in filter) { + resolvedToBlock = this._getBlockTag(filter.toBlock); + } + + if ( + address.filter((a) => typeof a !== "string").length > 0 || + // eslint-disable-next-line eqeqeq + (resolvedFromBlock != null && typeof resolvedFromBlock !== "string") || + // eslint-disable-next-line eqeqeq + (resolvedToBlock != null && typeof resolvedToBlock !== "string") + ) { + return Promise.all([ + Promise.all(address), + resolvedFromBlock, + resolvedToBlock, + ]).then((result) => { + return resolve(result[0], result[1], result[2]); + }); + } + + return resolve(address as string[], resolvedFromBlock, resolvedToBlock); + } + + private _wrapLog(value: LogParams): Log { + return new Log(formatLog(value), this); + } + + private _getRpcBlockTag(blockTag: string): string | { blockHash: string } { + if (isHexString(blockTag, 32)) { + return { blockHash: blockTag }; + } + + return blockTag; + } +} + +function isPromise(value: any): value is Promise { + return Boolean(value) && typeof value.then === "function"; +} + +function concisify(items: string[]): string[] { + items = Array.from(new Set(items).values()); + items.sort(); + return items; +} diff --git a/packages/hardhat-ethers/src/internal/errors.ts b/packages/hardhat-ethers/src/internal/errors.ts new file mode 100644 index 0000000000..ce7f3a0233 --- /dev/null +++ b/packages/hardhat-ethers/src/internal/errors.ts @@ -0,0 +1,35 @@ +import { NomicLabsHardhatPluginError } from "hardhat/plugins"; + +export class HardhatEthersError extends NomicLabsHardhatPluginError { + constructor(message: string, parent?: Error) { + super("@nomiclabs/hardhat-ethers", message, parent); + } +} + +export class NotImplementedError extends HardhatEthersError { + constructor(method: string) { + super(`Method '${method}' is not implemented`); + } +} + +export class NonStringEventError extends HardhatEthersError { + constructor(method: string, event: any) { + super(`Method '${method}' only supports string events, got '${event}'`); + } +} + +export class AccountIndexOutOfRange extends HardhatEthersError { + constructor(accountIndex: number, accountsLength: number) { + super( + `Tried to get account with index ${accountIndex} but there are ${accountsLength} accounts` + ); + } +} + +export class BroadcastedTxDifferentHash extends HardhatEthersError { + constructor(txHash: string, broadcastedTxHash: string) { + super( + `Expected broadcasted transaction to have hash '${txHash}', but got '${broadcastedTxHash}'` + ); + } +} diff --git a/packages/hardhat-ethers/src/internal/ethers-provider-wrapper.ts b/packages/hardhat-ethers/src/internal/ethers-provider-wrapper.ts deleted file mode 100644 index b0aa8c9afd..0000000000 --- a/packages/hardhat-ethers/src/internal/ethers-provider-wrapper.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ethers } from "ethers"; -import { EthereumProvider } from "hardhat/types"; - -export class EthersProviderWrapper extends ethers.providers.JsonRpcProvider { - private readonly _hardhatProvider: EthereumProvider; - - constructor(hardhatProvider: EthereumProvider) { - super(); - this._hardhatProvider = hardhatProvider; - } - - public async send(method: string, params: any): Promise { - const result = await this._hardhatProvider.send(method, params); - - // We replicate ethers' behavior. - this.emit("debug", { - action: "send", - request: { - id: 42, - jsonrpc: "2.0", - method, - params, - }, - response: result, - provider: this, - }); - - return result; - } - - public toJSON() { - return ""; - } -} diff --git a/packages/hardhat-ethers/src/internal/ethers-utils.ts b/packages/hardhat-ethers/src/internal/ethers-utils.ts new file mode 100644 index 0000000000..a94e452c12 --- /dev/null +++ b/packages/hardhat-ethers/src/internal/ethers-utils.ts @@ -0,0 +1,459 @@ +// these helpers functions were copied verbatim from ethers + +import type { + TransactionRequest, + PreparedTransactionRequest, + BlockParams, + TransactionResponseParams, + TransactionReceiptParams, + LogParams, + JsonRpcTransactionRequest, +} from "ethers/types/providers"; + +import { + accessListify, + assert, + assertArgument, + getAddress, + getBigInt, + getCreateAddress, + getNumber, + hexlify, + isHexString, + Signature, + toQuantity, +} from "ethers"; +import { HardhatEthersError } from "./errors"; + +export type FormatFunc = (value: any) => any; + +export function copyRequest( + req: TransactionRequest +): PreparedTransactionRequest { + const result: any = {}; + + // These could be addresses, ENS names or Addressables + if (req.to !== null && req.to !== undefined) { + result.to = req.to; + } + if (req.from !== null && req.from !== undefined) { + result.from = req.from; + } + + if (req.data !== null && req.data !== undefined) { + result.data = hexlify(req.data); + } + + const bigIntKeys = + "chainId,gasLimit,gasPrice,maxFeePerGas,maxPriorityFeePerGas,value".split( + /,/ + ); + for (const key of bigIntKeys) { + if ( + !(key in req) || + (req as any)[key] === null || + (req as any)[key] === undefined + ) { + continue; + } + result[key] = getBigInt((req as any)[key], `request.${key}`); + } + + const numberKeys = "type,nonce".split(/,/); + for (const key of numberKeys) { + if ( + !(key in req) || + (req as any)[key] === null || + (req as any)[key] === undefined + ) { + continue; + } + result[key] = getNumber((req as any)[key], `request.${key}`); + } + + if (req.accessList !== null && req.accessList !== undefined) { + result.accessList = accessListify(req.accessList); + } + + if ("blockTag" in req) { + result.blockTag = req.blockTag; + } + + if ("enableCcipRead" in req) { + result.enableCcipReadEnabled = Boolean(req.enableCcipRead); + } + + if ("customData" in req) { + result.customData = req.customData; + } + + return result; +} + +export async function resolveProperties(value: { + [P in keyof T]: T[P] | Promise; +}): Promise { + const keys = Object.keys(value); + const results = await Promise.all( + keys.map((k) => Promise.resolve(value[k as keyof T])) + ); + return results.reduce((accum: any, v, index) => { + accum[keys[index]] = v; + return accum; + }, {} as { [P in keyof T]: T[P] }); +} + +export function formatBlock(value: any): BlockParams { + const result = _formatBlock(value); + result.transactions = value.transactions.map( + (tx: string | TransactionResponseParams) => { + if (typeof tx === "string") { + return tx; + } + return formatTransactionResponse(tx); + } + ); + return result; +} + +const _formatBlock = object({ + hash: allowNull(formatHash), + parentHash: formatHash, + number: getNumber, + + timestamp: getNumber, + nonce: allowNull(formatData), + difficulty: getBigInt, + + gasLimit: getBigInt, + gasUsed: getBigInt, + + miner: allowNull(getAddress), + extraData: formatData, + + baseFeePerGas: allowNull(getBigInt), +}); + +function object( + format: Record, + altNames?: Record +): FormatFunc { + return (value: any) => { + const result: any = {}; + // eslint-disable-next-line guard-for-in + for (const key in format) { + let srcKey = key; + if (altNames !== undefined && key in altNames && !(srcKey in value)) { + for (const altKey of altNames[key]) { + if (altKey in value) { + srcKey = altKey; + break; + } + } + } + + try { + const nv = format[key](value[srcKey]); + if (nv !== undefined) { + result[key] = nv; + } + } catch (error) { + const message = error instanceof Error ? error.message : "not-an-error"; + assert( + false, + `invalid value for value.${key} (${message})`, + "BAD_DATA", + { value } + ); + } + } + return result; + }; +} + +function allowNull(format: FormatFunc, nullValue?: any): FormatFunc { + return function (value: any) { + // eslint-disable-next-line eqeqeq + if (value === null || value === undefined) { + return nullValue; + } + return format(value); + }; +} + +function formatHash(value: any): string { + assertArgument(isHexString(value, 32), "invalid hash", "value", value); + return value; +} + +function formatData(value: string): string { + assertArgument(isHexString(value, true), "invalid data", "value", value); + return value; +} + +export function formatTransactionResponse( + value: any +): TransactionResponseParams { + // Some clients (TestRPC) do strange things like return 0x0 for the + // 0 address; correct this to be a real address + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (value.to && getBigInt(value.to) === 0n) { + value.to = "0x0000000000000000000000000000000000000000"; + } + + const result = object( + { + hash: formatHash, + + type: (v: any) => { + // eslint-disable-next-line eqeqeq + if (v === "0x" || v == null) { + return 0; + } + return getNumber(v); + }, + accessList: allowNull(accessListify, null), + + blockHash: allowNull(formatHash, null), + blockNumber: allowNull(getNumber, null), + transactionIndex: allowNull(getNumber, null), + + from: getAddress, + + // either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas) must be set + gasPrice: allowNull(getBigInt), + maxPriorityFeePerGas: allowNull(getBigInt), + maxFeePerGas: allowNull(getBigInt), + + gasLimit: getBigInt, + to: allowNull(getAddress, null), + value: getBigInt, + nonce: getNumber, + data: formatData, + + creates: allowNull(getAddress, null), + + chainId: allowNull(getBigInt, null), + }, + { + data: ["input"], + gasLimit: ["gas"], + } + )(value); + + // If to and creates are empty, populate the creates from the value + // eslint-disable-next-line eqeqeq + if (result.to == null && result.creates == null) { + result.creates = getCreateAddress(result); + } + + // @TODO: Check fee data + + // Add an access list to supported transaction types + // eslint-disable-next-line eqeqeq + if ((value.type === 1 || value.type === 2) && value.accessList == null) { + result.accessList = []; + } + + // Compute the signature + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (value.signature) { + result.signature = Signature.from(value.signature); + } else { + result.signature = Signature.from(value); + } + + // Some backends omit ChainId on legacy transactions, but we can compute it + // eslint-disable-next-line eqeqeq + if (result.chainId == null) { + const chainId = result.signature.legacyChainId; + // eslint-disable-next-line eqeqeq + if (chainId != null) { + result.chainId = chainId; + } + } + + // @TODO: check chainID + /* + if (value.chainId != null) { + let chainId = value.chainId; + + if (isHexString(chainId)) { + chainId = BigNumber.from(chainId).toNumber(); + } + + result.chainId = chainId; + + } else { + let chainId = value.networkId; + + // geth-etc returns chainId + if (chainId == null && result.v == null) { + chainId = value.chainId; + } + + if (isHexString(chainId)) { + chainId = BigNumber.from(chainId).toNumber(); + } + + if (typeof(chainId) !== "number" && result.v != null) { + chainId = (result.v - 35) / 2; + if (chainId < 0) { chainId = 0; } + chainId = parseInt(chainId); + } + + if (typeof(chainId) !== "number") { chainId = 0; } + + result.chainId = chainId; + } + */ + + // 0x0000... should actually be null + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (result.blockHash && getBigInt(result.blockHash) === 0n) { + result.blockHash = null; + } + + return result; +} + +function arrayOf(format: FormatFunc): FormatFunc { + return (array: any) => { + if (!Array.isArray(array)) { + throw new HardhatEthersError("not an array"); + } + return array.map((i) => format(i)); + }; +} + +const _formatReceiptLog = object( + { + transactionIndex: getNumber, + blockNumber: getNumber, + transactionHash: formatHash, + address: getAddress, + topics: arrayOf(formatHash), + data: formatData, + index: getNumber, + blockHash: formatHash, + }, + { + index: ["logIndex"], + } +); + +const _formatTransactionReceipt = object( + { + to: allowNull(getAddress, null), + from: allowNull(getAddress, null), + contractAddress: allowNull(getAddress, null), + // should be allowNull(hash), but broken-EIP-658 support is handled in receipt + index: getNumber, + root: allowNull(hexlify), + gasUsed: getBigInt, + logsBloom: allowNull(formatData), + blockHash: formatHash, + hash: formatHash, + logs: arrayOf(formatReceiptLog), + blockNumber: getNumber, + cumulativeGasUsed: getBigInt, + effectiveGasPrice: allowNull(getBigInt), + status: allowNull(getNumber), + type: allowNull(getNumber, 0), + }, + { + effectiveGasPrice: ["gasPrice"], + hash: ["transactionHash"], + index: ["transactionIndex"], + } +); + +export function formatTransactionReceipt(value: any): TransactionReceiptParams { + return _formatTransactionReceipt(value); +} + +export function formatReceiptLog(value: any): LogParams { + return _formatReceiptLog(value); +} + +function formatBoolean(value: any): boolean { + switch (value) { + case true: + case "true": + return true; + case false: + case "false": + return false; + } + assertArgument( + false, + `invalid boolean; ${JSON.stringify(value)}`, + "value", + value + ); +} + +const _formatLog = object( + { + address: getAddress, + blockHash: formatHash, + blockNumber: getNumber, + data: formatData, + index: getNumber, + removed: formatBoolean, + topics: arrayOf(formatHash), + transactionHash: formatHash, + transactionIndex: getNumber, + }, + { + index: ["logIndex"], + } +); + +export function formatLog(value: any): LogParams { + return _formatLog(value); +} + +export function getRpcTransaction( + tx: TransactionRequest +): JsonRpcTransactionRequest { + const result: JsonRpcTransactionRequest = {}; + + // JSON-RPC now requires numeric values to be "quantity" values + [ + "chainId", + "gasLimit", + "gasPrice", + "type", + "maxFeePerGas", + "maxPriorityFeePerGas", + "nonce", + "value", + ].forEach((key) => { + if ((tx as any)[key] === null || (tx as any)[key] === undefined) { + return; + } + let dstKey = key; + if (key === "gasLimit") { + dstKey = "gas"; + } + (result as any)[dstKey] = toQuantity( + getBigInt((tx as any)[key], `tx.${key}`) + ); + }); + + // Make sure addresses and data are lowercase + ["from", "to", "data"].forEach((key) => { + if ((tx as any)[key] === null || (tx as any)[key] === undefined) { + return; + } + (result as any)[key] = hexlify((tx as any)[key]); + }); + + // Normalize the access list object + if (tx.accessList !== null && tx.accessList !== undefined) { + result.accessList = accessListify(tx.accessList); + } + + return result; +} diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index 3d9e95c0f8..c622e333da 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -1,13 +1,9 @@ -import type { ethers } from "ethers"; -import type { SignerWithAddress } from "../signers"; +import type { ethers as EthersT, BaseContract } from "ethers"; +import type { CustomEthersSigner } from "../signers"; import type { FactoryOptions, Libraries } from "../types"; -import { NomicLabsHardhatPluginError } from "hardhat/plugins"; -import { - Artifact, - HardhatRuntimeEnvironment, - NetworkConfig, -} from "hardhat/types"; +import { Artifact, HardhatRuntimeEnvironment } from "hardhat/types"; +import { HardhatEthersError } from "./errors"; interface Link { sourceName: string; @@ -15,8 +11,6 @@ interface Link { address: string; } -const pluginName = "hardhat-ethers"; - function isArtifact(artifact: any): artifact is Artifact { const { contractName, @@ -41,8 +35,8 @@ function isArtifact(artifact: any): artifact is Artifact { export async function getSigners( hre: HardhatRuntimeEnvironment -): Promise { - const accounts = await hre.ethers.provider.listAccounts(); +): Promise { + const accounts: string[] = await hre.ethers.provider.send("eth_accounts", []); const signersWithAddress = await Promise.all( accounts.map((account) => getSigner(hre, account)) @@ -54,14 +48,15 @@ export async function getSigners( export async function getSigner( hre: HardhatRuntimeEnvironment, address: string -): Promise { - const { SignerWithAddress: SignerWithAddressImpl } = await import( +): Promise { + const { CustomEthersSigner: SignerWithAddressImpl } = await import( "../signers" ); - const signer = hre.ethers.provider.getSigner(address); - - const signerWithAddress = await SignerWithAddressImpl.create(signer); + const signerWithAddress = await SignerWithAddressImpl.create( + hre.ethers.provider, + address + ); return signerWithAddress; } @@ -69,68 +64,76 @@ export async function getSigner( export async function getImpersonatedSigner( hre: HardhatRuntimeEnvironment, address: string -): Promise { +): Promise { await hre.ethers.provider.send("hardhat_impersonateAccount", [address]); return getSigner(hre, address); } -export function getContractFactory( +export function getContractFactory( hre: HardhatRuntimeEnvironment, name: string, - signerOrOptions?: ethers.Signer | FactoryOptions -): Promise; + signerOrOptions?: EthersT.Signer | FactoryOptions +): Promise>; -export function getContractFactory( +export function getContractFactory( hre: HardhatRuntimeEnvironment, abi: any[], - bytecode: ethers.utils.BytesLike, - signer?: ethers.Signer -): Promise; - -export async function getContractFactory( + bytecode: EthersT.BytesLike, + signer?: EthersT.Signer +): Promise>; + +export async function getContractFactory< + A extends any[] = any[], + I = BaseContract +>( hre: HardhatRuntimeEnvironment, nameOrAbi: string | any[], bytecodeOrFactoryOptions?: - | (ethers.Signer | FactoryOptions) - | ethers.utils.BytesLike, - signer?: ethers.Signer -) { + | (EthersT.Signer | FactoryOptions) + | EthersT.BytesLike, + signer?: EthersT.Signer +): Promise> { if (typeof nameOrAbi === "string") { const artifact = await hre.artifacts.readArtifact(nameOrAbi); - return getContractFactoryFromArtifact( + return getContractFactoryFromArtifact( hre, artifact, - bytecodeOrFactoryOptions as ethers.Signer | FactoryOptions | undefined + bytecodeOrFactoryOptions as EthersT.Signer | FactoryOptions | undefined ); } return getContractFactoryByAbiAndBytecode( hre, nameOrAbi, - bytecodeOrFactoryOptions as ethers.utils.BytesLike, + bytecodeOrFactoryOptions as EthersT.BytesLike, signer ); } function isFactoryOptions( - signerOrOptions?: ethers.Signer | FactoryOptions + signerOrOptions?: EthersT.Signer | FactoryOptions ): signerOrOptions is FactoryOptions { - const { Signer } = require("ethers") as typeof ethers; - return signerOrOptions !== undefined && !Signer.isSigner(signerOrOptions); + if (signerOrOptions === undefined || "provider" in signerOrOptions) { + return false; + } + + return true; } -export async function getContractFactoryFromArtifact( +export async function getContractFactoryFromArtifact< + A extends any[] = any[], + I = BaseContract +>( hre: HardhatRuntimeEnvironment, artifact: Artifact, - signerOrOptions?: ethers.Signer | FactoryOptions -) { + signerOrOptions?: EthersT.Signer | FactoryOptions +): Promise> { let libraries: Libraries = {}; - let signer: ethers.Signer | undefined; + let signer: EthersT.Signer | undefined; if (!isArtifact(artifact)) { - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.` ); } @@ -143,8 +146,7 @@ export async function getContractFactoryFromArtifact( } if (artifact.bytecode === "0x") { - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `You are trying to create a contract factory for the contract ${artifact.contractName}, which is abstract and can't be deployed. If you want to call a contract using ${artifact.contractName} as its interface use the "getContractAt" function instead.` ); @@ -164,7 +166,7 @@ async function collectLibrariesAndLink( artifact: Artifact, libraries: Libraries ) { - const { utils } = require("ethers") as typeof ethers; + const ethers = require("ethers") as typeof EthersT; const neededLibraries: Array<{ sourceName: string; @@ -182,10 +184,20 @@ async function collectLibrariesAndLink( for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries( libraries )) { - if (!utils.isAddress(linkedLibraryAddress)) { - throw new NomicLabsHardhatPluginError( - pluginName, - `You tried to link the contract ${artifact.contractName} with the library ${linkedLibraryName}, but provided this invalid address: ${linkedLibraryAddress}` + let resolvedAddress: string; + if (ethers.isAddressable(linkedLibraryAddress)) { + resolvedAddress = await linkedLibraryAddress.getAddress(); + } else { + resolvedAddress = linkedLibraryAddress; + } + + if (!ethers.isAddress(resolvedAddress)) { + throw new HardhatEthersError( + `You tried to link the contract ${ + artifact.contractName + } with the library ${linkedLibraryName}, but provided this invalid address: ${ + resolvedAddress as any + }` ); } @@ -208,8 +220,7 @@ ${libraryFQNames}`; } else { detailedMessage = "This contract doesn't need linking any libraries."; } - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `You tried to link the contract ${artifact.contractName} with ${linkedLibraryName}, which is not one of its libraries. ${detailedMessage}` ); @@ -220,8 +231,7 @@ ${detailedMessage}` .map(({ sourceName, libName }) => `${sourceName}:${libName}`) .map((x) => `* ${x}`) .join("\n"); - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `The library name ${linkedLibraryName} is ambiguous for the contract ${artifact.contractName}. It may resolve to one of the following libraries: ${matchingNeededLibrariesFQNs} @@ -238,8 +248,7 @@ To fix this, choose one of these fully qualified library names and replace where // for it to be given twice in the libraries user input: // once as a library name and another as a fully qualified library name. if (linksToApply.has(neededLibraryFQN)) { - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `The library names ${neededLibrary.libName} and ${neededLibraryFQN} refer to the same library and were given as two separate library links. Remove one of them and review your library links before proceeding.` ); @@ -248,7 +257,7 @@ Remove one of them and review your library links before proceeding.` linksToApply.set(neededLibraryFQN, { sourceName: neededLibrary.sourceName, libraryName: neededLibrary.libName, - address: linkedLibraryAddress, + address: resolvedAddress, }); } @@ -259,8 +268,7 @@ Remove one of them and review your library links before proceeding.` .map((x) => `* ${x}`) .join("\n"); - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `The contract ${artifact.contractName} is missing links for the following libraries: ${missingLibraries} @@ -272,32 +280,30 @@ Learn more about linking contracts at https://hardhat.org/hardhat-runner/plugins return linkBytecode(artifact, [...linksToApply.values()]); } -async function getContractFactoryByAbiAndBytecode( +async function getContractFactoryByAbiAndBytecode< + A extends any[] = any[], + I = BaseContract +>( hre: HardhatRuntimeEnvironment, abi: any[], - bytecode: ethers.utils.BytesLike, - signer?: ethers.Signer -) { - const { ContractFactory } = require("ethers") as typeof ethers; + bytecode: EthersT.BytesLike, + signer?: EthersT.Signer +): Promise> { + const { ContractFactory } = require("ethers") as typeof EthersT; if (signer === undefined) { const signers = await hre.ethers.getSigners(); signer = signers[0]; } - const abiWithAddedGas = addGasToAbiMethodsIfNecessary( - hre.network.config, - abi - ); - - return new ContractFactory(abiWithAddedGas, bytecode, signer); + return new ContractFactory(abi, bytecode, signer); } export async function getContractAt( hre: HardhatRuntimeEnvironment, nameOrAbi: string | any[], - address: string, - signer?: ethers.Signer + address: string | EthersT.Addressable, + signer?: EthersT.Signer ) { if (typeof nameOrAbi === "string") { const artifact = await hre.artifacts.readArtifact(nameOrAbi); @@ -305,7 +311,7 @@ export async function getContractAt( return getContractAtFromArtifact(hre, artifact, address, signer); } - const { Contract } = require("ethers") as typeof ethers; + const ethers = require("ethers") as typeof EthersT; if (signer === undefined) { const signers = await hre.ethers.getSigners(); @@ -314,36 +320,38 @@ export async function getContractAt( // If there's no signer, we want to put the provider for the selected network here. // This allows read only operations on the contract interface. - const signerOrProvider: ethers.Signer | ethers.providers.Provider = + const signerOrProvider: EthersT.Signer | EthersT.Provider = signer !== undefined ? signer : hre.ethers.provider; - const abiWithAddedGas = addGasToAbiMethodsIfNecessary( - hre.network.config, - nameOrAbi - ); + let resolvedAddress; + if (ethers.isAddressable(address)) { + resolvedAddress = await address.getAddress(); + } else { + resolvedAddress = address; + } - return new Contract(address, abiWithAddedGas, signerOrProvider); + return new ethers.Contract(resolvedAddress, nameOrAbi, signerOrProvider); } export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, args?: any[], - signerOrOptions?: ethers.Signer | FactoryOptions -): Promise; + signerOrOptions?: EthersT.Signer | FactoryOptions +): Promise; export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, - signerOrOptions?: ethers.Signer | FactoryOptions -): Promise; + signerOrOptions?: EthersT.Signer | FactoryOptions +): Promise; export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, - argsOrSignerOrOptions?: any[] | ethers.Signer | FactoryOptions, - signerOrOptions?: ethers.Signer | FactoryOptions -): Promise { + argsOrSignerOrOptions?: any[] | EthersT.Signer | FactoryOptions, + signerOrOptions?: EthersT.Signer | FactoryOptions +): Promise { let args = []; if (Array.isArray(argsOrSignerOrOptions)) { args = argsOrSignerOrOptions; @@ -351,74 +359,41 @@ export async function deployContract( signerOrOptions = argsOrSignerOrOptions; } const factory = await getContractFactory(hre, name, signerOrOptions); - return factory.deploy(...args); + return factory.deploy(...args) as any; } export async function getContractAtFromArtifact( hre: HardhatRuntimeEnvironment, artifact: Artifact, - address: string, - signer?: ethers.Signer + address: string | EthersT.Addressable, + signer?: EthersT.Signer ) { + const ethers = require("ethers") as typeof EthersT; if (!isArtifact(artifact)) { - throw new NomicLabsHardhatPluginError( - pluginName, + throw new HardhatEthersError( `You are trying to create a contract by artifact, but you have not passed a valid artifact parameter.` ); } - const factory = await getContractFactoryByAbiAndBytecode( - hre, - artifact.abi, - "0x", - signer - ); - - let contract = factory.attach(address); - // If there's no signer, we connect the contract instance to the provider for the selected network. - if (contract.provider === null) { - contract = contract.connect(hre.ethers.provider); + if (signer === undefined) { + const signers = await hre.ethers.getSigners(); + signer = signers[0]; } - return contract; -} - -// This helper adds a `gas` field to the ABI function elements if the network -// is set up to use a fixed amount of gas. -// This is done so that ethers doesn't automatically estimate gas limits on -// every call. -function addGasToAbiMethodsIfNecessary( - networkConfig: NetworkConfig, - abi: any[] -): any[] { - const { BigNumber } = require("ethers") as typeof ethers; - - if (networkConfig.gas === "auto" || networkConfig.gas === undefined) { - return abi; + let resolvedAddress; + if (ethers.isAddressable(address)) { + resolvedAddress = await address.getAddress(); + } else { + resolvedAddress = address; } - // ethers adds 21000 to whatever the abi `gas` field has. This may lead to - // OOG errors, as people may set the default gas to the same value as the - // block gas limit, especially on Hardhat Network. - // To avoid this, we substract 21000. - // HOTFIX: We substract 1M for now. See: https://github.com/ethers-io/ethers.js/issues/1058#issuecomment-703175279 - const gasLimit = BigNumber.from(networkConfig.gas).sub(1000000).toHexString(); - - const modifiedAbi: any[] = []; + let contract = new ethers.Contract(resolvedAddress, artifact.abi, signer); - for (const abiElement of abi) { - if (abiElement.type !== "function") { - modifiedAbi.push(abiElement); - continue; - } - - modifiedAbi.push({ - ...abiElement, - gas: gasLimit, - }); + if (contract.runner === null) { + contract = contract.connect(hre.ethers.provider) as EthersT.Contract; } - return modifiedAbi; + return contract; } function linkBytecode(artifact: Artifact, libraries: Link[]): string { diff --git a/packages/hardhat-ethers/src/internal/index.ts b/packages/hardhat-ethers/src/internal/index.ts index a8f46f51e0..12f4a0b7a3 100644 --- a/packages/hardhat-ethers/src/internal/index.ts +++ b/packages/hardhat-ethers/src/internal/index.ts @@ -1,9 +1,9 @@ import type EthersT from "ethers"; -import type * as ProviderProxyT from "./provider-proxy"; import { extendEnvironment } from "hardhat/config"; import { lazyObject } from "hardhat/plugins"; +import { CustomEthersProvider } from "./custom-ethers-provider"; import { getContractAt, getContractAtFromArtifact, @@ -16,29 +16,19 @@ import { } from "./helpers"; import "./type-extensions"; -const registerCustomInspection = (BigNumber: any) => { - const inspectCustomSymbol = Symbol.for("nodejs.util.inspect.custom"); - - BigNumber.prototype[inspectCustomSymbol] = function () { - return `BigNumber { value: "${this.toString()}" }`; - }; -}; - extendEnvironment((hre) => { hre.ethers = lazyObject(() => { - const { createProviderProxy } = - require("./provider-proxy") as typeof ProviderProxyT; - const { ethers } = require("ethers") as typeof EthersT; - registerCustomInspection(ethers.BigNumber); - - const providerProxy = createProviderProxy(hre.network.provider); + const provider = new CustomEthersProvider( + hre.network.provider, + hre.network.name + ); return { ...ethers, - provider: providerProxy, + provider, getSigner: (address: string) => getSigner(hre, address), getSigners: () => getSigners(hre), @@ -47,12 +37,11 @@ extendEnvironment((hre) => { // We cast to any here as we hit a limitation of Function#bind and // overloads. See: https://github.com/microsoft/TypeScript/issues/28582 getContractFactory: getContractFactory.bind(null, hre) as any, - getContractFactoryFromArtifact: getContractFactoryFromArtifact.bind( - null, - hre - ), - getContractAt: getContractAt.bind(null, hre), - getContractAtFromArtifact: getContractAtFromArtifact.bind(null, hre), + getContractFactoryFromArtifact: (...args) => + getContractFactoryFromArtifact(hre, ...args), + getContractAt: (...args) => getContractAt(hre, ...args), + getContractAtFromArtifact: (...args) => + getContractAtFromArtifact(hre, ...args), deployContract: deployContract.bind(null, hre) as any, }; }); diff --git a/packages/hardhat-ethers/src/internal/provider-proxy.ts b/packages/hardhat-ethers/src/internal/provider-proxy.ts deleted file mode 100644 index 4a722de9da..0000000000 --- a/packages/hardhat-ethers/src/internal/provider-proxy.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - HARDHAT_NETWORK_RESET_EVENT, - HARDHAT_NETWORK_REVERT_SNAPSHOT_EVENT, -} from "hardhat/internal/constants"; -import { EthereumProvider } from "hardhat/types"; - -import { EthersProviderWrapper } from "./ethers-provider-wrapper"; -import { createUpdatableTargetProxy } from "./updatable-target-proxy"; - -/** - * This method returns a proxy that uses an underlying provider for everything. - * - * This underlying provider is replaced by a new one after a successful hardhat_reset, - * because ethers providers can have internal state that returns wrong results after - * the network is reset. - */ -export function createProviderProxy( - hardhatProvider: EthereumProvider -): EthersProviderWrapper { - const initialProvider = new EthersProviderWrapper(hardhatProvider); - - const { proxy: providerProxy, setTarget } = - createUpdatableTargetProxy(initialProvider); - - hardhatProvider.on(HARDHAT_NETWORK_RESET_EVENT, () => { - setTarget(new EthersProviderWrapper(hardhatProvider)); - }); - hardhatProvider.on(HARDHAT_NETWORK_REVERT_SNAPSHOT_EVENT, () => { - setTarget(new EthersProviderWrapper(hardhatProvider)); - }); - - return providerProxy; -} diff --git a/packages/hardhat-ethers/src/internal/updatable-target-proxy.ts b/packages/hardhat-ethers/src/internal/updatable-target-proxy.ts deleted file mode 100644 index 8ad55cd3ac..0000000000 --- a/packages/hardhat-ethers/src/internal/updatable-target-proxy.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Returns a read-only proxy that just forwards everything to a target, - * and a function that can be used to change that underlying target - */ -export function createUpdatableTargetProxy( - initialTarget: T -): { - proxy: T; - setTarget: (target: T) => void; -} { - const targetObject = { - target: initialTarget, - }; - - let isExtensible = Object.isExtensible(initialTarget); - - const handler: Required> = { - // these two functions are implemented because of the Required type - apply(_, _thisArg, _argArray) { - throw new Error( - "cannot be implemented because the target is not a function" - ); - }, - - construct(_, _argArray, _newTarget) { - throw new Error( - "cannot be implemented because the target is not a function" - ); - }, - - defineProperty(_, property, _descriptor) { - throw new Error( - `cannot define property ${String(property)} in read-only proxy` - ); - }, - - deleteProperty(_, property) { - throw new Error( - `cannot delete property ${String(property)} in read-only proxy` - ); - }, - - get(_, property, receiver) { - const result = Reflect.get(targetObject.target, property, receiver); - - if (result instanceof Function) { - return result.bind(targetObject.target); - } - - return result; - }, - - getOwnPropertyDescriptor(_, property) { - const descriptor = Reflect.getOwnPropertyDescriptor( - targetObject.target, - property - ); - - if (descriptor !== undefined) { - Object.defineProperty(targetObject.target, property, descriptor); - } - - return descriptor; - }, - - getPrototypeOf(_) { - return Reflect.getPrototypeOf(targetObject.target); - }, - - has(_, property) { - return Reflect.has(targetObject.target, property); - }, - - isExtensible(_) { - // we need to return the extensibility value of the original target - return isExtensible; - }, - - ownKeys(_) { - return Reflect.ownKeys(targetObject.target); - }, - - preventExtensions(_) { - isExtensible = false; - return Reflect.preventExtensions(targetObject.target); - }, - - set(_, property, _value, _receiver) { - throw new Error( - `cannot set property ${String(property)} in read-only proxy` - ); - }, - - setPrototypeOf(_, _prototype) { - throw new Error("cannot change the prototype in read-only proxy"); - }, - }; - - const proxy: T = new Proxy(initialTarget, handler); - - const setTarget = (newTarget: T) => { - targetObject.target = newTarget; - }; - - return { proxy, setTarget }; -} diff --git a/packages/hardhat-ethers/src/signers.ts b/packages/hardhat-ethers/src/signers.ts index 48294f1cb9..ebb068e8d4 100644 --- a/packages/hardhat-ethers/src/signers.ts +++ b/packages/hardhat-ethers/src/signers.ts @@ -1,49 +1,298 @@ -import { ethers } from "ethers"; +import type { BlockTag, TransactionRequest } from "ethers/types/providers"; +import { + assertArgument, + ethers, + getAddress, + hexlify, + resolveAddress, + toUtf8Bytes, + TransactionLike, + TypedDataEncoder, +} from "ethers"; +import { CustomEthersProvider } from "./internal/custom-ethers-provider"; +import { + copyRequest, + getRpcTransaction, + resolveProperties, +} from "./internal/ethers-utils"; +import { HardhatEthersError, NotImplementedError } from "./internal/errors"; -export class SignerWithAddress extends ethers.Signer { - public static async create(signer: ethers.providers.JsonRpcSigner) { - return new SignerWithAddress(await signer.getAddress(), signer); +export class CustomEthersSigner implements ethers.Signer { + public readonly address: string; + public readonly provider: ethers.JsonRpcProvider | CustomEthersProvider; + + public static async create(provider: CustomEthersProvider, address: string) { + const hre = await import("hardhat"); + let gasLimit: number | undefined; + if ( + hre.network.name === "hardhat" && + hre.network.config.gas !== "auto" && + hre.network.config.gas !== undefined + ) { + gasLimit = hre.network.config.gas; + } + + return new CustomEthersSigner(address, provider, gasLimit); } private constructor( - public readonly address: string, - private readonly _signer: ethers.providers.JsonRpcSigner + address: string, + _provider: ethers.JsonRpcProvider | CustomEthersProvider, + private readonly _gasLimit?: number ) { - super(); - (this as any).provider = _signer.provider; + this.address = getAddress(address); + this.provider = _provider; } - public async getAddress(): Promise { - return this.address; + public connect( + provider: ethers.JsonRpcProvider | CustomEthersProvider + ): ethers.Signer { + return new CustomEthersSigner(this.address, provider); } - public signMessage(message: string | ethers.utils.Bytes): Promise { - return this._signer.signMessage(message); + public getNonce(blockTag?: BlockTag | undefined): Promise { + return this.provider.getTransactionCount(this.address, blockTag); } - public signTransaction( - transaction: ethers.utils.Deferrable - ): Promise { - return this._signer.signTransaction(transaction); + public populateCall( + tx: TransactionRequest + ): Promise> { + return populate(this, tx); + } + + public populateTransaction( + tx: TransactionRequest + ): Promise> { + return this.populateCall(tx); + } + + public async estimateGas(tx: TransactionRequest): Promise { + return this.provider.estimateGas(await this.populateCall(tx)); + } + + public async call(tx: TransactionRequest): Promise { + return this.provider.call(await this.populateCall(tx)); + } + + public resolveName(name: string): Promise { + return this.provider.resolveName(name); + } + + public async signTransaction(_tx: TransactionRequest): Promise { + // TODO if we split the signer for the in-process and json-rpc networks, + // we can enable this method when using the in-process network or when the + // json-rpc network has a private key + throw new NotImplementedError("CustomEthersSigner.signTransaction"); } - public sendTransaction( - transaction: ethers.utils.Deferrable - ): Promise { - return this._signer.sendTransaction(transaction); + public async sendTransaction( + tx: TransactionRequest + ): Promise { + // This cannot be mined any earlier than any recent block + const blockNumber = await this.provider.getBlockNumber(); + + // Send the transaction + const hash = await this._sendUncheckedTransaction(tx); + + // Unfortunately, JSON-RPC only provides and opaque transaction hash + // for a response, and we need the actual transaction, so we poll + // for it; it should show up very quickly + + return new Promise((resolve) => { + const timeouts = [1000, 100]; + const checkTx = async () => { + // Try getting the transaction + const txPolled = await this.provider.getTransaction(hash); + if (txPolled !== null) { + resolve(txPolled.replaceableTransaction(blockNumber)); + return; + } + + // Wait another 4 seconds + setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + checkTx(); + }, timeouts.pop() ?? 4000); + }; + // eslint-disable-next-line @typescript-eslint/no-floating-promises + checkTx(); + }); } - public connect(provider: ethers.providers.Provider): SignerWithAddress { - return new SignerWithAddress(this.address, this._signer.connect(provider)); + public signMessage(message: string | Uint8Array): Promise { + const resolvedMessage = + typeof message === "string" ? toUtf8Bytes(message) : message; + return this.provider.send("personal_sign", [ + hexlify(resolvedMessage), + this.address.toLowerCase(), + ]); } - public _signTypedData( - ...params: Parameters + public async signTypedData( + domain: ethers.TypedDataDomain, + types: Record, + value: Record ): Promise { - return this._signer._signTypedData(...params); + const copiedValue = deepCopy(value); + + // Populate any ENS names (in-place) + const populated = await TypedDataEncoder.resolveNames( + domain, + types, + copiedValue, + async (v: string) => { + return v; + } + ); + + return this.provider.send("eth_signTypedData_v4", [ + this.address.toLowerCase(), + JSON.stringify( + TypedDataEncoder.getPayload(populated.domain, types, populated.value), + (_k, v) => { + if (typeof v === "bigint") { + return v.toString(); + } + + return v; + } + ), + ]); + } + + public async getAddress(): Promise { + return this.address; } public toJSON() { return ``; } + + private async _sendUncheckedTransaction( + tx: TransactionRequest + ): Promise { + const resolvedTx = deepCopy(tx); + + const promises: Array> = []; + + // Make sure the from matches the sender + if (resolvedTx.from !== null && resolvedTx.from !== undefined) { + const _from = resolvedTx.from; + promises.push( + (async () => { + const from = await resolveAddress(_from, this.provider); + assertArgument( + from !== null && + from !== undefined && + from.toLowerCase() === this.address.toLowerCase(), + "from address mismatch", + "transaction", + tx + ); + resolvedTx.from = from; + })() + ); + } else { + resolvedTx.from = this.address; + } + + if (resolvedTx.gasLimit === null || resolvedTx.gasLimit === undefined) { + if (this._gasLimit !== undefined) { + resolvedTx.gasLimit = this._gasLimit; + } else { + promises.push( + (async () => { + resolvedTx.gasLimit = await this.provider.estimateGas({ + ...resolvedTx, + from: this.address, + }); + })() + ); + } + } + + // The address may be an ENS name or Addressable + if (resolvedTx.to !== null && resolvedTx.to !== undefined) { + const _to = resolvedTx.to; + promises.push( + (async () => { + resolvedTx.to = await resolveAddress(_to, this.provider); + })() + ); + } + + // Wait until all of our properties are filled in + if (promises.length > 0) { + await Promise.all(promises); + } + + const hexTx = getRpcTransaction(resolvedTx); + + return this.provider.send("eth_sendTransaction", [hexTx]); + } +} + +// exported as an alias to make migration easier +export { CustomEthersSigner as SignerWithAddress }; + +async function populate( + signer: ethers.Signer, + tx: TransactionRequest +): Promise> { + const pop: any = copyRequest(tx); + + if (pop.to !== null && pop.to !== undefined) { + pop.to = resolveAddress(pop.to, signer); + } + + if (pop.from !== null && pop.from !== undefined) { + const from = pop.from; + pop.from = Promise.all([ + signer.getAddress(), + resolveAddress(from, signer), + ]).then(([address, resolvedFrom]) => { + assertArgument( + address.toLowerCase() === resolvedFrom.toLowerCase(), + "transaction from mismatch", + "tx.from", + resolvedFrom + ); + return address; + }); + } else { + pop.from = signer.getAddress(); + } + + return resolveProperties(pop); +} + +const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g); +function deepCopy(value: T): T { + if ( + value === null || + value === undefined || + Primitive.indexOf(typeof value) >= 0 + ) { + return value; + } + + // Keep any Addressable + if (typeof (value as any).getAddress === "function") { + return value; + } + + if (Array.isArray(value)) { + return (value as any).map(deepCopy); + } + + if (typeof value === "object") { + return Object.keys(value).reduce((accum, key) => { + accum[key] = (value as any)[key]; + return accum; + }, {} as any); + } + + throw new HardhatEthersError( + `Assertion error: ${value as any} (${typeof value})` + ); } diff --git a/packages/hardhat-ethers/src/types/index.ts b/packages/hardhat-ethers/src/types/index.ts index b39b673ce3..54100a372a 100644 --- a/packages/hardhat-ethers/src/types/index.ts +++ b/packages/hardhat-ethers/src/types/index.ts @@ -1,10 +1,10 @@ import type * as ethers from "ethers"; -import type { SignerWithAddress } from "../signers"; - -import { Artifact } from "hardhat/types"; +import type { Artifact } from "hardhat/types"; +import type { CustomEthersProvider } from "../internal/custom-ethers-provider"; +import type { CustomEthersSigner } from "../signers"; export interface Libraries { - [libraryName: string]: string; + [libraryName: string]: string | ethers.Addressable; } export interface FactoryOptions { @@ -12,15 +12,21 @@ export interface FactoryOptions { libraries?: Libraries; } -export declare function getContractFactory( +export declare function getContractFactory< + A extends any[] = any[], + I = ethers.BaseContract +>( name: string, signerOrOptions?: ethers.Signer | FactoryOptions -): Promise; -export declare function getContractFactory( +): Promise>; +export declare function getContractFactory< + A extends any[] = any[], + I = ethers.BaseContract +>( abi: any[], - bytecode: ethers.utils.BytesLike, + bytecode: ethers.BytesLike, signer?: ethers.Signer -): Promise; +): Promise>; export declare function deployContract( name: string, @@ -33,17 +39,22 @@ export declare function deployContract( signerOrOptions?: ethers.Signer | FactoryOptions ): Promise; +export declare function getContractFactoryFromArtifact< + A extends any[] = any[], + I = ethers.BaseContract +>( + artifact: Artifact, + signerOrOptions?: ethers.Signer | FactoryOptions +): Promise>; + export interface HardhatEthersHelpers { - provider: ethers.providers.JsonRpcProvider; + provider: CustomEthersProvider; getContractFactory: typeof getContractFactory; - getContractFactoryFromArtifact: ( - artifact: Artifact, - signerOrOptions?: ethers.Signer | FactoryOptions - ) => Promise; + getContractFactoryFromArtifact: typeof getContractFactoryFromArtifact; getContractAt: ( nameOrAbi: string | any[], - address: string, + address: string | ethers.Addressable, signer?: ethers.Signer ) => Promise; getContractAtFromArtifact: ( @@ -51,8 +62,8 @@ export interface HardhatEthersHelpers { address: string, signer?: ethers.Signer ) => Promise; - getSigner: (address: string) => Promise; - getSigners: () => Promise; - getImpersonatedSigner: (address: string) => Promise; + getSigner: (address: string) => Promise; + getSigners: () => Promise; + getImpersonatedSigner: (address: string) => Promise; deployContract: typeof deployContract; } diff --git a/packages/hardhat-ethers/test/custom-ethers-provider.ts b/packages/hardhat-ethers/test/custom-ethers-provider.ts new file mode 100644 index 0000000000..b315bd70ac --- /dev/null +++ b/packages/hardhat-ethers/test/custom-ethers-provider.ts @@ -0,0 +1,1043 @@ +import { assert, use } from "chai"; +import chaiAsPromised from "chai-as-promised"; + +import { ExampleContract, EXAMPLE_CONTRACT } from "./example-contracts"; +import { + assertIsNotNull, + assertWithin, + usePersistentEnvironment, +} from "./helpers"; + +use(chaiAsPromised); + +describe("custom provider", function () { + usePersistentEnvironment("minimal-project"); + + it("can access itself through .provider", async function () { + assert.strictEqual( + this.env.ethers.provider, + this.env.ethers.provider.provider + ); + }); + + it("should have a destroy method", async function () { + this.env.ethers.provider.destroy(); + }); + + it("should have a send method for raw JSON-RPC requests", async function () { + const accounts = await this.env.ethers.provider.send("eth_accounts"); + + assert.isArray(accounts); + }); + + describe("getSigner", function () { + it("should get a signer using an index", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + assert.strictEqual( + await signer.getAddress(), + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + }); + + it("should get a signer using an address", async function () { + const signer = await this.env.ethers.provider.getSigner( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + + assert.strictEqual( + await signer.getAddress(), + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + }); + + it("should get a signer even if the address is all lowercase", async function () { + const signer = await this.env.ethers.provider.getSigner( + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" + ); + + assert.strictEqual( + await signer.getAddress(), + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + }); + + it("should throw if the address checksum is wrong", async function () { + await assert.isRejected( + this.env.ethers.provider.getSigner( + "0XF39FD6E51AAD88F6F4CE6AB8827279CFFFB92266" + ), + "invalid address" + ); + }); + + it("should throw if the index doesn't match an account", async function () { + await assert.isRejected( + this.env.ethers.provider.getSigner(100), + "Tried to get account with index 100 but there are 20 accounts" + ); + }); + + it("should work for impersonated accounts", async function () { + const [s] = await this.env.ethers.getSigners(); + const randomAddress = "0xf965cceab9374d9f961581b6e38942e45e1cfeae"; + + await s.sendTransaction({ + to: randomAddress, + value: this.env.ethers.parseEther("1"), + }); + + await this.env.ethers.provider.send("hardhat_impersonateAccount", [ + randomAddress, + ]); + + const impersonatedSigner = await this.env.ethers.provider.getSigner( + randomAddress + ); + + // shouldn't revert + await impersonatedSigner.sendTransaction({ + to: s.address, + value: this.env.ethers.parseEther("0.1"), + }); + }); + }); + + it("should return the latest block number", async function () { + const latestBlockNumber = await this.env.ethers.provider.getBlockNumber(); + + assert.strictEqual(latestBlockNumber, 0); + + await this.env.ethers.provider.send("hardhat_mine"); + + assert.strictEqual(latestBlockNumber, 0); + }); + + it("should return the network", async function () { + const network = await this.env.ethers.provider.getNetwork(); + + assert.strictEqual(network.name, "hardhat"); + assert.strictEqual(network.chainId, 31337n); + }); + + it("should return fee data", async function () { + const feeData = await this.env.ethers.provider.getFeeData(); + + assert.typeOf(feeData.gasPrice, "bigint"); + assert.typeOf(feeData.maxFeePerGas, "bigint"); + assert.typeOf(feeData.maxPriorityFeePerGas, "bigint"); + }); + + describe("getBalance", function () { + beforeEach(async function () { + await this.env.network.provider.send("hardhat_reset"); + }); + + it("should return the balance of an address", async function () { + const balance = await this.env.ethers.provider.getBalance( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + + assert.strictEqual(balance, this.env.ethers.parseEther("10000")); + }); + + it("should return the balance of a signer", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const balance = await this.env.ethers.provider.getBalance(signer); + + assert.strictEqual(balance, this.env.ethers.parseEther("10000")); + }); + + it("should accept block numbers", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const gasLimit = 21_000n; + const gasPrice = this.env.ethers.parseUnits("100", "gwei"); + const value = this.env.ethers.parseEther("1"); + + await signer.sendTransaction({ + to: this.env.ethers.ZeroAddress, + value, + gasLimit, + gasPrice, + }); + + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const balanceAfter = await this.env.ethers.provider.getBalance( + signer, + "latest" + ); + assert.strictEqual( + balanceAfter, + this.env.ethers.parseEther("10000") - gasLimit * gasPrice - value + ); + + const balanceBefore = await this.env.ethers.provider.getBalance( + signer, + blockNumber - 1 + ); + assert.strictEqual(balanceBefore, this.env.ethers.parseEther("10000")); + }); + + it("should accept block hashes", async function () { + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const balance = await this.env.ethers.provider.getBalance( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + block.hash + ); + + assert.strictEqual(balance, this.env.ethers.parseEther("10000")); + }); + + it("should return the balance of a contract", async function () { + // deploy a contract with some ETH + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy({ + value: this.env.ethers.parseEther("0.5"), + }); + + // check the balance of the contract + const balance = await this.env.ethers.provider.getBalance(contract); + + assert.strictEqual(balance, 5n * 10n ** 17n); + }); + }); + + describe("getTransactionCount", function () { + beforeEach(async function () { + await this.env.network.provider.send("hardhat_reset"); + }); + + it("should return the transaction count of an address", async function () { + const balance = await this.env.ethers.provider.getTransactionCount( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ); + + assert.strictEqual(balance, 0); + }); + + it("should return the transaction count of a signer", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const balance = await this.env.ethers.provider.getTransactionCount( + signer + ); + + assert.strictEqual(balance, 0); + }); + + it("should accept block numbers", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + await signer.sendTransaction({ + to: this.env.ethers.ZeroAddress, + }); + + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const transactionCountAfter = + await this.env.ethers.provider.getTransactionCount(signer, "latest"); + assert.strictEqual(transactionCountAfter, 1); + + const transactionCountBefore = + await this.env.ethers.provider.getTransactionCount( + signer, + blockNumber - 1 + ); + assert.strictEqual(transactionCountBefore, 0); + }); + + it("should accept block hashes", async function () { + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const balance = await this.env.ethers.provider.getTransactionCount( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + block.hash + ); + + assert.strictEqual(balance, 0); + }); + }); + + describe("getCode", function () { + // deploys an empty contract + const deploymentBytecode = + "0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220eeaf807039e8b863535433564733b36afab56700620e89f192795eaf32f272ee64736f6c63430008110033"; + const contractBytecode = + "0x6080604052600080fdfea2646970667358221220eeaf807039e8b863535433564733b36afab56700620e89f192795eaf32f272ee64736f6c63430008110033"; + + let contract: ExampleContract; + beforeEach(async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + [], + deploymentBytecode, + signer + ); + contract = await factory.deploy(); + }); + + it("should return the code of an address", async function () { + const contractAddress = await contract.getAddress(); + + const code = await this.env.ethers.provider.getCode(contractAddress); + + assert.strictEqual(code, contractBytecode); + }); + + it("should return the code of a contract", async function () { + const code = await this.env.ethers.provider.getCode(contract); + + assert.strictEqual(code, contractBytecode); + }); + + it("should accept block numbers", async function () { + const codeAfter = await this.env.ethers.provider.getCode( + contract, + "latest" + ); + assert.strictEqual(codeAfter, contractBytecode); + + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + const codeBefore = await this.env.ethers.provider.getCode( + contract, + blockNumber - 1 + ); + assert.strictEqual(codeBefore, "0x"); + }); + + it("should accept block hashes", async function () { + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const code = await this.env.ethers.provider.getCode(contract, block.hash); + assert.strictEqual(code, contractBytecode); + }); + }); + + describe("getStorage", function () { + let contract: ExampleContract; + beforeEach(async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + contract = await factory.deploy(); + }); + + it("should get the storage of an address", async function () { + const contractAddress = await contract.getAddress(); + + await contract.inc(); + + const value = await this.env.ethers.provider.getStorage( + contractAddress, + 0 + ); + const doubleValue = await this.env.ethers.provider.getStorage( + contractAddress, + 1 + ); + + assert.strictEqual( + value, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + doubleValue, + "0x0000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("should get the storage of a contract", async function () { + await contract.inc(); + + const value = await this.env.ethers.provider.getStorage(contract, 0); + const doubleValue = await this.env.ethers.provider.getStorage( + contract, + 1 + ); + + assert.strictEqual( + value, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + doubleValue, + "0x0000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("should accept block numbers", async function () { + await contract.inc(); + + const storageValueAfter = await this.env.ethers.provider.getStorage( + contract, + 0, + "latest" + ); + assert.strictEqual( + storageValueAfter, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + const storageValueBefore = await this.env.ethers.provider.getStorage( + contract, + 0, + blockNumber - 1 + ); + assert.strictEqual( + storageValueBefore, + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("should accept block hashes", async function () { + await contract.inc(); + + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const storageValue = await this.env.ethers.provider.getStorage( + contract, + 0, + block.hash + ); + + assert.strictEqual( + storageValue, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + }); + + it("should accept short hex encode strings as the storage position", async function () { + await contract.inc(); + + const value = await this.env.ethers.provider.getStorage(contract, "0x0"); + const doubleValue = await this.env.ethers.provider.getStorage( + contract, + "0x1" + ); + assert.strictEqual( + value, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + doubleValue, + "0x0000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("should accept long hex encode strings as the storage position", async function () { + await contract.inc(); + + const value = await this.env.ethers.provider.getStorage( + contract, + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + const doubleValue = await this.env.ethers.provider.getStorage( + contract, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + value, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + doubleValue, + "0x0000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("should accept bigints as the storage position", async function () { + await contract.inc(); + + const value = await this.env.ethers.provider.getStorage(contract, 0n); + const doubleValue = await this.env.ethers.provider.getStorage( + contract, + 1n + ); + assert.strictEqual( + value, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + assert.strictEqual( + doubleValue, + "0x0000000000000000000000000000000000000000000000000000000000000002" + ); + }); + }); + + describe("estimateGas", function () { + it("should estimate gas for a value transaction", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const gasEstimation = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: signer.address, + }); + + assert.strictEqual(Number(gasEstimation), 21_001); + }); + + it("should estimate gas for a contract call", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + const gasEstimation = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + }); + + assertWithin(Number(gasEstimation), 65_000, 70_000); + }); + + it("should accept a block number", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + await contract.inc(); + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const gasEstimationAfter = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + blockTag: "latest", + }); + + assertWithin(Number(gasEstimationAfter), 30_000, 35_000); + + const gasEstimationBefore = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + blockTag: blockNumber - 1, + }); + + assertWithin(Number(gasEstimationBefore), 65_000, 70_000); + }); + + it("should accept a block hash", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const gasEstimation = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + blockTag: block.hash, + }); + + assertWithin(Number(gasEstimation), 65_000, 70_000); + }); + + it("should use the pending block by default", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + // this estimates the cost of increasing the value from 0 to 1 + const gasEstimationFirstInc = await this.env.ethers.provider.estimateGas({ + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + }); + + await this.env.ethers.provider.send("evm_setAutomine", [false]); + await contract.inc(); + + // if the pending block is used, this should estimate the cost of + // increasing the value from 1 to 2, and this should be cheaper than + // increasing it from 0 to 1 + const gasEstimationSecondInc = await this.env.ethers.provider.estimateGas( + { + from: signer.address, + to: await contract.getAddress(), + data: "0x371303c0", // inc() + } + ); + + assert.isTrue( + gasEstimationSecondInc < gasEstimationFirstInc, + "Expected second gas estimation to be lower" + ); + + await this.env.ethers.provider.send("evm_setAutomine", [true]); + }); + }); + + describe("call", function () { + it("should make a contract call using an address", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + await contract.inc(); + + const result = await this.env.ethers.provider.call({ + from: signer.address, + to: await contract.getAddress(), + data: "0x3fa4f245", // value() + }); + + assert.strictEqual( + result, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + }); + + it("should make a contract call using a contract", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + await contract.inc(); + + const result = await this.env.ethers.provider.call({ + from: signer.address, + to: contract, + data: "0x3fa4f245", // value() + }); + + assert.strictEqual( + result, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + }); + + it("should accept a block number", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + await contract.inc(); + + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const resultAfter = await this.env.ethers.provider.call({ + from: signer.address, + to: contract, + data: "0x3fa4f245", // value() + blockTag: "latest", + }); + + assert.strictEqual( + resultAfter, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + + const resultBefore = await this.env.ethers.provider.call({ + from: signer.address, + to: contract, + data: "0x3fa4f245", // value() + blockTag: blockNumber - 1, + }); + + assert.strictEqual( + resultBefore, + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("should accept a block hash", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + await contract.inc(); + + const block = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(block); + assertIsNotNull(block.hash); + + const result = await this.env.ethers.provider.call({ + from: signer.address, + to: contract, + data: "0x3fa4f245", // value() + blockTag: block.hash, + }); + + assert.strictEqual( + result, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + }); + }); + + describe("broadcastTransaction", function () { + it("should send a raw transaction", async function () { + await this.env.ethers.provider.send("hardhat_reset"); + // private key of the first unlocked account + const wallet = new this.env.ethers.Wallet( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + this.env.ethers.provider + ); + const rawTx = await wallet.signTransaction({ + to: this.env.ethers.ZeroAddress, + chainId: 31337, + gasPrice: 100n * 10n ** 9n, + gasLimit: 21_000, + }); + + const tx = await this.env.ethers.provider.broadcastTransaction(rawTx); + + assert.strictEqual(tx.from, wallet.address); + assert.strictEqual(tx.to, this.env.ethers.ZeroAddress); + assert.strictEqual(tx.gasLimit, 21_000n); + }); + }); + + describe("getBlock", function () { + it("should accept latest and earliest block tags", async function () { + await this.env.ethers.provider.send("hardhat_reset"); + await this.env.ethers.provider.send("hardhat_mine"); + await this.env.ethers.provider.send("hardhat_mine"); + await this.env.ethers.provider.send("hardhat_mine"); + + const latestBlock = await this.env.ethers.provider.getBlock("latest"); + assertIsNotNull(latestBlock); + assert.strictEqual(latestBlock.number, 3); + + const earliestBlock = await this.env.ethers.provider.getBlock("earliest"); + assertIsNotNull(earliestBlock); + assert.strictEqual(earliestBlock.number, 0); + }); + + it("should accept numbers", async function () { + await this.env.ethers.provider.send("hardhat_reset"); + await this.env.ethers.provider.send("hardhat_mine"); + await this.env.ethers.provider.send("hardhat_mine"); + await this.env.ethers.provider.send("hardhat_mine"); + + const latestBlock = await this.env.ethers.provider.getBlock(3); + assertIsNotNull(latestBlock); + assert.strictEqual(latestBlock.number, 3); + + const earliestBlock = await this.env.ethers.provider.getBlock(1); + assertIsNotNull(earliestBlock); + assert.strictEqual(earliestBlock.number, 1); + }); + + it("should accept block hashes", async function () { + await this.env.ethers.provider.send("hardhat_reset"); + + const blockByNumber = await this.env.ethers.provider.getBlock(0); + assertIsNotNull(blockByNumber); + assertIsNotNull(blockByNumber.hash); + + const blockByHash = await this.env.ethers.provider.getBlock( + blockByNumber.hash + ); + assertIsNotNull(blockByHash); + + assert.strictEqual(blockByNumber.number, blockByHash.number); + assert.strictEqual(blockByNumber.hash, blockByHash.hash); + }); + + it("shouldn't prefetch transactions by default", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const tx = await signer.sendTransaction({ to: signer.address }); + + const block = await this.env.ethers.provider.getBlock("latest"); + assertIsNotNull(block); + + assert.lengthOf(block.transactions, 1); + assert.strictEqual(block.transactions[0], tx.hash); + + assert.throws(() => block.prefetchedTransactions); + }); + + it("shouldn't prefetch transactions if false is passed", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const tx = await signer.sendTransaction({ to: signer.address }); + + const block = await this.env.ethers.provider.getBlock("latest", false); + assertIsNotNull(block); + + assert.lengthOf(block.transactions, 1); + assert.strictEqual(block.transactions[0], tx.hash); + + assert.throws(() => block.prefetchedTransactions); + }); + + it("should prefetch transactions if true is passed", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const tx = await signer.sendTransaction({ to: signer.address }); + + const block = await this.env.ethers.provider.getBlock("latest", true); + assertIsNotNull(block); + + assert.lengthOf(block.transactions, 1); + assert.strictEqual(block.transactions[0], tx.hash); + + assert.lengthOf(block.prefetchedTransactions, 1); + assert.strictEqual(block.prefetchedTransactions[0].hash, tx.hash); + assert.strictEqual(block.prefetchedTransactions[0].from, signer.address); + }); + }); + + describe("getTransaction", function () { + it("should get a transaction by its hash", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const sentTx = await signer.sendTransaction({ to: signer.address }); + + const fetchedTx = await this.env.ethers.provider.getTransaction( + sentTx.hash + ); + + assertIsNotNull(fetchedTx); + assert.strictEqual(fetchedTx.hash, sentTx.hash); + }); + + it("should return null if the transaction doesn't exist", async function () { + const tx = await this.env.ethers.provider.getTransaction( + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + + assert.isNull(tx); + }); + }); + + describe("getTransactionReceipt", function () { + it("should get a receipt by the transaction hash", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const tx = await signer.sendTransaction({ to: signer.address }); + + const receipt = await this.env.ethers.provider.getTransactionReceipt( + tx.hash + ); + + assertIsNotNull(receipt); + assert.strictEqual(receipt.hash, tx.hash); + assert.strictEqual(receipt.status, 1); + }); + + it("should return null if the transaction doesn't exist", async function () { + const receipt = await this.env.ethers.provider.getTransactionReceipt( + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + + assert.isNull(receipt); + }); + }); + + describe("getLogs", function () { + // keccak("Inc()") + const INC_EVENT_TOPIC = + "0xccf19ee637b3555bb918b8270dfab3f2b4ec60236d1ab717296aa85d6921224f"; + // keccak("AnotherEvent()") + const ANOTHER_EVENT_TOPIC = + "0x601d819e31a3cd164f83f7a7cf9cb5042ab1acff87b773c68f63d059c0af2dc0"; + + it("should get the logs from the latest block by default", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + await contract.inc(); + + const logs = await this.env.ethers.provider.getLogs({}); + + assert.lengthOf(logs, 1); + + const log = logs[0]; + assert.strictEqual(log.address, await contract.getAddress()); + assert.lengthOf(log.topics, 1); + assert.strictEqual(log.topics[0], INC_EVENT_TOPIC); + }); + + it("should get the logs by block number", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + await contract.inc(); + await this.env.ethers.provider.send("hardhat_mine"); + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + // latest block shouldn't have logs + const latestBlockLogs = await this.env.ethers.provider.getLogs({ + fromBlock: blockNumber, + toBlock: blockNumber, + }); + assert.lengthOf(latestBlockLogs, 0); + + const logs = await this.env.ethers.provider.getLogs({ + fromBlock: blockNumber - 1, + toBlock: blockNumber - 1, + }); + + assert.lengthOf(logs, 1); + + const log = logs[0]; + assert.strictEqual(log.address, await contract.getAddress()); + assert.lengthOf(log.topics, 1); + assert.strictEqual(log.topics[0], INC_EVENT_TOPIC); + }); + + it("should get the logs by address", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract1 = await factory.deploy(); + const contract2 = await factory.deploy(); + + await contract1.inc(); + await contract2.inc(); + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const logs = await this.env.ethers.provider.getLogs({ + fromBlock: blockNumber - 1, + toBlock: blockNumber, + }); + + assert.lengthOf(logs, 2); + + const logsByAddress = await this.env.ethers.provider.getLogs({ + address: await contract1.getAddress(), + fromBlock: blockNumber - 1, + toBlock: blockNumber, + }); + + assert.lengthOf(logsByAddress, 1); + assert.strictEqual( + logsByAddress[0].address, + await contract1.getAddress() + ); + }); + + it("should get the logs by an array of addresses", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract1 = await factory.deploy(); + const contract2 = await factory.deploy(); + const contract3 = await factory.deploy(); + + await contract1.inc(); + await contract2.inc(); + await contract3.inc(); + const blockNumber = await this.env.ethers.provider.getBlockNumber(); + + const logs = await this.env.ethers.provider.getLogs({ + fromBlock: blockNumber - 2, + toBlock: blockNumber, + }); + + assert.lengthOf(logs, 3); + + const contract1Address = await contract1.getAddress(); + const contract2Address = await contract2.getAddress(); + const logsByAddress = await this.env.ethers.provider.getLogs({ + address: [contract1Address, contract2Address], + fromBlock: blockNumber - 2, + toBlock: blockNumber, + }); + + assert.lengthOf(logsByAddress, 2); + assert.strictEqual(logsByAddress[0].address, contract1Address); + assert.strictEqual(logsByAddress[1].address, contract2Address); + }); + + it("should get the logs by topic", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + const contract = await factory.deploy(); + + await contract.emitsTwoEvents(); + + const logs = await this.env.ethers.provider.getLogs({}); + assert.lengthOf(logs, 2); + + const incEventLogs = await this.env.ethers.provider.getLogs({ + topics: [INC_EVENT_TOPIC], + }); + + assert.lengthOf(incEventLogs, 1); + assert.lengthOf(incEventLogs[0].topics, 1); + assert.strictEqual(incEventLogs[0].topics[0], INC_EVENT_TOPIC); + + const anotherEventLogs = await this.env.ethers.provider.getLogs({ + topics: [ANOTHER_EVENT_TOPIC], + }); + + assert.lengthOf(anotherEventLogs, 1); + assert.lengthOf(anotherEventLogs[0].topics, 1); + assert.strictEqual(anotherEventLogs[0].topics[0], ANOTHER_EVENT_TOPIC); + }); + }); +}); diff --git a/packages/hardhat-ethers/test/custom-ethers-signer.ts b/packages/hardhat-ethers/test/custom-ethers-signer.ts new file mode 100644 index 0000000000..2bb725b4df --- /dev/null +++ b/packages/hardhat-ethers/test/custom-ethers-signer.ts @@ -0,0 +1,299 @@ +import { assert } from "chai"; + +import { ExampleContract, EXAMPLE_CONTRACT } from "./example-contracts"; +import { + assertIsNotNull, + assertWithin, + usePersistentEnvironment, +} from "./helpers"; + +describe("custom signer", function () { + describe("minimal project", function () { + usePersistentEnvironment("minimal-project"); + + it("has an address field that matches the address", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + assert.isString(signer.address); + assert.strictEqual(signer.address, await signer.getAddress()); + }); + + it("can be connected to a provider", async function () { + if ( + process.env.INFURA_URL === undefined || + process.env.INFURA_URL === "" + ) { + this.skip(); + } + + const signerConnectedToHardhat = await this.env.ethers.provider.getSigner( + 0 + ); + + const nonceInHardhat = await signerConnectedToHardhat.getNonce(); + + const mainnetProvider = new this.env.ethers.JsonRpcProvider( + process.env.INFURA_URL + ); + + const signerConnectedToMainnet = + signerConnectedToHardhat.connect(mainnetProvider); + + const nonceInMainnet = await signerConnectedToMainnet.getNonce(); + + assert.strictEqual(nonceInHardhat, 0); + assert.isAbove(nonceInMainnet, 0); + }); + + it("can get the nonce of the signer", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + assert.strictEqual(await signer.getNonce(), 0); + + await signer.sendTransaction({ to: signer }); + assert.strictEqual(await signer.getNonce(), 1); + }); + + it("should populate a call/tx", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const populatedCall = await signer.populateCall({ + to: signer, + }); + + assert.strictEqual(populatedCall.from, signer.address); + + // populateTransaction does exactly the same + const populatedTx = await signer.populateCall({ + to: signer, + }); + + assert.strictEqual(populatedTx.from, signer.address); + }); + + describe("estimateGas", function () { + it("should estimate gas for a value transaction", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const gasEstimation = await signer.estimateGas({ + to: signer, + }); + + assert.strictEqual(Number(gasEstimation), 21_001); + }); + + it("should estimate gas for a contract call", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory< + [], + ExampleContract + >(EXAMPLE_CONTRACT.abi, EXAMPLE_CONTRACT.deploymentBytecode, signer); + const contract = await factory.deploy(); + + const gasEstimation = await signer.estimateGas({ + to: contract, + data: "0x371303c0", // inc() + }); + + assertWithin(Number(gasEstimation), 65_000, 70_000); + }); + }); + + describe("call", function () { + it("should make a contract call", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + const factory = new this.env.ethers.ContractFactory< + [], + ExampleContract + >(EXAMPLE_CONTRACT.abi, EXAMPLE_CONTRACT.deploymentBytecode, signer); + const contract = await factory.deploy(); + await contract.inc(); + + const result = await signer.call({ + to: contract, + data: "0x3fa4f245", // value() + }); + + assert.strictEqual( + result, + "0x0000000000000000000000000000000000000000000000000000000000000001" + ); + }); + }); + + describe("sendTransaction", function () { + it("should send a transaction", async function () { + const sender = await this.env.ethers.provider.getSigner(0); + const receiver = await this.env.ethers.provider.getSigner(1); + + const balanceBefore = await this.env.ethers.provider.getBalance( + receiver + ); + + await sender.sendTransaction({ + to: receiver, + value: this.env.ethers.parseEther("1"), + }); + + const balanceAfter = await this.env.ethers.provider.getBalance( + receiver + ); + + const balanceDifference = balanceAfter - balanceBefore; + + assert.strictEqual(balanceDifference, 10n ** 18n); + }); + }); + + describe("signMessage", function () { + it("should sign a message", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const signedMessage = await signer.signMessage("hello"); + + assert.strictEqual( + signedMessage, + "0xf16ea9a3478698f695fd1401bfe27e9e4a7e8e3da94aa72b021125e31fa899cc573c48ea3fe1d4ab61a9db10c19032026e3ed2dbccba5a178235ac27f94504311c" + ); + }); + }); + + describe("signTypedData", function () { + const types = { + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, + ], + }; + + const data = { + from: { + name: "John", + wallet: "0x0000000000000000000000000000000000000001", + }, + to: { + name: "Mark", + wallet: "0x0000000000000000000000000000000000000002", + }, + contents: "something", + }; + + it("should sign data", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const signedData = await signer.signTypedData( + { + chainId: 31337, + }, + types, + data + ); + + assert.strictEqual( + signedData, + "0xbea20009786d1f69327eea384d6b8082f2d35b41212d1acbbd490516f0ae776748e93d4603df49033f89ce6a97afba4523d753d35e962ea431cc706642ad713f1b" + ); + }); + + it("should use the chain id", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const signedData = await signer.signTypedData( + { + chainId: 10101, + }, + types, + data + ); + + // we get a different value from the different test because we changed the + // chainId + assert.strictEqual( + signedData, + "0x8a6a6aeca0cf03dbffd6d7b15207c0dcf5c7daa432e510b5de1ebecff8de6cd457e2eaa9fe96c11474a7344584f4b128c773153836142647c426b5f2c3eb6c701b" + ); + }); + }); + + describe("default gas limit", function () { + it("should use the block gas limit for the in-process hardhat network", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const tx = await signer.sendTransaction({ to: signer }); + + if (!("blockGasLimit" in this.env.network.config)) { + assert.fail("test should be run in the hardhat network"); + } + + const blockGasLimit = this.env.network.config.blockGasLimit; + assert.strictEqual(Number(tx.gasLimit), blockGasLimit); + }); + + it("should use custom gas limit, if provided", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const tx = await signer.sendTransaction({ + to: signer, + gasLimit: 30_000, + }); + + assert.strictEqual(tx.gasLimit, 30_000n); + }); + }); + + describe("nonce management", function () { + it("should send a second transaction with the right nonce if the first one wasn't mined", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + await this.env.ethers.provider.send("evm_setAutomine", [false]); + + const tx1 = await signer.sendTransaction({ + to: signer, + gasLimit: 30_000, + }); + const tx2 = await signer.sendTransaction({ + to: signer, + gasLimit: 30_000, + }); + + assert.notEqual(tx1.nonce, tx2.nonce); + assert.strictEqual(tx2.nonce, tx1.nonce + 1); + + await this.env.ethers.provider.send("hardhat_mine", []); + + const latestBlock = await this.env.ethers.provider.getBlock("latest"); + + assertIsNotNull(latestBlock); + + assert.lengthOf(latestBlock.transactions, 2); + }); + }); + }); + + describe('project with gas set to "auto"', function () { + usePersistentEnvironment("hardhat-project-with-gas-auto"); + + it("should estimate the gas of the transaction", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const tx = await signer.sendTransaction({ to: signer }); + + assert.strictEqual(tx.gasLimit, 21_001n); + }); + + it("should use custom gas limit, if provided", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const tx = await signer.sendTransaction({ + to: signer, + gasLimit: 30_000, + }); + + assert.strictEqual(tx.gasLimit, 30_000n); + }); + }); +}); diff --git a/packages/hardhat-ethers/test/ethers-provider-wrapper.ts b/packages/hardhat-ethers/test/ethers-provider-wrapper.ts deleted file mode 100644 index d1f730195f..0000000000 --- a/packages/hardhat-ethers/test/ethers-provider-wrapper.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { assert } from "chai"; -import { ethers } from "ethers"; - -import { EthersProviderWrapper } from "../src/internal/ethers-provider-wrapper"; - -import { useEnvironment } from "./helpers"; - -describe("Ethers provider wrapper", function () { - let realProvider: ethers.providers.JsonRpcProvider; - let wrapper: EthersProviderWrapper; - - useEnvironment("hardhat-project"); - - beforeEach(function () { - realProvider = new ethers.providers.JsonRpcProvider( - "http://127.0.0.1:8545" - ); - wrapper = new EthersProviderWrapper(this.env.network.provider); - }); - - it("Should return the same as the real provider", async function () { - const response = await realProvider.send("eth_accounts", []); - const response2 = await wrapper.send("eth_accounts", []); - - assert.deepEqual(response, response2); - }); - - it("Should return the same error", async function () { - this.skip(); - // We disable this test for RskJ - // See: https://github.com/rsksmart/rskj/issues/876 - const version: string = await this.env.network.provider.send( - "web3_clientVersion" - ); - if (version.includes("RskJ")) { - this.skip(); - } - - try { - await realProvider.send("error_please", []); - assert.fail("Ethers provider should have failed"); - } catch (err: any) { - try { - await wrapper.send("error_please", []); - assert.fail("Wrapped provider should have failed"); - } catch (err2: any) { - assert.deepEqual(err2.message, err.message); - } - } - }); -}); diff --git a/packages/hardhat-ethers/test/example-contracts.ts b/packages/hardhat-ethers/test/example-contracts.ts new file mode 100644 index 0000000000..7f463fcd38 --- /dev/null +++ b/packages/hardhat-ethers/test/example-contracts.ts @@ -0,0 +1,58 @@ +import type { + BaseContract, + BaseContractMethod, + BigNumberish, + ContractTransactionResponse, +} from "ethers"; + +/* +contract Example { + uint public value; + uint public doubleValue; + event Inc(); + event AnotherEvent(); + + constructor() payable {} + + function inc() public { + value++; + doubleValue = 2 * value; + emit Inc(); + } + + function emitsTwoEvents() public { + emit Inc(); + emit AnotherEvent(); + } +} +*/ +export const EXAMPLE_CONTRACT = { + deploymentBytecode: + "0x6080604052610284806100136000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063371303c0146100515780633fa4f2451461005b578063b190115914610079578063e377818414610083575b600080fd5b6100596100a1565b005b6100636100fb565b604051610070919061017a565b60405180910390f35b610081610101565b005b61008b61015b565b604051610098919061017a565b60405180910390f35b6000808154809291906100b3906101c4565b919050555060005460026100c7919061020c565b6001819055507fccf19ee637b3555bb918b8270dfab3f2b4ec60236d1ab717296aa85d6921224f60405160405180910390a1565b60005481565b7fccf19ee637b3555bb918b8270dfab3f2b4ec60236d1ab717296aa85d6921224f60405160405180910390a17f601d819e31a3cd164f83f7a7cf9cb5042ab1acff87b773c68f63d059c0af2dc060405160405180910390a1565b60015481565b6000819050919050565b61017481610161565b82525050565b600060208201905061018f600083018461016b565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101cf82610161565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361020157610200610195565b5b600182019050919050565b600061021782610161565b915061022283610161565b925082820261023081610161565b9150828204841483151761024757610246610195565b5b509291505056fea2646970667358221220bedfe038de0cf21194c025de5a282c3415bf29f716ef1af0073bc2c45d803e8164736f6c63430008110033", + abi: [ + "event Inc()", + "event AnotherEvent()", + "function value() public view returns (uint256)", + "function doubleValue() public view returns (uint256)", + "function inc() public", + "function emitsTwoEvents() public", + ], +}; + +export type ExampleContract = BaseContract & { + inc: BaseContractMethod<[], void, ContractTransactionResponse>; + emitsTwoEvents: BaseContractMethod<[], void, ContractTransactionResponse>; +}; + +export type TestContractLib = BaseContract & { + printNumber: BaseContractMethod< + [BigNumberish], + bigint, + ContractTransactionResponse + >; +}; + +export type GreeterContract = BaseContract & { + greet: BaseContractMethod<[], string, string>; + setGreeting: BaseContractMethod<[string], void, ContractTransactionResponse>; +}; diff --git a/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/.gitignore b/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/.gitignore new file mode 100644 index 0000000000..4a4ecc528f --- /dev/null +++ b/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/.gitignore @@ -0,0 +1,2 @@ +cache/ +artifacts/ diff --git a/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/hardhat.config.js b/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/hardhat.config.js new file mode 100644 index 0000000000..18a8d57186 --- /dev/null +++ b/packages/hardhat-ethers/test/fixture-projects/hardhat-project-with-gas-auto/hardhat.config.js @@ -0,0 +1,10 @@ +require("../../../src/internal/index"); + +module.exports = { + solidity: "0.5.15", + networks: { + hardhat: { + gas: "auto", + }, + }, +}; diff --git a/packages/hardhat-ethers/test/fixture-projects/minimal-project/hardhat.config.js b/packages/hardhat-ethers/test/fixture-projects/minimal-project/hardhat.config.js new file mode 100644 index 0000000000..c1f3384738 --- /dev/null +++ b/packages/hardhat-ethers/test/fixture-projects/minimal-project/hardhat.config.js @@ -0,0 +1,5 @@ +require("../../../src/internal/index"); + +module.exports = { + solidity: "0.8.0", +}; diff --git a/packages/hardhat-ethers/test/helpers.ts b/packages/hardhat-ethers/test/helpers.ts index 17642ecd83..318ad7e5b6 100644 --- a/packages/hardhat-ethers/test/helpers.ts +++ b/packages/hardhat-ethers/test/helpers.ts @@ -1,3 +1,5 @@ +import { assert } from "chai"; +import { ContractRunner, Signer } from "ethers"; import { resetHardhatContext } from "hardhat/plugins-testing"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import path from "path"; @@ -13,7 +15,7 @@ declare module "mocha" { export function useEnvironment( fixtureProjectName: string, - networkName = "localhost" + networkName = "hardhat" ) { beforeEach("Loading hardhat environment", function () { process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName)); @@ -26,3 +28,43 @@ export function useEnvironment( resetHardhatContext(); }); } + +export function usePersistentEnvironment( + fixtureProjectName: string, + networkName = "hardhat" +) { + before("Loading hardhat environment", function () { + process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName)); + process.env.HARDHAT_NETWORK = networkName; + + this.env = require("hardhat"); + }); + + after("Resetting hardhat", function () { + resetHardhatContext(); + }); +} + +export function assertWithin( + value: number | bigint, + min: number | bigint, + max: number | bigint +) { + if (value < min || value > max) { + assert.fail(`Expected ${value} to be between ${min} and ${max}`); + } +} + +export function assertIsNotNull( + value: T +): asserts value is Exclude { + assert.isNotNull(value); +} + +export function assertIsSigner( + value: ContractRunner | null +): asserts value is Signer { + assertIsNotNull(value); + assert.isTrue("getAddress" in value); + assert.isTrue("signTransaction" in value); +} diff --git a/packages/hardhat-ethers/test/index.ts b/packages/hardhat-ethers/test/index.ts index 50bd7757d8..4ae4bc9442 100644 --- a/packages/hardhat-ethers/test/index.ts +++ b/packages/hardhat-ethers/test/index.ts @@ -1,19 +1,21 @@ +import type { ethers as EthersT } from "ethers"; import chai, { assert } from "chai"; import chaiAsPromised from "chai-as-promised"; -import { ethers, Signer } from "ethers"; +import { ethers } from "ethers"; import { NomicLabsHardhatPluginError } from "hardhat/plugins"; import { Artifact } from "hardhat/types"; -import util from "util"; -import { EthersProviderWrapper } from "../src/internal/ethers-provider-wrapper"; +import { CustomEthersSigner } from "../src/signers"; +import { GreeterContract, TestContractLib } from "./example-contracts"; -import { useEnvironment } from "./helpers"; +import { assertIsSigner, useEnvironment } from "./helpers"; chai.use(chaiAsPromised); describe("Ethers plugin", function () { describe("ganache", function () { - useEnvironment("hardhat-project"); + useEnvironment("hardhat-project", "localhost"); + describe("HRE extensions", function () { it("should extend hardhat runtime environment", function () { assert.isDefined(this.env.ethers); @@ -26,84 +28,6 @@ describe("Ethers plugin", function () { ...Object.keys(ethers), ]); }); - - describe("Custom formatters", function () { - const assertBigNumberFormat = function ( - BigNumber: any, - value: string | number, - expected: string - ) { - assert.equal(util.format("%o", BigNumber.from(value)), expected); - }; - - describe("BigNumber", function () { - it("should format zero unaltered", function () { - assertBigNumberFormat( - this.env.ethers.BigNumber, - 0, - 'BigNumber { value: "0" }' - ); - }); - - it("should provide human readable versions of positive integers", function () { - const BigNumber = this.env.ethers.BigNumber; - - assertBigNumberFormat(BigNumber, 1, 'BigNumber { value: "1" }'); - assertBigNumberFormat(BigNumber, 999, 'BigNumber { value: "999" }'); - assertBigNumberFormat( - BigNumber, - 1000, - 'BigNumber { value: "1000" }' - ); - assertBigNumberFormat( - BigNumber, - 999999, - 'BigNumber { value: "999999" }' - ); - assertBigNumberFormat( - BigNumber, - 1000000, - 'BigNumber { value: "1000000" }' - ); - assertBigNumberFormat( - BigNumber, - "999999999999999999292", - 'BigNumber { value: "999999999999999999292" }' - ); - }); - - it("should provide human readable versions of negative integers", function () { - const BigNumber = this.env.ethers.BigNumber; - - assertBigNumberFormat(BigNumber, -1, 'BigNumber { value: "-1" }'); - assertBigNumberFormat( - BigNumber, - -999, - 'BigNumber { value: "-999" }' - ); - assertBigNumberFormat( - BigNumber, - -1000, - 'BigNumber { value: "-1000" }' - ); - assertBigNumberFormat( - BigNumber, - -999999, - 'BigNumber { value: "-999999" }' - ); - assertBigNumberFormat( - BigNumber, - -1000000, - 'BigNumber { value: "-1000000" }' - ); - assertBigNumberFormat( - BigNumber, - "-999999999999999999292", - 'BigNumber { value: "-999999999999999999292" }' - ); - }); - }); - }); }); describe("Provider", function () { @@ -112,12 +36,15 @@ describe("Ethers plugin", function () { "eth_accounts", [] ); - assert.equal(accounts[0], "0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1"); + assert.strictEqual( + accounts[0], + "0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1" + ); }); }); describe("Signers and contracts helpers", function () { - let signers: ethers.Signer[]; + let signers: CustomEthersSigner[]; let greeterArtifact: Artifact; let iGreeterArtifact: Artifact; @@ -132,7 +59,7 @@ describe("Ethers plugin", function () { describe("getSigners", function () { it("should return the signers", async function () { const sigs = await this.env.ethers.getSigners(); - assert.equal( + assert.strictEqual( await sigs[0].getAddress(), "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" ); @@ -140,7 +67,7 @@ describe("Ethers plugin", function () { it("should expose the address synchronously", async function () { const sigs = await this.env.ethers.getSigners(); - assert.equal( + assert.strictEqual( sigs[0].address, "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" ); @@ -171,7 +98,7 @@ describe("Ethers plugin", function () { const result = await sig.signMessage("hello"); - assert.equal( + assert.strictEqual( result, "0x1845faa75f53acb0c3e7247dcf294ce045c139722418dc9638709b54bafffa093591aeaaa195e7dc53f7e774c80e9a7f1371f0647a100d1c9e81db83d8ddd47801" ); @@ -181,40 +108,54 @@ describe("Ethers plugin", function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); - assert.throws(() => sig.signTransaction(tx)); + await assert.isRejected(sig.signTransaction(tx)); }); - it("should return the balance of the account", async function () { + // `signer.getBalance` is not present in ethers v6; we should re-enable + // this test when/if it's added back + it.skip("should return the balance of the account", async function () { const [sig] = await this.env.ethers.getSigners(); - assert.equal( + assert.strictEqual( + // @ts-expect-error (await sig.getBalance()).toString(), "100000000000000000000" ); }); + it("should return the balance of the account", async function () { + const [sig] = await this.env.ethers.getSigners(); + assert.strictEqual( + await this.env.ethers.provider.getBalance(sig), + 100000000000000000000n + ); + }); + it("should return the transaction count of the account", async function () { const [sig] = await this.env.ethers.getSigners(); - assert.equal((await sig.getTransactionCount()).toString(), "0"); + assert.strictEqual( + await this.env.ethers.provider.getTransactionCount(sig), + 0 + ); }); it("should allow to use the estimateGas method", async function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); const result = await sig.estimateGas(tx); - assert.isTrue(result.gt(0)); + assert.isTrue(result > 0n); }); it("should allow to use the call method", async function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); const result = await sig.call(tx); @@ -225,46 +166,39 @@ describe("Ethers plugin", function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); const response = await sig.sendTransaction(tx); const receipt = await response.wait(); - assert.equal(receipt.status, 1); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + assert.strictEqual(receipt.status, 1); }); it("should get the chainId", async function () { - const [sig] = await this.env.ethers.getSigners(); + const { chainId } = await this.env.ethers.provider.getNetwork(); - const chainId = await sig.getChainId(); - - assert.equal(chainId, 1337); + assert.strictEqual(chainId, 1337n); }); it("should get the gas price", async function () { - const [sig] = await this.env.ethers.getSigners(); - - const gasPrice = await sig.getGasPrice(); + const feeData = await this.env.ethers.provider.getFeeData(); - assert.equal(gasPrice.toString(), "20000000000"); + assert.strictEqual(feeData.gasPrice, 20000000000n); }); - it("should check and populate a transaction", async function () { + it("should populate a transaction", async function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); - const checkedTransaction = sig.checkTransaction(tx); + const populatedTransaction = await sig.populateTransaction(tx); - assert.equal(await checkedTransaction.from, sig.address); - - const populatedTransaction = await sig.populateTransaction( - checkedTransaction - ); - - assert.equal(populatedTransaction.from, sig.address); + assert.strictEqual(populatedTransaction.from, sig.address); }); }); @@ -276,13 +210,15 @@ describe("Ethers plugin", function () { "Greeter" ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + + // non-existent functions should be null + assert.isNull(contract.interface.getFunction("doesntExist")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -315,19 +251,22 @@ describe("Ethers plugin", function () { ); const library = await libraryFactory.deploy(); - const contractFactory = await this.env.ethers.getContractFactory( - "TestContractLib", - { libraries: { TestLibrary: library.address } } - ); - assert.equal( - await contractFactory.signer.getAddress(), + const contractFactory = await this.env.ethers.getContractFactory< + [], + TestContractLib + >("TestContractLib", { + libraries: { TestLibrary: library.target }, + }); + assertIsSigner(contractFactory.runner); + assert.strictEqual( + await contractFactory.runner.getAddress(), await signers[0].getAddress() ); const numberPrinter = await contractFactory.deploy(); - const someNumber = 50; - assert.equal( - await numberPrinter.callStatic.printNumber(someNumber), - someNumber * 2 + const someNumber = 50n; + assert.strictEqual( + await numberPrinter.printNumber.staticCall(someNumber), + someNumber * 2n ); }); @@ -340,8 +279,9 @@ describe("Ethers plugin", function () { try { await this.env.ethers.getContractFactory("TestContractLib", { libraries: { - TestLibrary: library.address, - "contracts/TestContractLib.sol:TestLibrary": library.address, + TestLibrary: await library.getAddress(), + "contracts/TestContractLib.sol:TestLibrary": + await library.getAddress(), }, }); } catch (reason: any) { @@ -379,10 +319,11 @@ describe("Ethers plugin", function () { const contractFactory = await this.env.ethers.getContractFactory( "TestNonUniqueLib", - { libraries: { NonUniqueLibrary: library.address } } + { libraries: { NonUniqueLibrary: await library.getAddress() } } ); - assert.equal( - await contractFactory.signer.getAddress(), + assertIsSigner(contractFactory.runner); + assert.strictEqual( + await contractFactory.runner.getAddress(), await signers[0].getAddress() ); }); @@ -400,9 +341,9 @@ describe("Ethers plugin", function () { try { await this.env.ethers.getContractFactory("TestAmbiguousLib", { libraries: { - AmbiguousLibrary: library.address, + AmbiguousLibrary: await library.getAddress(), "contracts/AmbiguousLibrary2.sol:AmbiguousLibrary": - library2.address, + await library2.getAddress(), }, }); } catch (reason: any) { @@ -490,49 +431,27 @@ describe("Ethers plugin", function () { ); }); - it("should fail to create a contract factory when incorrectly linking a library with an ethers.Contract", async function () { + it("should contract instances as libraries", async function () { const libraryFactory = await this.env.ethers.getContractFactory( "TestLibrary" ); const library = await libraryFactory.deploy(); - try { - await this.env.ethers.getContractFactory("TestContractLib", { - libraries: { TestLibrary: library as any }, - }); - } catch (reason: any) { - assert.instanceOf( - reason, - NomicLabsHardhatPluginError, - "getContractFactory should fail with a hardhat plugin error" - ); - assert.isTrue( - reason.message.includes( - "invalid address", - "getContractFactory should report the invalid address as the cause" - ) - ); - // This assert is here just to make sure we don't end up printing an enormous object - // in the error message. This may happen if the argument received is particularly complex. - assert.isTrue( - reason.message.length <= 400, - "getContractFactory should fail with an error message that isn't too large" - ); - return; - } - - assert.fail( - "getContractFactory should fail to create a contract factory if there is an invalid address" - ); + await this.env.ethers.getContractFactory("TestContractLib", { + libraries: { TestLibrary: library }, + }); }); it("Should be able to send txs and make calls", async function () { - const Greeter = await this.env.ethers.getContractFactory("Greeter"); + const Greeter = await this.env.ethers.getContractFactory< + [], + GreeterContract + >("Greeter"); const greeter = await Greeter.deploy(); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); describe("with custom signer", function () { @@ -543,13 +462,12 @@ describe("Ethers plugin", function () { signers[1] ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -564,13 +482,12 @@ describe("Ethers plugin", function () { greeterArtifact.bytecode ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -580,25 +497,26 @@ describe("Ethers plugin", function () { iGreeterArtifact.abi, iGreeterArtifact.bytecode ); - assert.equal(contract.bytecode, "0x"); - assert.containsAllKeys(contract.interface.functions, ["greet()"]); + assert.strictEqual(contract.bytecode, "0x"); + assert.isNotNull(contract.interface.getFunction("greet")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); it("Should be able to send txs and make calls", async function () { - const Greeter = await this.env.ethers.getContractFactory( - greeterArtifact.abi, - greeterArtifact.bytecode - ); + const Greeter = await this.env.ethers.getContractFactory< + [], + GreeterContract + >(greeterArtifact.abi, greeterArtifact.bytecode); const greeter = await Greeter.deploy(); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); describe("with custom signer", function () { @@ -610,13 +528,12 @@ describe("Ethers plugin", function () { signers[1] ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -630,13 +547,12 @@ describe("Ethers plugin", function () { greeterArtifact ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -652,32 +568,37 @@ describe("Ethers plugin", function () { ); const contractFactory = - await this.env.ethers.getContractFactoryFromArtifact( - testContractLibArtifact, - { libraries: { TestLibrary: library.address } } - ); + await this.env.ethers.getContractFactoryFromArtifact< + [], + TestContractLib + >(testContractLibArtifact, { + libraries: { TestLibrary: await library.getAddress() }, + }); + assertIsSigner(contractFactory.runner); - assert.equal( - await contractFactory.signer.getAddress(), + assert.strictEqual( + await contractFactory.runner.getAddress(), await signers[0].getAddress() ); + const numberPrinter = await contractFactory.deploy(); - const someNumber = 50; - assert.equal( - await numberPrinter.callStatic.printNumber(someNumber), - someNumber * 2 + const someNumber = 50n; + assert.strictEqual( + await numberPrinter.printNumber.staticCall(someNumber), + someNumber * 2n ); }); it("Should be able to send txs and make calls", async function () { - const Greeter = await this.env.ethers.getContractFactoryFromArtifact( - greeterArtifact - ); + const Greeter = await this.env.ethers.getContractFactoryFromArtifact< + [], + GreeterContract + >(greeterArtifact); const greeter = await Greeter.deploy(); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); describe("with custom signer", function () { @@ -688,13 +609,12 @@ describe("Ethers plugin", function () { signers[1] ); - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -702,10 +622,13 @@ describe("Ethers plugin", function () { }); describe("getContractAt", function () { - let deployedGreeter: ethers.Contract; + let deployedGreeter: GreeterContract; beforeEach(async function () { - const Greeter = await this.env.ethers.getContractFactory("Greeter"); + const Greeter = await this.env.ethers.getContractFactory< + [], + GreeterContract + >("Greeter"); deployedGreeter = await Greeter.deploy(); }); @@ -719,16 +642,15 @@ describe("Ethers plugin", function () { it("Should return an instance of a contract", async function () { const contract = await this.env.ethers.getContractAt( "Greeter", - deployedGreeter.address + deployedGreeter.target ); - assert.containsAllKeys(contract.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.exists(contract.setGreeting); + assert.exists(contract.greet); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -736,13 +658,14 @@ describe("Ethers plugin", function () { it("Should return an instance of an interface", async function () { const contract = await this.env.ethers.getContractAt( "IGreeter", - deployedGreeter.address + deployedGreeter.target ); - assert.containsAllKeys(contract.functions, ["greet()"]); + assert.isNotNull(contract.interface.getFunction("greet")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -750,24 +673,24 @@ describe("Ethers plugin", function () { it("Should be able to send txs and make calls", async function () { const greeter = await this.env.ethers.getContractAt( "Greeter", - deployedGreeter.address + deployedGreeter.target ); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); describe("with custom signer", function () { it("Should return an instance of a contract associated to a custom signer", async function () { const contract = await this.env.ethers.getContractAt( "Greeter", - deployedGreeter.address, + deployedGreeter.target, signers[1] ); - - assert.equal( - await contract.signer.getAddress(), + assertIsSigner(contract.runner); + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -778,16 +701,15 @@ describe("Ethers plugin", function () { it("Should return an instance of a contract", async function () { const contract = await this.env.ethers.getContractAt( greeterArtifact.abi, - deployedGreeter.address + deployedGreeter.target ); - assert.containsAllKeys(contract.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -795,13 +717,14 @@ describe("Ethers plugin", function () { it("Should return an instance of an interface", async function () { const contract = await this.env.ethers.getContractAt( iGreeterArtifact.abi, - deployedGreeter.address + deployedGreeter.target ); - assert.containsAllKeys(contract.functions, ["greet()"]); + assert.isNotNull(contract.interface.getFunction("greet")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -809,52 +732,52 @@ describe("Ethers plugin", function () { it("Should be able to send txs and make calls", async function () { const greeter = await this.env.ethers.getContractAt( greeterArtifact.abi, - deployedGreeter.address + deployedGreeter.target ); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); - it("Should be able to detect events", async function () { - const greeter = await this.env.ethers.getContractAt( - greeterArtifact.abi, - deployedGreeter.address - ); - - // at the time of this writing, ethers' default polling interval is - // 4000 ms. here we turn it down in order to speed up this test. - // see also - // https://github.com/ethers-io/ethers.js/issues/615#issuecomment-848991047 - const provider = greeter.provider as EthersProviderWrapper; - provider.pollingInterval = 100; - - let eventEmitted = false; - greeter.on("GreetingUpdated", () => { - eventEmitted = true; - }); - - await greeter.functions.setGreeting("Hola"); - - // wait for 1.5 polling intervals for the event to fire - await new Promise((resolve) => - setTimeout(resolve, provider.pollingInterval * 2) - ); - - assert.equal(eventEmitted, true); - }); + // TODO re-enable when we make .on("event") work + // it("Should be able to detect events", async function () { + // const greeter = await this.env.ethers.getContractAt( + // greeterArtifact.abi, + // deployedGreeter.target + // ); + // + // // at the time of this writing, ethers' default polling interval is + // // 4000 ms. here we turn it down in order to speed up this test. + // // see also + // // https://github.com/ethers-io/ethers.js/issues/615#issuecomment-848991047 + // // const provider = greeter.provider as any; + // // provider.pollingInterval = 100; + // + // let eventEmitted = false; + // await greeter.on("GreetingUpdated", () => { + // eventEmitted = true; + // }); + // + // await greeter.setGreeting("Hola"); + // + // // wait for 1.5 polling intervals for the event to fire + // await new Promise((resolve) => setTimeout(resolve, 10_000)); + // + // assert.strictEqual(eventEmitted, true); + // }); describe("with custom signer", function () { it("Should return an instance of a contract associated to a custom signer", async function () { const contract = await this.env.ethers.getContractAt( greeterArtifact.abi, - deployedGreeter.address, + deployedGreeter.target, signers[1] ); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -866,31 +789,36 @@ describe("Ethers plugin", function () { ); const library = await libraryFactory.deploy(); - const contractFactory = await this.env.ethers.getContractFactory( - "TestContractLib", - { libraries: { TestLibrary: library.address } } - ); + const contractFactory = await this.env.ethers.getContractFactory< + [], + TestContractLib + >("TestContractLib", { + libraries: { TestLibrary: library.target }, + }); const numberPrinter = await contractFactory.deploy(); const numberPrinterAtAddress = await this.env.ethers.getContractAt( "TestContractLib", - numberPrinter.address + numberPrinter.target ); - const someNumber = 50; - assert.equal( - await numberPrinterAtAddress.callStatic.printNumber(someNumber), - someNumber * 2 + const someNumber = 50n; + assert.strictEqual( + await numberPrinterAtAddress.printNumber.staticCall(someNumber), + someNumber * 2n ); }); }); }); describe("getContractAtFromArtifact", function () { - let deployedGreeter: ethers.Contract; + let deployedGreeter: GreeterContract; beforeEach(async function () { - const Greeter = await this.env.ethers.getContractFactory("Greeter"); + const Greeter = await this.env.ethers.getContractFactory< + [], + GreeterContract + >("Greeter"); deployedGreeter = await Greeter.deploy(); }); @@ -898,16 +826,15 @@ describe("Ethers plugin", function () { it("Should return an instance of a contract", async function () { const contract = await this.env.ethers.getContractAtFromArtifact( greeterArtifact, - deployedGreeter.address + await deployedGreeter.getAddress() ); - assert.containsAllKeys(contract.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[0].getAddress() ); }); @@ -915,24 +842,25 @@ describe("Ethers plugin", function () { it("Should be able to send txs and make calls", async function () { const greeter = await this.env.ethers.getContractAtFromArtifact( greeterArtifact, - deployedGreeter.address + await deployedGreeter.getAddress() ); - assert.equal(await greeter.functions.greet(), "Hi"); - await greeter.functions.setGreeting("Hola"); - assert.equal(await greeter.functions.greet(), "Hola"); + assert.strictEqual(await greeter.greet(), "Hi"); + await greeter.setGreeting("Hola"); + assert.strictEqual(await greeter.greet(), "Hola"); }); describe("with custom signer", function () { it("Should return an instance of a contract associated to a custom signer", async function () { const contract = await this.env.ethers.getContractAtFromArtifact( greeterArtifact, - deployedGreeter.address, + await deployedGreeter.getAddress(), signers[1] ); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signers[1].getAddress() ); }); @@ -997,16 +925,15 @@ describe("Ethers plugin", function () { }); async function assertContract( - contract: ethers.Contract, - signer: Signer + contract: EthersT.Contract, + signer: CustomEthersSigner ) { - assert.containsAllKeys(contract.interface.functions, [ - "setGreeting(string)", - "greet()", - ]); + assert.isNotNull(contract.interface.getFunction("greet")); + assert.isNotNull(contract.interface.getFunction("setGreeting")); + assertIsSigner(contract.runner); - assert.equal( - await contract.signer.getAddress(), + assert.strictEqual( + await contract.runner.getAddress(), await signer.getAddress() ); } @@ -1018,46 +945,45 @@ describe("Ethers plugin", function () { useEnvironment("hardhat-project", "hardhat"); describe("contract events", function () { - it("should be detected", async function () { - const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const deployedGreeter: ethers.Contract = await Greeter.deploy(); - - // at the time of this writing, ethers' default polling interval is - // 4000 ms. here we turn it down in order to speed up this test. - // see also - // https://github.com/ethers-io/ethers.js/issues/615#issuecomment-848991047 - const provider = deployedGreeter.provider as EthersProviderWrapper; - provider.pollingInterval = 200; - - let eventEmitted = false; - deployedGreeter.on("GreetingUpdated", () => { - eventEmitted = true; - }); - - await deployedGreeter.functions.setGreeting("Hola"); - - // wait for 1.5 polling intervals for the event to fire - await new Promise((resolve) => - setTimeout(resolve, provider.pollingInterval * 2) - ); - - assert.equal(eventEmitted, true); - }); + // TODO re-enable when we make .on("event") work + // it("should be detected", async function () { + // const Greeter = await this.env.ethers.getContractFactory("Greeter"); + // const deployedGreeter: any = await Greeter.deploy(); + // + // // at the time of this writing, ethers' default polling interval is + // // 4000 ms. here we turn it down in order to speed up this test. + // // see also + // // https://github.com/ethers-io/ethers.js/issues/615#issuecomment-848991047 + // // const provider = deployedGreeter.provider as EthersProviderWrapper; + // // provider.pollingInterval = 200; + // + // let eventEmitted = false; + // deployedGreeter.on("GreetingUpdated", () => { + // eventEmitted = true; + // }); + // + // await deployedGreeter.setGreeting("Hola"); + // + // // wait for 1.5 polling intervals for the event to fire + // await new Promise((resolve) => setTimeout(resolve, 200 * 2)); + // + // assert.strictEqual(eventEmitted, true); + // }); }); describe("hardhat_reset", function () { it("should return the correct block number after a hardhat_reset", async function () { let blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "0"); + assert.strictEqual(blockNumber.toString(), "0"); await this.env.ethers.provider.send("evm_mine", []); await this.env.ethers.provider.send("evm_mine", []); blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "2"); + assert.strictEqual(blockNumber.toString(), "2"); await this.env.ethers.provider.send("hardhat_reset", []); blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "0"); + assert.strictEqual(blockNumber.toString(), "0"); }); it("should return the correct block after a hardhat_reset", async function () { @@ -1083,21 +1009,21 @@ describe("Ethers plugin", function () { sig.address ); - assert.equal(nonce, 0); + assert.strictEqual(nonce, 0); const response = await sig.sendTransaction({ from: sig.address, - to: this.env.ethers.constants.AddressZero, + to: this.env.ethers.ZeroAddress, value: "0x1", }); await response.wait(); nonce = await this.env.ethers.provider.getTransactionCount(sig.address); - assert.equal(nonce, 1); + assert.strictEqual(nonce, 1); await this.env.ethers.provider.send("hardhat_reset", []); nonce = await this.env.ethers.provider.getTransactionCount(sig.address); - assert.equal(nonce, 0); + assert.strictEqual(nonce, 0); }); it("should return the correct balance after a hardhat_reset", async function () { @@ -1105,32 +1031,38 @@ describe("Ethers plugin", function () { let balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "10000000000000000000000"); + assert.strictEqual(balance.toString(), "10000000000000000000000"); const response = await sig.sendTransaction({ from: sig.address, - to: this.env.ethers.constants.AddressZero, + to: this.env.ethers.ZeroAddress, gasPrice: 8e9, }); await response.wait(); balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "9999999832000000000000"); + assert.strictEqual(balance.toString(), "9999999832000000000000"); await this.env.ethers.provider.send("hardhat_reset", []); balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "10000000000000000000000"); + assert.strictEqual(balance.toString(), "10000000000000000000000"); }); it("should return the correct code after a hardhat_reset", async function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); const response = await sig.sendTransaction(tx); const receipt = await response.wait(); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + if (receipt.contractAddress === null) { + assert.fail("receipt.contractAddress shoudn't be null"); + } let code = await this.env.ethers.provider.getCode( receipt.contractAddress @@ -1151,16 +1083,16 @@ describe("Ethers plugin", function () { [] ); let blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "0"); + assert.strictEqual(blockNumber.toString(), "0"); await this.env.ethers.provider.send("evm_mine", []); await this.env.ethers.provider.send("evm_mine", []); blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "2"); + assert.strictEqual(blockNumber.toString(), "2"); await this.env.ethers.provider.send("evm_revert", [snapshotId]); blockNumber = await this.env.ethers.provider.getBlockNumber(); - assert.equal(blockNumber.toString(), "0"); + assert.strictEqual(blockNumber.toString(), "0"); }); it("should return the correct block after a evm_revert", async function () { @@ -1194,21 +1126,21 @@ describe("Ethers plugin", function () { sig.address ); - assert.equal(nonce, 0); + assert.strictEqual(nonce, 0); const response = await sig.sendTransaction({ from: sig.address, - to: this.env.ethers.constants.AddressZero, + to: this.env.ethers.ZeroAddress, value: "0x1", }); await response.wait(); nonce = await this.env.ethers.provider.getTransactionCount(sig.address); - assert.equal(nonce, 1); + assert.strictEqual(nonce, 1); await this.env.ethers.provider.send("evm_revert", [snapshotId]); nonce = await this.env.ethers.provider.getTransactionCount(sig.address); - assert.equal(nonce, 0); + assert.strictEqual(nonce, 0); }); it("should return the correct balance after a evm_revert", async function () { @@ -1220,21 +1152,21 @@ describe("Ethers plugin", function () { let balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "10000000000000000000000"); + assert.strictEqual(balance.toString(), "10000000000000000000000"); const response = await sig.sendTransaction({ from: sig.address, - to: this.env.ethers.constants.AddressZero, + to: this.env.ethers.ZeroAddress, gasPrice: 8e9, }); await response.wait(); balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "9999999832000000000000"); + assert.strictEqual(balance.toString(), "9999999832000000000000"); await this.env.ethers.provider.send("evm_revert", [snapshotId]); balance = await this.env.ethers.provider.getBalance(sig.address); - assert.equal(balance.toString(), "10000000000000000000000"); + assert.strictEqual(balance.toString(), "10000000000000000000000"); }); it("should return the correct code after a evm_revert", async function () { @@ -1245,12 +1177,19 @@ describe("Ethers plugin", function () { const [sig] = await this.env.ethers.getSigners(); const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); const response = await sig.sendTransaction(tx); const receipt = await response.wait(); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + if (receipt.contractAddress === null) { + assert.fail("receipt.contractAddress shoudn't be null"); + } + let code = await this.env.ethers.provider.getCode( receipt.contractAddress ); @@ -1263,7 +1202,7 @@ describe("Ethers plugin", function () { }); }); - it("_signTypedData integration test", async function () { + it("signTypedData integration test", async function () { // See https://eips.ethereum.org/EIPS/eip-712#parameters // There's a json schema and an explanation for each field. const typedMessage = { @@ -1304,7 +1243,7 @@ describe("Ethers plugin", function () { }; const [signer] = await this.env.ethers.getSigners(); - const signature = await signer._signTypedData( + const signature = await signer.signTypedData( typedMessage.domain, typedMessage.types, typedMessage.message @@ -1316,28 +1255,30 @@ describe("Ethers plugin", function () { assert.lengthOf(signature, signatureSizeInBytes * byteToHex + hexPrefix); }); }); + describe("ganache via WebSocket", function () { useEnvironment("hardhat-project"); - it("should be able to detect events", async function () { - await this.env.run("compile", { quiet: true }); - - const Greeter = await this.env.ethers.getContractFactory("Greeter"); - const deployedGreeter: ethers.Contract = await Greeter.deploy(); - - const readonlyContract = deployedGreeter.connect( - new ethers.providers.WebSocketProvider("ws://127.0.0.1:8545") - ); - let emitted = false; - readonlyContract.on("GreetingUpdated", () => { - emitted = true; - }); - - await deployedGreeter.functions.setGreeting("Hola"); - - // wait for the event to fire - await new Promise((resolve) => setTimeout(resolve, 100)); - - assert.equal(emitted, true); - }); + // TODO re-enable when we make .on("event") work + // it("should be able to detect events", async function () { + // await this.env.run("compile", { quiet: true }); + // + // const Greeter = await this.env.ethers.getContractFactory("Greeter"); + // const deployedGreeter: any = await Greeter.deploy(); + // + // const readonlyContract = deployedGreeter.connect( + // new ethers.WebSocketProvider("ws://127.0.0.1:8545") + // ); + // let emitted = false; + // await readonlyContract.on("GreetingUpdated", () => { + // emitted = true; + // }); + // + // await deployedGreeter.setGreeting("Hola"); + // + // // wait for the event to fire + // await new Promise((resolve) => setTimeout(resolve, 100)); + // + // assert.strictEqual(emitted, true); + // }); }); }); diff --git a/packages/hardhat-ethers/test/no-accounts.ts b/packages/hardhat-ethers/test/no-accounts.ts index b068088a98..4f70fe468a 100644 --- a/packages/hardhat-ethers/test/no-accounts.ts +++ b/packages/hardhat-ethers/test/no-accounts.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { TASK_COMPILE } from "hardhat/builtin-tasks/task-names"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { SignerWithAddress } from "../src/signers"; +import { CustomEthersSigner } from "../src/signers"; import { useEnvironment } from "./helpers"; @@ -33,23 +33,36 @@ describe("hardhat-ethers plugin", function () { it("Should return an instance of a contract with a read-only provider", async function () { const receipt = await deployGreeter(this.env, signerAddress); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + if (receipt.contractAddress === null) { + assert.fail("receipt.contractAddress shoudn't be null"); + } + const contract = await this.env.ethers.getContractAt( "Greeter", receipt.contractAddress ); - assert.isDefined(contract.provider); - assert.isNotNull(contract.provider); + assert.isDefined(contract.runner); + assert.isNotNull(contract.runner); - const greeting = await contract.functions.greet(); + const greeting = await contract.greet(); - assert.equal(greeting, "Hi"); + assert.strictEqual(greeting, "Hi"); }); }); describe("with the abi and address", function () { it("Should return an instance of a contract with a read-only provider", async function () { const receipt = await deployGreeter(this.env, signerAddress); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + if (receipt.contractAddress === null) { + assert.fail("receipt.contractAddress shoudn't be null"); + } const signers = await this.env.ethers.getSigners(); assert.isEmpty(signers); @@ -63,12 +76,12 @@ describe("hardhat-ethers plugin", function () { receipt.contractAddress ); - assert.isDefined(contract.provider); - assert.isNotNull(contract.provider); + assert.isDefined(contract.runner); + assert.isNotNull(contract.runner); - const greeting = await contract.functions.greet(); + const greeting = await contract.greet(); - assert.equal(greeting, "Hi"); + assert.strictEqual(greeting, "Hi"); }); }); }); @@ -81,8 +94,8 @@ describe("hardhat-ethers plugin", function () { assert.isTrue(signers.every((aSigner) => aSigner.address !== address)); const signer = await this.env.ethers.getSigner(address); - assert.instanceOf(signer, SignerWithAddress); - assert.equal(signer.address, address); + assert.instanceOf(signer, CustomEthersSigner); + assert.strictEqual(signer.address, address); }); }); }); @@ -93,7 +106,7 @@ async function deployGreeter( signerAddress: string ) { const Greeter = await hre.ethers.getContractFactory("Greeter"); - const tx = Greeter.getDeployTransaction(); + const tx = await Greeter.getDeployTransaction(); tx.from = signerAddress; await hre.network.provider.request({ @@ -111,7 +124,10 @@ async function deployGreeter( }); assert.isDefined(hre.ethers.provider); const receipt = await hre.ethers.provider.getTransactionReceipt(txHash); - assert.equal(receipt.status, 1, "The deployment transaction failed."); + if (receipt === null) { + assert.fail("receipt shoudn't be null"); + } + assert.strictEqual(receipt.status, 1, "The deployment transaction failed."); return receipt; } diff --git a/packages/hardhat-ethers/test/updatable-target-proxy.ts b/packages/hardhat-ethers/test/updatable-target-proxy.ts deleted file mode 100644 index fac06e0e60..0000000000 --- a/packages/hardhat-ethers/test/updatable-target-proxy.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { assert } from "chai"; - -import { createUpdatableTargetProxy } from "../src/internal/updatable-target-proxy"; - -describe("updatable target proxy", function () { - it("should proxy properties", function () { - const o: any = { - a: 1, - getA() { - return this.a; - }, - b: {}, - getB() { - return this.b; - }, - }; - - const { proxy } = createUpdatableTargetProxy(o); - - assert.equal(proxy.a, 1); - assert.equal(proxy.getA(), 1); - assert.equal(proxy.b, o.b); - assert.equal(proxy.getB(), o.b); - }); - - it("should let set a new target", function () { - const o1: any = { - a: 1, - getA() { - return this.a; - }, - b: {}, - getB() { - return this.b; - }, - }; - - const o2: any = { - a: 2, - getA() { - return this.a; - }, - b: {}, - getB() { - return this.b; - }, - }; - - const { proxy, setTarget } = createUpdatableTargetProxy(o1); - - assert.equal(proxy.a, 1); - - setTarget(o2); - - assert.equal(proxy.a, 2); - assert.equal(proxy.getA(), 2); - assert.equal(proxy.b, o2.b); - assert.equal(proxy.getB(), o2.b); - }); - - it("shouldn't let you modify the proxied object", function () { - const o: any = { - a: 1, - }; - - const { proxy } = createUpdatableTargetProxy(o); - - assert.throws(() => { - proxy.a = 2; - }); - assert.throws(() => { - delete proxy.a; - }); - assert.throws(() => { - Object.defineProperty(proxy, "b", {}); - }); - assert.throws(() => { - Object.setPrototypeOf(proxy, {}); - }); - }); - - it("should let you call methods that modify the object", function () { - const o = { - a: 1, - inc() { - this.a++; - }, - }; - - const { proxy } = createUpdatableTargetProxy(o); - - assert.equal(proxy.a, 1); - proxy.inc(); - assert.equal(proxy.a, 2); - }); - - it("should trap getOwnPropertyDescriptor correctly", () => { - const o = { a: 1 }; - const { proxy, setTarget } = createUpdatableTargetProxy(o); - - assert.deepEqual(Object.getOwnPropertyDescriptor(proxy, "a"), { - value: 1, - writable: true, - enumerable: true, - configurable: true, - }); - - const o2 = { a: 2, b: 3 }; - setTarget(o2); - - assert.deepEqual(Object.getOwnPropertyDescriptor(proxy, "a"), { - value: 2, - writable: true, - enumerable: true, - configurable: true, - }); - assert.deepEqual(Object.getOwnPropertyDescriptor(proxy, "b"), { - value: 3, - writable: true, - enumerable: true, - configurable: true, - }); - }); - - it("should trap getPrototypeOf correctly", () => { - const proto = {}; - const o = Object.create(proto); - - const { proxy, setTarget } = createUpdatableTargetProxy(o); - - assert.equal(Object.getPrototypeOf(proxy), proto); - - const proto2 = {}; - const o2 = Object.create(proto2); - - setTarget(o2); - assert.equal(Object.getPrototypeOf(proxy), proto2); - }); - - it("should trap has correctly", () => { - const proto = { a: 1 }; - const o = Object.create(proto); - o.b = 2; - - const { proxy, setTarget } = createUpdatableTargetProxy(o); - - assert.isTrue("a" in proxy); - assert.isTrue("b" in proxy); - assert.isFalse("c" in proxy); - - const proto2 = { a: 2 }; - const o2 = Object.create(proto2); - o2.b = 4; - o2.c = 6; - - setTarget(o2); - assert.isTrue("a" in proxy); - assert.isTrue("b" in proxy); - assert.isTrue("c" in proxy); - assert.isFalse("d" in proxy); - }); - - it("should return isExtensible correctly", () => { - const o: any = {}; - Object.preventExtensions(o); - - const { proxy, setTarget } = createUpdatableTargetProxy(o); - - assert.isFalse(Object.isExtensible(proxy)); - - // if the proxy is initially not extensible, then it can't be made - // extensible afterwards - setTarget({}); - assert.isFalse(Object.isExtensible(proxy)); - }); - - it("should trap ownKeys correctly", () => { - const proto = { a: 1 }; - const o: any = Object.create(proto); - o.b = 1; - - const { proxy, setTarget } = createUpdatableTargetProxy(o); - assert.deepEqual(Object.getOwnPropertyNames(proxy), ["b"]); - - const proto2 = { c: 1 }; - const o2: any = Object.create(proto2); - o2.d = 1; - setTarget(o2); - assert.deepEqual(Object.getOwnPropertyNames(proxy), ["d"]); - }); - - it("should trap preventExtensions correctly", () => { - const o: any = {}; - - const { proxy } = createUpdatableTargetProxy(o); - assert.isTrue(Object.isExtensible(proxy)); - - Object.preventExtensions(proxy); - assert.isFalse(Object.isExtensible(proxy)); - }); -}); diff --git a/yarn.lock b/yarn.lock index 8f15159e61..636451fe90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" + integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" @@ -1010,6 +1015,11 @@ lodash "^4.17.16" uuid "^7.0.3" +"@noble/hashes@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" + integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" @@ -1175,6 +1185,17 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" +"@nomicfoundation/hardhat-chai-matchers@^1.0.0": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" + integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@types/chai-as-promised" "^7.1.3" + chai-as-promised "^7.1.1" + deep-eql "^4.0.1" + ordinal "^1.0.3" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" @@ -1241,6 +1262,11 @@ "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" +"@nomiclabs/hardhat-ethers@^2.0.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.2.tgz#812d48929c3bf8fe840ec29eab4b613693467679" + integrity sha512-NLDlDFL2us07C0jB/9wzvR0kuLivChJWCXTKcj3yqjZqMoYp7g7wwS157F70VHx/+9gHIBGzak5pKDwG8gEefA== + "@nomiclabs/hardhat-etherscan@^3.0.0": version "3.1.7" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz#72e3d5bd5d0ceb695e097a7f6f5ff6fcbf062b9a" @@ -2108,6 +2134,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.3.tgz#da2253f0ff03a0b3a9e445c8cbdf78e7fda7d48c" + integrity sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -4227,6 +4258,18 @@ ethers@^5.0.0, ethers@^5.0.13, ethers@^5.4.7, ethers@^5.7.1: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.1.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.2.3.tgz#9ddee438b5949e9724ba4c5d2c3b8deb5202ce96" + integrity sha512-l1Z/Yr+HrOk+7LTeYRHGMvYwVLGpTuVrT/kJ7Kagi3nekGISYILIby0f1ipV9BGzgERyy+w4emH+d3PhhcxIfA== + dependencies: + "@adraffy/ens-normalize" "1.9.0" + "@noble/hashes" "1.1.2" + "@noble/secp256k1" "1.7.1" + aes-js "4.0.0-beta.3" + tslib "2.4.0" + ws "8.5.0" + ethjs-abi@0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.1.8.tgz#cd288583ed628cdfadaf8adefa3ba1dbcbca6c18" @@ -8779,6 +8822,11 @@ tsconfig-paths@^3.10.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -9562,6 +9610,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" From e9949863810ed89ce1d2187d33723c1de937a761 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Mon, 15 May 2023 17:32:42 +0200 Subject: [PATCH 10/95] Create silly-ghosts-sing.md --- .changeset/silly-ghosts-sing.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/silly-ghosts-sing.md diff --git a/.changeset/silly-ghosts-sing.md b/.changeset/silly-ghosts-sing.md new file mode 100644 index 0000000000..4653a5dfc2 --- /dev/null +++ b/.changeset/silly-ghosts-sing.md @@ -0,0 +1,5 @@ +--- +"hardhat": patch +--- + +Added block numbers for all mainnet hardforks From 10e9c725fff719751e63c938828ae3c0018bdedc Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 19 May 2023 10:33:47 +0200 Subject: [PATCH 11/95] Rename CustomEthers* to HardhatEthers* --- .../src/dist/src/signer-with-address.ts | 2 +- ...provider.ts => hardhat-ethers-provider.ts} | 20 +++++----- .../hardhat-ethers/src/internal/helpers.ts | 10 ++--- packages/hardhat-ethers/src/internal/index.ts | 4 +- packages/hardhat-ethers/src/signers.ts | 20 +++++----- packages/hardhat-ethers/src/types/index.ts | 12 +++--- ...provider.ts => hardhat-ethers-provider.ts} | 2 +- ...ers-signer.ts => hardhat-ethers-signer.ts} | 2 +- packages/hardhat-ethers/test/index.ts | 38 +++++++++---------- packages/hardhat-ethers/test/no-accounts.ts | 4 +- 10 files changed, 57 insertions(+), 57 deletions(-) rename packages/hardhat-ethers/src/internal/{custom-ethers-provider.ts => hardhat-ethers-provider.ts} (96%) rename packages/hardhat-ethers/test/{custom-ethers-provider.ts => hardhat-ethers-provider.ts} (99%) rename packages/hardhat-ethers/test/{custom-ethers-signer.ts => hardhat-ethers-signer.ts} (99%) diff --git a/packages/hardhat-ethers/src/dist/src/signer-with-address.ts b/packages/hardhat-ethers/src/dist/src/signer-with-address.ts index dbdd5440d3..890a7a60b1 100644 --- a/packages/hardhat-ethers/src/dist/src/signer-with-address.ts +++ b/packages/hardhat-ethers/src/dist/src/signer-with-address.ts @@ -1 +1 @@ -export { CustomEthersSigner as SignerWithAddress } from "../../signers"; +export { HardhatEthersSigner as SignerWithAddress } from "../../signers"; diff --git a/packages/hardhat-ethers/src/internal/custom-ethers-provider.ts b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts similarity index 96% rename from packages/hardhat-ethers/src/internal/custom-ethers-provider.ts rename to packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts index c7f97b5b83..7181ffac94 100644 --- a/packages/hardhat-ethers/src/internal/custom-ethers-provider.ts +++ b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts @@ -29,7 +29,7 @@ import { toQuantity, } from "ethers"; import { EthereumProvider } from "hardhat/types"; -import { CustomEthersSigner } from "../signers"; +import { HardhatEthersSigner } from "../signers"; import { copyRequest, formatBlock, @@ -46,7 +46,7 @@ import { NotImplementedError, } from "./errors"; -export class CustomEthersProvider implements ethers.Provider { +export class HardhatEthersProvider implements ethers.Provider { constructor( private readonly _hardhatProvider: EthereumProvider, private readonly _networkName: string @@ -64,7 +64,7 @@ export class CustomEthersProvider implements ethers.Provider { public async getSigner( address?: number | string - ): Promise { + ): Promise { if (address === null || address === undefined) { address = 0; } @@ -77,11 +77,11 @@ export class CustomEthersProvider implements ethers.Provider { if (address >= accounts.length) { throw new AccountIndexOutOfRange(address, accounts.length); } - return CustomEthersSigner.create(this, accounts[address]); + return HardhatEthersSigner.create(this, accounts[address]); } if (typeof address === "string") { - return CustomEthersSigner.create(this, address); + return HardhatEthersSigner.create(this, address); } throw new HardhatEthersError(`Couldn't get account ${address as any}`); @@ -293,7 +293,7 @@ export class CustomEthersProvider implements ethers.Provider { } public async getTransactionResult(_hash: string): Promise { - throw new NotImplementedError("CustomEthersProvider.getTransactionResult"); + throw new NotImplementedError("HardhatEthersProvider.getTransactionResult"); } public async getLogs( @@ -309,11 +309,11 @@ export class CustomEthersProvider implements ethers.Provider { } public async resolveName(_ensName: string): Promise { - throw new NotImplementedError("CustomEthersProvider.resolveName"); + throw new NotImplementedError("HardhatEthersProvider.resolveName"); } public async lookupAddress(_address: string): Promise { - throw new NotImplementedError("CustomEthersProvider.lookupAddress"); + throw new NotImplementedError("HardhatEthersProvider.lookupAddress"); } public async waitForTransaction( @@ -321,13 +321,13 @@ export class CustomEthersProvider implements ethers.Provider { _confirms?: number | undefined, _timeout?: number | undefined ): Promise { - throw new NotImplementedError("CustomEthersProvider.waitForTransaction"); + throw new NotImplementedError("HardhatEthersProvider.waitForTransaction"); } public async waitForBlock( _blockTag?: BlockTag | undefined ): Promise { - throw new NotImplementedError("CustomEthersProvider.waitForBlock"); + throw new NotImplementedError("HardhatEthersProvider.waitForBlock"); } public async on(event: ProviderEvent, listener: Listener): Promise { diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index c622e333da..9b3296b9e5 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -1,5 +1,5 @@ import type { ethers as EthersT, BaseContract } from "ethers"; -import type { CustomEthersSigner } from "../signers"; +import type { HardhatEthersSigner } from "../signers"; import type { FactoryOptions, Libraries } from "../types"; import { Artifact, HardhatRuntimeEnvironment } from "hardhat/types"; @@ -35,7 +35,7 @@ function isArtifact(artifact: any): artifact is Artifact { export async function getSigners( hre: HardhatRuntimeEnvironment -): Promise { +): Promise { const accounts: string[] = await hre.ethers.provider.send("eth_accounts", []); const signersWithAddress = await Promise.all( @@ -48,8 +48,8 @@ export async function getSigners( export async function getSigner( hre: HardhatRuntimeEnvironment, address: string -): Promise { - const { CustomEthersSigner: SignerWithAddressImpl } = await import( +): Promise { + const { HardhatEthersSigner: SignerWithAddressImpl } = await import( "../signers" ); @@ -64,7 +64,7 @@ export async function getSigner( export async function getImpersonatedSigner( hre: HardhatRuntimeEnvironment, address: string -): Promise { +): Promise { await hre.ethers.provider.send("hardhat_impersonateAccount", [address]); return getSigner(hre, address); } diff --git a/packages/hardhat-ethers/src/internal/index.ts b/packages/hardhat-ethers/src/internal/index.ts index 12f4a0b7a3..9561f44ea6 100644 --- a/packages/hardhat-ethers/src/internal/index.ts +++ b/packages/hardhat-ethers/src/internal/index.ts @@ -3,7 +3,7 @@ import type EthersT from "ethers"; import { extendEnvironment } from "hardhat/config"; import { lazyObject } from "hardhat/plugins"; -import { CustomEthersProvider } from "./custom-ethers-provider"; +import { HardhatEthersProvider } from "./hardhat-ethers-provider"; import { getContractAt, getContractAtFromArtifact, @@ -20,7 +20,7 @@ extendEnvironment((hre) => { hre.ethers = lazyObject(() => { const { ethers } = require("ethers") as typeof EthersT; - const provider = new CustomEthersProvider( + const provider = new HardhatEthersProvider( hre.network.provider, hre.network.name ); diff --git a/packages/hardhat-ethers/src/signers.ts b/packages/hardhat-ethers/src/signers.ts index ebb068e8d4..2995cd16ed 100644 --- a/packages/hardhat-ethers/src/signers.ts +++ b/packages/hardhat-ethers/src/signers.ts @@ -9,7 +9,7 @@ import { TransactionLike, TypedDataEncoder, } from "ethers"; -import { CustomEthersProvider } from "./internal/custom-ethers-provider"; +import { HardhatEthersProvider } from "./internal/hardhat-ethers-provider"; import { copyRequest, getRpcTransaction, @@ -17,11 +17,11 @@ import { } from "./internal/ethers-utils"; import { HardhatEthersError, NotImplementedError } from "./internal/errors"; -export class CustomEthersSigner implements ethers.Signer { +export class HardhatEthersSigner implements ethers.Signer { public readonly address: string; - public readonly provider: ethers.JsonRpcProvider | CustomEthersProvider; + public readonly provider: ethers.JsonRpcProvider | HardhatEthersProvider; - public static async create(provider: CustomEthersProvider, address: string) { + public static async create(provider: HardhatEthersProvider, address: string) { const hre = await import("hardhat"); let gasLimit: number | undefined; if ( @@ -32,12 +32,12 @@ export class CustomEthersSigner implements ethers.Signer { gasLimit = hre.network.config.gas; } - return new CustomEthersSigner(address, provider, gasLimit); + return new HardhatEthersSigner(address, provider, gasLimit); } private constructor( address: string, - _provider: ethers.JsonRpcProvider | CustomEthersProvider, + _provider: ethers.JsonRpcProvider | HardhatEthersProvider, private readonly _gasLimit?: number ) { this.address = getAddress(address); @@ -45,9 +45,9 @@ export class CustomEthersSigner implements ethers.Signer { } public connect( - provider: ethers.JsonRpcProvider | CustomEthersProvider + provider: ethers.JsonRpcProvider | HardhatEthersProvider ): ethers.Signer { - return new CustomEthersSigner(this.address, provider); + return new HardhatEthersSigner(this.address, provider); } public getNonce(blockTag?: BlockTag | undefined): Promise { @@ -82,7 +82,7 @@ export class CustomEthersSigner implements ethers.Signer { // TODO if we split the signer for the in-process and json-rpc networks, // we can enable this method when using the in-process network or when the // json-rpc network has a private key - throw new NotImplementedError("CustomEthersSigner.signTransaction"); + throw new NotImplementedError("HardhatEthersSigner.signTransaction"); } public async sendTransaction( @@ -233,7 +233,7 @@ export class CustomEthersSigner implements ethers.Signer { } // exported as an alias to make migration easier -export { CustomEthersSigner as SignerWithAddress }; +export { HardhatEthersSigner as SignerWithAddress }; async function populate( signer: ethers.Signer, diff --git a/packages/hardhat-ethers/src/types/index.ts b/packages/hardhat-ethers/src/types/index.ts index 54100a372a..c8949e62e9 100644 --- a/packages/hardhat-ethers/src/types/index.ts +++ b/packages/hardhat-ethers/src/types/index.ts @@ -1,7 +1,7 @@ import type * as ethers from "ethers"; import type { Artifact } from "hardhat/types"; -import type { CustomEthersProvider } from "../internal/custom-ethers-provider"; -import type { CustomEthersSigner } from "../signers"; +import type { HardhatEthersProvider } from "../internal/hardhat-ethers-provider"; +import type { HardhatEthersSigner } from "../signers"; export interface Libraries { [libraryName: string]: string | ethers.Addressable; @@ -48,7 +48,7 @@ export declare function getContractFactoryFromArtifact< ): Promise>; export interface HardhatEthersHelpers { - provider: CustomEthersProvider; + provider: HardhatEthersProvider; getContractFactory: typeof getContractFactory; getContractFactoryFromArtifact: typeof getContractFactoryFromArtifact; @@ -62,8 +62,8 @@ export interface HardhatEthersHelpers { address: string, signer?: ethers.Signer ) => Promise; - getSigner: (address: string) => Promise; - getSigners: () => Promise; - getImpersonatedSigner: (address: string) => Promise; + getSigner: (address: string) => Promise; + getSigners: () => Promise; + getImpersonatedSigner: (address: string) => Promise; deployContract: typeof deployContract; } diff --git a/packages/hardhat-ethers/test/custom-ethers-provider.ts b/packages/hardhat-ethers/test/hardhat-ethers-provider.ts similarity index 99% rename from packages/hardhat-ethers/test/custom-ethers-provider.ts rename to packages/hardhat-ethers/test/hardhat-ethers-provider.ts index b315bd70ac..8f47ce1a76 100644 --- a/packages/hardhat-ethers/test/custom-ethers-provider.ts +++ b/packages/hardhat-ethers/test/hardhat-ethers-provider.ts @@ -10,7 +10,7 @@ import { use(chaiAsPromised); -describe("custom provider", function () { +describe("hardhat ethers provider", function () { usePersistentEnvironment("minimal-project"); it("can access itself through .provider", async function () { diff --git a/packages/hardhat-ethers/test/custom-ethers-signer.ts b/packages/hardhat-ethers/test/hardhat-ethers-signer.ts similarity index 99% rename from packages/hardhat-ethers/test/custom-ethers-signer.ts rename to packages/hardhat-ethers/test/hardhat-ethers-signer.ts index 2bb725b4df..9063586c99 100644 --- a/packages/hardhat-ethers/test/custom-ethers-signer.ts +++ b/packages/hardhat-ethers/test/hardhat-ethers-signer.ts @@ -7,7 +7,7 @@ import { usePersistentEnvironment, } from "./helpers"; -describe("custom signer", function () { +describe("hardhat ethers signer", function () { describe("minimal project", function () { usePersistentEnvironment("minimal-project"); diff --git a/packages/hardhat-ethers/test/index.ts b/packages/hardhat-ethers/test/index.ts index 4ae4bc9442..1b3683bb98 100644 --- a/packages/hardhat-ethers/test/index.ts +++ b/packages/hardhat-ethers/test/index.ts @@ -5,7 +5,7 @@ import { ethers } from "ethers"; import { NomicLabsHardhatPluginError } from "hardhat/plugins"; import { Artifact } from "hardhat/types"; -import { CustomEthersSigner } from "../src/signers"; +import { HardhatEthersSigner } from "../src/signers"; import { GreeterContract, TestContractLib } from "./example-contracts"; import { assertIsSigner, useEnvironment } from "./helpers"; @@ -44,7 +44,7 @@ describe("Ethers plugin", function () { }); describe("Signers and contracts helpers", function () { - let signers: CustomEthersSigner[]; + let signers: HardhatEthersSigner[]; let greeterArtifact: Artifact; let iGreeterArtifact: Artifact; @@ -454,8 +454,8 @@ describe("Ethers plugin", function () { assert.strictEqual(await greeter.greet(), "Hola"); }); - describe("with custom signer", function () { - it("should return a contract factory connected to the custom signer", async function () { + describe("with hardhat's signer", function () { + it("should return a contract factory connected to the hardhat's signer", async function () { // It's already compiled in artifacts/ const contract = await this.env.ethers.getContractFactory( "Greeter", @@ -519,8 +519,8 @@ describe("Ethers plugin", function () { assert.strictEqual(await greeter.greet(), "Hola"); }); - describe("with custom signer", function () { - it("should return a contract factory connected to the custom signer", async function () { + describe("with hardhat's signer", function () { + it("should return a contract factory connected to the hardhat's signer", async function () { // It's already compiled in artifacts/ const contract = await this.env.ethers.getContractFactory( greeterArtifact.abi, @@ -601,8 +601,8 @@ describe("Ethers plugin", function () { assert.strictEqual(await greeter.greet(), "Hola"); }); - describe("with custom signer", function () { - it("should return a contract factory connected to the custom signer", async function () { + describe("with hardhat's signer", function () { + it("should return a contract factory connected to the hardhat's signer", async function () { const contract = await this.env.ethers.getContractFactoryFromArtifact( greeterArtifact, @@ -681,8 +681,8 @@ describe("Ethers plugin", function () { assert.strictEqual(await greeter.greet(), "Hola"); }); - describe("with custom signer", function () { - it("Should return an instance of a contract associated to a custom signer", async function () { + describe("with hardhat's signer", function () { + it("Should return an instance of a contract associated to a hardhat's signer", async function () { const contract = await this.env.ethers.getContractAt( "Greeter", deployedGreeter.target, @@ -767,8 +767,8 @@ describe("Ethers plugin", function () { // assert.strictEqual(eventEmitted, true); // }); - describe("with custom signer", function () { - it("Should return an instance of a contract associated to a custom signer", async function () { + describe("with hardhat's signer", function () { + it("Should return an instance of a contract associated to a hardhat's signer", async function () { const contract = await this.env.ethers.getContractAt( greeterArtifact.abi, deployedGreeter.target, @@ -850,8 +850,8 @@ describe("Ethers plugin", function () { assert.strictEqual(await greeter.greet(), "Hola"); }); - describe("with custom signer", function () { - it("Should return an instance of a contract associated to a custom signer", async function () { + describe("with hardhat's signer", function () { + it("Should return an instance of a contract associated to a hardhat's signer", async function () { const contract = await this.env.ethers.getContractAtFromArtifact( greeterArtifact, await deployedGreeter.getAddress(), @@ -875,7 +875,7 @@ describe("Ethers plugin", function () { await assertContract(contract, signers[0]); }); - it("should deploy and return a contract with custom signer passed directly", async function () { + it("should deploy and return a contract with hardhat's signer passed directly", async function () { const contract = await this.env.ethers.deployContract( "Greeter", signers[1] @@ -884,7 +884,7 @@ describe("Ethers plugin", function () { await assertContract(contract, signers[1]); }); - it("should deploy and return a contract with custom signer passed as an option", async function () { + it("should deploy and return a contract with hardhat's signer passed as an option", async function () { const contract = await this.env.ethers.deployContract("Greeter", { signer: signers[1], }); @@ -902,7 +902,7 @@ describe("Ethers plugin", function () { assert(await contract.greet(), "Hello"); }); - it("should deploy with args and return a contract with custom signer", async function () { + it("should deploy with args and return a contract with hardhat's signer", async function () { const contract = await this.env.ethers.deployContract( "GreeterWithConstructorArg", ["Hello"], @@ -913,7 +913,7 @@ describe("Ethers plugin", function () { assert(await contract.greet(), "Hello"); }); - it("should deploy with args and return a contract with custom signer as an option", async function () { + it("should deploy with args and return a contract with hardhat's signer as an option", async function () { const contract = await this.env.ethers.deployContract( "GreeterWithConstructorArg", ["Hello"], @@ -926,7 +926,7 @@ describe("Ethers plugin", function () { async function assertContract( contract: EthersT.Contract, - signer: CustomEthersSigner + signer: HardhatEthersSigner ) { assert.isNotNull(contract.interface.getFunction("greet")); assert.isNotNull(contract.interface.getFunction("setGreeting")); diff --git a/packages/hardhat-ethers/test/no-accounts.ts b/packages/hardhat-ethers/test/no-accounts.ts index 4f70fe468a..067535626f 100644 --- a/packages/hardhat-ethers/test/no-accounts.ts +++ b/packages/hardhat-ethers/test/no-accounts.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { TASK_COMPILE } from "hardhat/builtin-tasks/task-names"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { CustomEthersSigner } from "../src/signers"; +import { HardhatEthersSigner } from "../src/signers"; import { useEnvironment } from "./helpers"; @@ -94,7 +94,7 @@ describe("hardhat-ethers plugin", function () { assert.isTrue(signers.every((aSigner) => aSigner.address !== address)); const signer = await this.env.ethers.getSigner(address); - assert.instanceOf(signer, CustomEthersSigner); + assert.instanceOf(signer, HardhatEthersSigner); assert.strictEqual(signer.address, address); }); }); From 952dc0e8df96235cf92b657383da24b767b4b6af Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 19 May 2023 10:40:55 +0200 Subject: [PATCH 12/95] Rename to @nomicfoundation/hardhat-ethers --- packages/hardhat-ethers/README.md | 10 +++++----- packages/hardhat-ethers/package.json | 8 ++++---- packages/hardhat-ethers/src/internal/errors.ts | 2 +- packages/hardhat-ethers/src/internal/helpers.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/hardhat-ethers/README.md b/packages/hardhat-ethers/README.md index 47ee313acc..e86c62c4b4 100644 --- a/packages/hardhat-ethers/README.md +++ b/packages/hardhat-ethers/README.md @@ -1,4 +1,4 @@ -[![npm](https://img.shields.io/npm/v/@nomiclabs/hardhat-ethers.svg)](https://www.npmjs.com/package/@nomiclabs/hardhat-ethers) [![hardhat](https://hardhat.org/buidler-plugin-badge.svg?1)](https://hardhat.org) +[![npm](https://img.shields.io/npm/v/@nomicfoundation/hardhat-ethers.svg)](https://www.npmjs.com/package/@nomicfoundation/hardhat-ethers) [![hardhat](https://hardhat.org/buidler-plugin-badge.svg?1)](https://hardhat.org) # hardhat-ethers @@ -11,19 +11,19 @@ This plugin brings to Hardhat the Ethereum library `ethers.js`, which allows you ## Installation ```bash -npm install --save-dev @nomiclabs/hardhat-ethers 'ethers@^5.0.0' +npm install --save-dev @nomicfoundation/hardhat-ethers 'ethers@^5.0.0' ``` And add the following statement to your `hardhat.config.js`: ```js -require("@nomiclabs/hardhat-ethers"); +require("@nomicfoundation/hardhat-ethers"); ``` Or, if you are using TypeScript, add this to your `hardhat.config.ts`: ```js -import "@nomiclabs/hardhat-ethers"; +import "@nomicfoundation/hardhat-ethers"; ``` ## Tasks @@ -90,7 +90,7 @@ There are no additional steps you need to take for this plugin to work. Install it and access ethers through the Hardhat Runtime Environment anywhere you need it (tasks, scripts, tests, etc). For example, in your `hardhat.config.js`: ```js -require("@nomiclabs/hardhat-ethers"); +require("@nomicfoundation/hardhat-ethers"); // task action function receives the Hardhat Runtime Environment as second argument task( diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index eb6b0dbad2..1277c4ef60 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -1,10 +1,10 @@ { - "name": "@nomiclabs/hardhat-ethers", + "name": "@nomicfoundation/hardhat-ethers", "version": "3.0.0", "description": "Hardhat plugin for ethers", - "homepage": "https://github.com/nomiclabs/hardhat/tree/main/packages/hardhat-ethers", - "repository": "github:nomiclabs/hardhat", - "author": "Nomic Labs LLC", + "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-ethers", + "repository": "github:nomicfoundation/hardhat", + "author": "Nomic Foundation", "license": "MIT", "main": "internal/index.js", "types": "internal/index.d.ts", diff --git a/packages/hardhat-ethers/src/internal/errors.ts b/packages/hardhat-ethers/src/internal/errors.ts index ce7f3a0233..1e4dc8a8cc 100644 --- a/packages/hardhat-ethers/src/internal/errors.ts +++ b/packages/hardhat-ethers/src/internal/errors.ts @@ -2,7 +2,7 @@ import { NomicLabsHardhatPluginError } from "hardhat/plugins"; export class HardhatEthersError extends NomicLabsHardhatPluginError { constructor(message: string, parent?: Error) { - super("@nomiclabs/hardhat-ethers", message, parent); + super("@nomicfoundation/hardhat-ethers", message, parent); } } diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index 9b3296b9e5..9cb63bcffd 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -272,7 +272,7 @@ Remove one of them and review your library links before proceeding.` `The contract ${artifact.contractName} is missing links for the following libraries: ${missingLibraries} -Learn more about linking contracts at https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers#library-linking +Learn more about linking contracts at https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-ethers#library-linking ` ); } From 084029f4ad7c5921bbe85dc8cb880cd1978bb9a0 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 19 May 2023 10:53:23 +0200 Subject: [PATCH 13/95] Respect gas config for all networks --- packages/hardhat-ethers/src/signers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/hardhat-ethers/src/signers.ts b/packages/hardhat-ethers/src/signers.ts index 2995cd16ed..452fe6fc9d 100644 --- a/packages/hardhat-ethers/src/signers.ts +++ b/packages/hardhat-ethers/src/signers.ts @@ -25,7 +25,6 @@ export class HardhatEthersSigner implements ethers.Signer { const hre = await import("hardhat"); let gasLimit: number | undefined; if ( - hre.network.name === "hardhat" && hre.network.config.gas !== "auto" && hre.network.config.gas !== undefined ) { From f0b8a72d364222f048cb9407eef057829ef2c6b5 Mon Sep 17 00:00:00 2001 From: Javier Donoso Date: Sat, 20 May 2023 17:44:20 +0200 Subject: [PATCH 14/95] gelato w3f plugin --- docs/src/content/hardhat-runner/plugins/plugins.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/content/hardhat-runner/plugins/plugins.ts b/docs/src/content/hardhat-runner/plugins/plugins.ts index 435cf481ea..774c14fcfe 100644 --- a/docs/src/content/hardhat-runner/plugins/plugins.ts +++ b/docs/src/content/hardhat-runner/plugins/plugins.ts @@ -773,6 +773,14 @@ const communityPlugins: IPlugin[] = [ "Enable project-specific features inside Truffle Dashboard, including advanced calldata decoding and more", tags: ["truffle-dashboard", "transaction", "signing", "decoding"], }, + { + name: "hardhat-w3f", + author: "Gelato Network", + npmPackage: "@gelatonetwork/web3-functions-sdk/hardhat-plugin", + authorUrl: "https://github.com/gelatodigital/web3-functions-sdk", + description: "Thie hardhat-w3f plugin allows builders to build & run Web3 Functions connecting smart off-chain data with smart contracts ", + tags: ["Gelato", "w3f", "offchain","functions"], + }, ]; const officialPlugins: IPlugin[] = [ From a28d5c2d111789133ac2e77f5e9ba74db5e08073 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Mon, 22 May 2023 11:15:47 +0200 Subject: [PATCH 15/95] Test hh-ethers with hh node instead of ganache --- .../empty-hardhat-project/hardhat.config.js | 3 + packages/common/run-with-hardhat.js | 79 +++++++++++++++++++ packages/hardhat-chai-matchers/README.md | 4 +- packages/hardhat-chai-matchers/package.json | 4 +- packages/hardhat-chai-matchers/src/index.ts | 2 +- .../test/changeEtherBalance.ts | 6 +- .../test/changeEtherBalances.ts | 6 +- .../test/changeTokenBalance.ts | 8 +- .../hardhat-project/hardhat.config.js | 2 +- .../hardhat-chai-matchers/test/helpers.ts | 2 +- packages/hardhat-ethers/.mocharc.json | 2 +- packages/hardhat-ethers/test/index.ts | 70 +++++++++------- 12 files changed, 141 insertions(+), 47 deletions(-) create mode 100644 packages/common/empty-hardhat-project/hardhat.config.js create mode 100644 packages/common/run-with-hardhat.js diff --git a/packages/common/empty-hardhat-project/hardhat.config.js b/packages/common/empty-hardhat-project/hardhat.config.js new file mode 100644 index 0000000000..aa3527a6b0 --- /dev/null +++ b/packages/common/empty-hardhat-project/hardhat.config.js @@ -0,0 +1,3 @@ +module.exports = { + solidity: "0.8.19", +}; diff --git a/packages/common/run-with-hardhat.js b/packages/common/run-with-hardhat.js new file mode 100644 index 0000000000..dcdf3b4b6f --- /dev/null +++ b/packages/common/run-with-hardhat.js @@ -0,0 +1,79 @@ +const { fork } = require("child_process"); +const path = require("path"); +let hardhatNodeProcess; + +/** + * Ensure hardhat node is running, for tests that require it. + */ +before(async () => { + console.log("\n### Starting hardhat node instance ###"); + + const pathToCli = path.resolve( + __dirname, + "..", + "hardhat-core", + "internal", + "cli", + "cli" + ); + const pathToEmptyProject = path.resolve(__dirname, "empty-hardhat-project"); + + hardhatNodeProcess = fork(pathToCli, ["node"], { + cwd: pathToEmptyProject, + env: { HARDHAT_EXPERIMENTAL_ALLOW_NON_LOCAL_INSTALLATION: "true" }, + stdio: "pipe", + }); + + return new Promise((resolve, reject) => { + let stdout = ""; + let stderr = ""; + + hardhatNodeProcess.stdout.on("data", (data) => { + stdout += data.toString(); + if ( + data + .toString() + .includes("Started HTTP and WebSocket JSON-RPC server at") + ) { + resolve(); + } + }); + + hardhatNodeProcess.stderr.on("data", (data) => { + stderr += data.toString(); + }); + + const buildErrorMessage = () => { + return `There was a problem running hardhat node. + +stdout: +${stdout} + +stderr: +${stderr}`; + }; + + hardhatNodeProcess.on("error", () => { + reject(new Error(buildErrorMessage())); + }); + + hardhatNodeProcess.on("exit", (statusCode) => { + if (statusCode === 0) { + return; + } + + reject(new Error(buildErrorMessage())); + }); + }); +}); + +/** + * Cleanup the process running hardhat node + */ +after(async () => { + if (hardhatNodeProcess === undefined) { + return; + } + hardhatNodeProcess.kill(); + console.log("\n### Stopped hardhat node instance ###"); +}); diff --git a/packages/hardhat-chai-matchers/README.md b/packages/hardhat-chai-matchers/README.md index 2cbf130d8d..59e6d1a0d8 100644 --- a/packages/hardhat-chai-matchers/README.md +++ b/packages/hardhat-chai-matchers/README.md @@ -17,13 +17,13 @@ npm install --save-dev @nomicfoundation/hardhat-chai-matchers If you are using an older version of npm, you'll also need to install all the packages used by the plugin. ```bash -npm install --save-dev @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers +npm install --save-dev @nomicfoundation/hardhat-chai-matchers chai @nomicfoundation/hardhat-ethers ethers ``` That's also the case if you are using yarn: ```bash -yarn add --dev @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers +yarn add --dev @nomicfoundation/hardhat-chai-matchers chai @nomicfoundation/hardhat-ethers ethers ``` ### Usage diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index 6427bd7ddc..7bc0a965b6 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -37,7 +37,7 @@ "README.md" ], "devDependencies": { - "@nomiclabs/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", "@types/bn.js": "^5.1.0", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", @@ -62,7 +62,7 @@ "typescript": "~4.7.4" }, "peerDependencies": { - "@nomiclabs/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", "chai": "^4.2.0", "ethers": "^6.1.0", "hardhat": "^2.9.4" diff --git a/packages/hardhat-chai-matchers/src/index.ts b/packages/hardhat-chai-matchers/src/index.ts index 658ffa8acd..d5fa986711 100644 --- a/packages/hardhat-chai-matchers/src/index.ts +++ b/packages/hardhat-chai-matchers/src/index.ts @@ -1,4 +1,4 @@ -import "@nomiclabs/hardhat-ethers"; +import "@nomicfoundation/hardhat-ethers"; import "./types"; diff --git a/packages/hardhat-chai-matchers/test/changeEtherBalance.ts b/packages/hardhat-chai-matchers/test/changeEtherBalance.ts index 9c2647ff48..c2c7adf932 100644 --- a/packages/hardhat-chai-matchers/test/changeEtherBalance.ts +++ b/packages/hardhat-chai-matchers/test/changeEtherBalance.ts @@ -1,4 +1,4 @@ -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { expect, AssertionError } from "chai"; import path from "path"; import util from "util"; @@ -23,8 +23,8 @@ describe("INTEGRATION: changeEtherBalance matcher", function () { }); function runTests() { - let sender: SignerWithAddress; - let receiver: SignerWithAddress; + let sender: HardhatEthersSigner; + let receiver: HardhatEthersSigner; let contract: ChangeEtherBalance; let txGasFees: number; diff --git a/packages/hardhat-chai-matchers/test/changeEtherBalances.ts b/packages/hardhat-chai-matchers/test/changeEtherBalances.ts index b88e48fead..dd06d39e2a 100644 --- a/packages/hardhat-chai-matchers/test/changeEtherBalances.ts +++ b/packages/hardhat-chai-matchers/test/changeEtherBalances.ts @@ -1,4 +1,4 @@ -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { expect, AssertionError } from "chai"; import path from "path"; import util from "util"; @@ -22,8 +22,8 @@ describe("INTEGRATION: changeEtherBalances matcher", function () { }); function runTests() { - let sender: SignerWithAddress; - let receiver: SignerWithAddress; + let sender: HardhatEthersSigner; + let receiver: HardhatEthersSigner; let contract: ChangeEtherBalance; let txGasFees: number; diff --git a/packages/hardhat-chai-matchers/test/changeTokenBalance.ts b/packages/hardhat-chai-matchers/test/changeTokenBalance.ts index 51fc3088f4..cecbf91c4e 100644 --- a/packages/hardhat-chai-matchers/test/changeTokenBalance.ts +++ b/packages/hardhat-chai-matchers/test/changeTokenBalance.ts @@ -1,7 +1,7 @@ import type { TransactionResponse } from "ethers"; import assert from "assert"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { AssertionError, expect } from "chai"; import path from "path"; import util from "util"; @@ -32,8 +32,8 @@ describe("INTEGRATION: changeTokenBalance and changeTokenBalances matchers", fun }); function runTests() { - let sender: SignerWithAddress; - let receiver: SignerWithAddress; + let sender: HardhatEthersSigner; + let receiver: HardhatEthersSigner; let mockToken: Token; let matchers: MatchersContract; @@ -642,7 +642,7 @@ async function runAllAsserts( | (() => TransactionResponse) | (() => Promise), token: Token, - accounts: Array, + accounts: Array, balances: Array ) { // changeTokenBalances works for the given arrays diff --git a/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js b/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js index 10d1d15ed6..d8edfc19ae 100644 --- a/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js +++ b/packages/hardhat-chai-matchers/test/fixture-projects/hardhat-project/hardhat.config.js @@ -1,4 +1,4 @@ -require("@nomiclabs/hardhat-ethers"); +require("@nomicfoundation/hardhat-ethers"); module.exports = { solidity: "0.8.4", diff --git a/packages/hardhat-chai-matchers/test/helpers.ts b/packages/hardhat-chai-matchers/test/helpers.ts index de2dc7e889..dd8485522e 100644 --- a/packages/hardhat-chai-matchers/test/helpers.ts +++ b/packages/hardhat-chai-matchers/test/helpers.ts @@ -6,7 +6,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import path from "path"; // we assume that all the fixture projects use the hardhat-ethers plugin -import "@nomiclabs/hardhat-ethers/internal/type-extensions"; +import "@nomicfoundation/hardhat-ethers/internal/type-extensions"; declare module "mocha" { interface Context { diff --git a/packages/hardhat-ethers/.mocharc.json b/packages/hardhat-ethers/.mocharc.json index 775e35460d..4cc970a890 100644 --- a/packages/hardhat-ethers/.mocharc.json +++ b/packages/hardhat-ethers/.mocharc.json @@ -1,6 +1,6 @@ { "require": "ts-node/register/files", - "file": "../common/run-with-ganache", + "file": "../common/run-with-hardhat", "ignore": ["test/fixture-projects/**/*"], "timeout": 10000 } diff --git a/packages/hardhat-ethers/test/index.ts b/packages/hardhat-ethers/test/index.ts index 1b3683bb98..a5b9e2fc9b 100644 --- a/packages/hardhat-ethers/test/index.ts +++ b/packages/hardhat-ethers/test/index.ts @@ -8,12 +8,12 @@ import { Artifact } from "hardhat/types"; import { HardhatEthersSigner } from "../src/signers"; import { GreeterContract, TestContractLib } from "./example-contracts"; -import { assertIsSigner, useEnvironment } from "./helpers"; +import { assertIsNotNull, assertIsSigner, useEnvironment } from "./helpers"; chai.use(chaiAsPromised); describe("Ethers plugin", function () { - describe("ganache", function () { + describe("hardhat node", function () { useEnvironment("hardhat-project", "localhost"); describe("HRE extensions", function () { @@ -38,7 +38,7 @@ describe("Ethers plugin", function () { ); assert.strictEqual( accounts[0], - "0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1" + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" ); }); }); @@ -61,7 +61,7 @@ describe("Ethers plugin", function () { const sigs = await this.env.ethers.getSigners(); assert.strictEqual( await sigs[0].getAddress(), - "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ); }); @@ -69,38 +69,46 @@ describe("Ethers plugin", function () { const sigs = await this.env.ethers.getSigners(); assert.strictEqual( sigs[0].address, - "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ); }); }); describe("getImpersonatedSigner", function () { - it("should invoke hardhat_impersonateAccount", async function () { + it("should return the working impersonated signer", async function () { + const [signer] = await this.env.ethers.getSigners(); const address = `0x${"ff".repeat(20)}`; - // TODO: We are testing this plugin against Ganache, so this fails. - // We should test it using Hardhat Network instead. - await assert.isRejected( - this.env.ethers.getImpersonatedSigner(address), - "Method hardhat_impersonateAccount not supported" + const impersonatedSigner = + await this.env.ethers.getImpersonatedSigner(address); + + assert.strictEqual( + impersonatedSigner.address, + "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF" ); + + // fund impersonated account + await signer.sendTransaction({ + to: impersonatedSigner, + value: 10n ** 18n, + }); + + // send a tx from impersonated account + await impersonatedSigner.sendTransaction({ + to: this.env.ethers.ZeroAddress, + value: 10n ** 17n, + }); }); - it("should return the working impersonated signer", async function () {}); }); describe("signer", function () { - /** - * this test has been skipped pending the removal of ganache from this - * test suite, which is being tracked at - * https://github.com/NomicFoundation/hardhat/issues/3447 - */ - it.skip("should sign a message", async function () { + it("should sign a message", async function () { const [sig] = await this.env.ethers.getSigners(); const result = await sig.signMessage("hello"); assert.strictEqual( result, - "0x1845faa75f53acb0c3e7247dcf294ce045c139722418dc9638709b54bafffa093591aeaaa195e7dc53f7e774c80e9a7f1371f0647a100d1c9e81db83d8ddd47801" + "0xf16ea9a3478698f695fd1401bfe27e9e4a7e8e3da94aa72b021125e31fa899cc573c48ea3fe1d4ab61a9db10c19032026e3ed2dbccba5a178235ac27f94504311c" ); }); @@ -125,17 +133,19 @@ describe("Ethers plugin", function () { }); it("should return the balance of the account", async function () { - const [sig] = await this.env.ethers.getSigners(); + // we use the second signer because the first one is used in previous tests + const [, secondSigner] = await this.env.ethers.getSigners(); assert.strictEqual( - await this.env.ethers.provider.getBalance(sig), - 100000000000000000000n + await this.env.ethers.provider.getBalance(secondSigner), + 10_000n * 10n ** 18n ); }); it("should return the transaction count of the account", async function () { - const [sig] = await this.env.ethers.getSigners(); + // we use the second signer because the first one is used in previous tests + const [, secondSigner] = await this.env.ethers.getSigners(); assert.strictEqual( - await this.env.ethers.provider.getTransactionCount(sig), + await this.env.ethers.provider.getTransactionCount(secondSigner), 0 ); }); @@ -181,13 +191,15 @@ describe("Ethers plugin", function () { it("should get the chainId", async function () { const { chainId } = await this.env.ethers.provider.getNetwork(); - assert.strictEqual(chainId, 1337n); + assert.strictEqual(chainId, 31337n); }); it("should get the gas price", async function () { - const feeData = await this.env.ethers.provider.getFeeData(); + const feeData: EthersT.FeeData = + await this.env.ethers.provider.getFeeData(); - assert.strictEqual(feeData.gasPrice, 20000000000n); + assertIsNotNull(feeData.gasPrice); + assert.isTrue(feeData.gasPrice > 0); }); it("should populate a transaction", async function () { @@ -1256,8 +1268,8 @@ describe("Ethers plugin", function () { }); }); - describe("ganache via WebSocket", function () { - useEnvironment("hardhat-project"); + describe("hardhat node via WebSocket", function () { + useEnvironment("hardhat-project", "localhost"); // TODO re-enable when we make .on("event") work // it("should be able to detect events", async function () { // await this.env.run("compile", { quiet: true }); From fa839f8db7ef33ede3662148de8c444aea8284d6 Mon Sep 17 00:00:00 2001 From: Javier Donoso Date: Tue, 23 May 2023 20:19:10 +0200 Subject: [PATCH 16/95] prettier --- docs/src/content/hardhat-runner/plugins/plugins.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/content/hardhat-runner/plugins/plugins.ts b/docs/src/content/hardhat-runner/plugins/plugins.ts index 774c14fcfe..02498836cf 100644 --- a/docs/src/content/hardhat-runner/plugins/plugins.ts +++ b/docs/src/content/hardhat-runner/plugins/plugins.ts @@ -778,8 +778,9 @@ const communityPlugins: IPlugin[] = [ author: "Gelato Network", npmPackage: "@gelatonetwork/web3-functions-sdk/hardhat-plugin", authorUrl: "https://github.com/gelatodigital/web3-functions-sdk", - description: "Thie hardhat-w3f plugin allows builders to build & run Web3 Functions connecting smart off-chain data with smart contracts ", - tags: ["Gelato", "w3f", "offchain","functions"], + description: + "Thie hardhat-w3f plugin allows builders to build & run Web3 Functions connecting smart off-chain data with smart contracts ", + tags: ["Gelato", "w3f", "offchain", "functions"], }, ]; From e87000ca4019e19b1bda851e515d06f388ef873f Mon Sep 17 00:00:00 2001 From: Javier Donoso Date: Tue, 23 May 2023 20:33:49 +0200 Subject: [PATCH 17/95] link --- docs/src/content/hardhat-runner/plugins/plugins.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/hardhat-runner/plugins/plugins.ts b/docs/src/content/hardhat-runner/plugins/plugins.ts index 02498836cf..63373b11ad 100644 --- a/docs/src/content/hardhat-runner/plugins/plugins.ts +++ b/docs/src/content/hardhat-runner/plugins/plugins.ts @@ -776,10 +776,10 @@ const communityPlugins: IPlugin[] = [ { name: "hardhat-w3f", author: "Gelato Network", - npmPackage: "@gelatonetwork/web3-functions-sdk/hardhat-plugin", + npmPackage: "@gelatonetwork/web3-functions-sdk", authorUrl: "https://github.com/gelatodigital/web3-functions-sdk", description: - "Thie hardhat-w3f plugin allows builders to build & run Web3 Functions connecting smart off-chain data with smart contracts ", + "The hardhat-w3f plugin allows builders to build & run Web3 Functions connecting smart off-chain data with smart contracts ", tags: ["Gelato", "w3f", "offchain", "functions"], }, ]; From b087d0ff2511dec90bdb9f5276fc2483007fb8b7 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 24 May 2023 12:19:34 +0200 Subject: [PATCH 18/95] Respect gas value in hardhat config --- packages/hardhat-ethers/.prettierignore | 1 + packages/hardhat-ethers/package.json | 1 + packages/hardhat-ethers/src/signers.ts | 41 ++++- packages/hardhat-ethers/test/environment.ts | 165 ++++++++++++++++++ .../test/fixture-projects/.gitignore | 1 + packages/hardhat-ethers/test/gas-config.ts | 143 +++++++++++++++ .../test/hardhat-ethers-provider.ts | 7 +- .../test/hardhat-ethers-signer.ts | 7 +- packages/hardhat-ethers/test/helpers.ts | 44 ----- packages/hardhat-ethers/test/index.ts | 5 +- packages/hardhat-ethers/test/no-accounts.ts | 2 +- 11 files changed, 355 insertions(+), 62 deletions(-) create mode 100644 packages/hardhat-ethers/test/environment.ts create mode 100644 packages/hardhat-ethers/test/fixture-projects/.gitignore create mode 100644 packages/hardhat-ethers/test/gas-config.ts diff --git a/packages/hardhat-ethers/.prettierignore b/packages/hardhat-ethers/.prettierignore index c66ddcfc8a..b78ac2c14d 100644 --- a/packages/hardhat-ethers/.prettierignore +++ b/packages/hardhat-ethers/.prettierignore @@ -9,4 +9,5 @@ /build-test /test/fixture-projects/**/artifacts /test/fixture-projects/**/cache +/test/fixture-projects/generated-fixtures CHANGELOG.md diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index 1277c4ef60..6065867680 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -46,6 +46,7 @@ "@typescript-eslint/parser": "5.53.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", + "chalk": "^2.4.2", "eslint": "^7.29.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-import": "2.24.1", diff --git a/packages/hardhat-ethers/src/signers.ts b/packages/hardhat-ethers/src/signers.ts index 452fe6fc9d..1986358fab 100644 --- a/packages/hardhat-ethers/src/signers.ts +++ b/packages/hardhat-ethers/src/signers.ts @@ -23,12 +23,43 @@ export class HardhatEthersSigner implements ethers.Signer { public static async create(provider: HardhatEthersProvider, address: string) { const hre = await import("hardhat"); + + // depending on the config, we set a fixed gas limit for all transactions let gasLimit: number | undefined; - if ( - hre.network.config.gas !== "auto" && - hre.network.config.gas !== undefined - ) { - gasLimit = hre.network.config.gas; + + if (hre.network.name === "hardhat") { + // If we are connected to the in-process hardhat network and the config + // has a fixed number as the gas config, we use that. + // Hardhat core already sets this value to the block gas limit when the + // user doesn't specify a number. + if (hre.network.config.gas !== "auto") { + gasLimit = hre.network.config.gas; + } + } else if (hre.network.name === "localhost") { + const configuredGasLimit = hre.config.networks.localhost.gas; + + if (configuredGasLimit !== "auto") { + // if the resolved gas config is a number, we use that + gasLimit = configuredGasLimit; + } else { + // if the resolved gas config is "auto", we need to check that + // the user config is undefined, because that's the default value; + // otherwise explicitly setting the gas to "auto" would have no effect + if (hre.userConfig.networks?.localhost?.gas === undefined) { + // finally, we check if we are connected to a hardhat network + let isHardhatNetwork = false; + try { + await hre.network.provider.send("hardhat_metadata"); + isHardhatNetwork = true; + } catch {} + + if (isHardhatNetwork) { + // WARNING: this assumes that the hardhat node is being run in the + // same project which might be wrong + gasLimit = hre.config.networks.hardhat.blockGasLimit; + } + } + } } return new HardhatEthersSigner(address, provider, gasLimit); diff --git a/packages/hardhat-ethers/test/environment.ts b/packages/hardhat-ethers/test/environment.ts new file mode 100644 index 0000000000..7e5c760d56 --- /dev/null +++ b/packages/hardhat-ethers/test/environment.ts @@ -0,0 +1,165 @@ +import chalk from "chalk"; +import fs from "fs"; +import { HardhatRuntimeEnvironment, HardhatUserConfig } from "hardhat/types"; +import { resetHardhatContext } from "hardhat/plugins-testing"; +import path from "path"; + +// Import this plugin type extensions for the HardhatRuntimeEnvironment +import "../src/internal/type-extensions"; + +declare module "mocha" { + interface Context { + env: HardhatRuntimeEnvironment; + } +} + +/** + * Start a new Hardhat environment for each test + */ +export function useEnvironment( + fixtureProjectName: string, + networkName = "hardhat" +) { + const fixtureProjectPath = path.resolve( + __dirname, + "fixture-projects", + fixtureProjectName + ); + + beforeEach("Loading hardhat environment", function () { + process.chdir(fixtureProjectPath); + process.env.HARDHAT_NETWORK = networkName; + + this.env = require("hardhat"); + }); + + afterEach("Resetting hardhat", function () { + resetHardhatContext(); + }); + + afterEach(function () { + if (this.currentTest?.state === "failed") { + console.log(chalk.red("Failed in fixture project", fixtureProjectPath)); + } + }); +} + +/** + * Like useEnvironment, but re-use the environment for the whole suite + */ +export function usePersistentEnvironment( + fixtureProjectName: string, + networkName = "hardhat" +) { + const fixtureProjectPath = path.resolve( + __dirname, + "fixture-projects", + fixtureProjectName + ); + + before("Loading hardhat environment", function () { + process.chdir(fixtureProjectPath); + process.env.HARDHAT_NETWORK = networkName; + + this.env = require("hardhat"); + }); + + after("Resetting hardhat", function () { + resetHardhatContext(); + }); + + afterEach(function () { + if (this.currentTest?.state === "failed") { + console.log(chalk.red("Failed in fixture project", fixtureProjectPath)); + } + }); +} + +/** + * Generate a fixture project on runtime with the given parameters, + * and start a persistent environment in that project. + */ +export function useGeneratedEnvironment( + hardhatGasLimit: "default" | "auto" | number, + localhostGasLimit: "default" | "auto" | number, + networkName: "hardhat" | "localhost" +) { + const fixtureProjectPath = path.resolve( + __dirname, + "fixture-projects", + "generated-fixtures", + `hardhat-gas-${hardhatGasLimit}-localhost-gas-${localhostGasLimit}` + ); + + before("Loading hardhat environment", function () { + // remove the directory if it exists and create an empty one + try { + fs.unlinkSync(fixtureProjectPath); + } catch {} + fs.mkdirSync(fixtureProjectPath, { recursive: true }); + + // generate and write the hardhat config + const hardhatConfigPath = path.resolve( + fixtureProjectPath, + "hardhat.config.js" + ); + + const hardhatConfig: HardhatUserConfig = { + solidity: "0.8.19", + networks: { + hardhat: {}, + localhost: {}, + }, + }; + if (hardhatGasLimit !== "default") { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + hardhatConfig.networks!.hardhat!.gas = hardhatGasLimit; + } + if (localhostGasLimit !== "default") { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + hardhatConfig.networks!.localhost!.gas = localhostGasLimit; + } + + fs.writeFileSync( + hardhatConfigPath, + ` +require("../../../../src/internal/index"); + +module.exports = ${JSON.stringify(hardhatConfig, null, 2)} +` + ); + + // generate and write the contracts + fs.mkdirSync(path.resolve(fixtureProjectPath, "contracts"), { + recursive: true, + }); + + fs.writeFileSync( + path.resolve(fixtureProjectPath, "contracts", "Example.sol"), + ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Example { + function f() public {} +} +` + ); + + // start the environment + process.chdir(fixtureProjectPath); + process.env.HARDHAT_NETWORK = networkName; + + this.env = require("hardhat"); + }); + + after("Resetting hardhat", function () { + resetHardhatContext(); + }); + + afterEach(function () { + if (this.currentTest?.state === "failed") { + console.log(chalk.red("Failed in fixture project", fixtureProjectPath)); + } + }); +} diff --git a/packages/hardhat-ethers/test/fixture-projects/.gitignore b/packages/hardhat-ethers/test/fixture-projects/.gitignore new file mode 100644 index 0000000000..4366b69da9 --- /dev/null +++ b/packages/hardhat-ethers/test/fixture-projects/.gitignore @@ -0,0 +1 @@ +generated-fixtures diff --git a/packages/hardhat-ethers/test/gas-config.ts b/packages/hardhat-ethers/test/gas-config.ts new file mode 100644 index 0000000000..13af3010cf --- /dev/null +++ b/packages/hardhat-ethers/test/gas-config.ts @@ -0,0 +1,143 @@ +import { assert, use } from "chai"; +import chaiAsPromised from "chai-as-promised"; + +import { useGeneratedEnvironment } from "./environment"; + +use(chaiAsPromised); + +// This test suite generates different gas configuration +// combinations and runs some common tests for all of them. + +type GasLimitValue = "default" | "auto" | number; +type ConnectedNetwork = "hardhat" | "localhost"; + +interface Combination { + hardhatGasLimit: GasLimitValue; + localhostGasLimit: GasLimitValue; + connectedNetwork: ConnectedNetwork; +} + +function generateCombinations(): Combination[] { + const result: Combination[] = []; + + const hardhatGasLimitValues: GasLimitValue[] = ["default", "auto", 1_000_000]; + const localhostGasLimitValues: GasLimitValue[] = [ + "default", + "auto", + 1_000_000, + ]; + const connectedNetworkValues: ConnectedNetwork[] = ["hardhat", "localhost"]; + + for (const hardhatGasLimit of hardhatGasLimitValues) { + for (const localhostGasLimit of localhostGasLimitValues) { + for (const connectedNetwork of connectedNetworkValues) { + result.push({ + hardhatGasLimit, + localhostGasLimit, + connectedNetwork, + }); + } + } + } + + return result; +} + +describe("gas config behavior", function () { + for (const { + hardhatGasLimit, + localhostGasLimit, + connectedNetwork, + } of generateCombinations()) { + describe(`hardhat gas limit: ${hardhatGasLimit} | localhostGasLimit: ${localhostGasLimit} | connectedNetwork: ${connectedNetwork}`, function () { + useGeneratedEnvironment( + hardhatGasLimit, + localhostGasLimit, + connectedNetwork + ); + + // for some combinations there will be a default gas limit that is used + // when no explicit gas limit is set by the user; in those cases, we + // assert that the tx indeed uses that gas limit; if not, then + // the result of an estimateGas call should be used + let defaultGasLimit: bigint | undefined; + if ( + (connectedNetwork === "hardhat" && hardhatGasLimit === 1_000_000) || + (connectedNetwork === "localhost" && localhostGasLimit === 1_000_000) + ) { + defaultGasLimit = 1_000_000n; + } else if ( + (connectedNetwork === "hardhat" && hardhatGasLimit === "default") || + (connectedNetwork === "localhost" && localhostGasLimit === "default") + ) { + // expect the block gas limit to be used as the default gas limit + defaultGasLimit = 30_000_000n; + } + + it("plain transaction, default gas limit", async function () { + const expectedGasLimit = defaultGasLimit ?? 21_001n; + + const [signer] = await this.env.ethers.getSigners(); + const tx = await signer.sendTransaction({ + to: signer, + }); + + assert.strictEqual(tx.gasLimit, expectedGasLimit); + }); + + it("plain transaction, explicit gas limit", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const tx = await signer.sendTransaction({ + to: signer, + gasLimit: 500_000, + }); + + assert.strictEqual(tx.gasLimit, 500_000n); + }); + + it("contract deployment, default gas limit", async function () { + const expectedGasLimit = defaultGasLimit ?? 76_985n; + + await this.env.run("compile", { quiet: true }); + const example: any = await this.env.ethers.deployContract("Example"); + const deploymentTx = await example.deploymentTransaction(); + + assert.strictEqual(deploymentTx.gasLimit, expectedGasLimit); + }); + + it("contract deployment, explicit gas limit", async function () { + await this.env.run("compile", { quiet: true }); + const Example: any = await this.env.ethers.getContractFactory( + "Example" + ); + const example = await Example.deploy({ + gasLimit: 500_000, + }); + const deploymentTx = await example.deploymentTransaction(); + + assert.strictEqual(deploymentTx.gasLimit, 500_000n); + }); + + it("contract call, default gas limit", async function () { + const expectedGasLimit = defaultGasLimit ?? 21_186n; + + await this.env.run("compile", { quiet: true }); + const example: any = await this.env.ethers.deployContract("Example"); + const tx = await example.f(); + + assert.strictEqual(tx.gasLimit, expectedGasLimit); + }); + + it("contract call, explicit gas limit", async function () { + await this.env.run("compile", { quiet: true }); + const example: any = await this.env.ethers.deployContract("Example"); + const tx = await example.f({ + gasLimit: 500_000, + }); + + assert.strictEqual(tx.gasLimit, 500_000n); + }); + }); + } +}); diff --git a/packages/hardhat-ethers/test/hardhat-ethers-provider.ts b/packages/hardhat-ethers/test/hardhat-ethers-provider.ts index 8f47ce1a76..3faa40eaba 100644 --- a/packages/hardhat-ethers/test/hardhat-ethers-provider.ts +++ b/packages/hardhat-ethers/test/hardhat-ethers-provider.ts @@ -2,11 +2,8 @@ import { assert, use } from "chai"; import chaiAsPromised from "chai-as-promised"; import { ExampleContract, EXAMPLE_CONTRACT } from "./example-contracts"; -import { - assertIsNotNull, - assertWithin, - usePersistentEnvironment, -} from "./helpers"; +import { usePersistentEnvironment } from "./environment"; +import { assertIsNotNull, assertWithin } from "./helpers"; use(chaiAsPromised); diff --git a/packages/hardhat-ethers/test/hardhat-ethers-signer.ts b/packages/hardhat-ethers/test/hardhat-ethers-signer.ts index 9063586c99..10ca35870b 100644 --- a/packages/hardhat-ethers/test/hardhat-ethers-signer.ts +++ b/packages/hardhat-ethers/test/hardhat-ethers-signer.ts @@ -1,11 +1,8 @@ import { assert } from "chai"; +import { usePersistentEnvironment } from "./environment"; import { ExampleContract, EXAMPLE_CONTRACT } from "./example-contracts"; -import { - assertIsNotNull, - assertWithin, - usePersistentEnvironment, -} from "./helpers"; +import { assertIsNotNull, assertWithin } from "./helpers"; describe("hardhat ethers signer", function () { describe("minimal project", function () { diff --git a/packages/hardhat-ethers/test/helpers.ts b/packages/hardhat-ethers/test/helpers.ts index 318ad7e5b6..e705afc866 100644 --- a/packages/hardhat-ethers/test/helpers.ts +++ b/packages/hardhat-ethers/test/helpers.ts @@ -1,49 +1,5 @@ import { assert } from "chai"; import { ContractRunner, Signer } from "ethers"; -import { resetHardhatContext } from "hardhat/plugins-testing"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import path from "path"; - -// Import this plugin type extensions for the HardhatRuntimeEnvironment -import "../src/internal/type-extensions"; - -declare module "mocha" { - interface Context { - env: HardhatRuntimeEnvironment; - } -} - -export function useEnvironment( - fixtureProjectName: string, - networkName = "hardhat" -) { - beforeEach("Loading hardhat environment", function () { - process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName)); - process.env.HARDHAT_NETWORK = networkName; - - this.env = require("hardhat"); - }); - - afterEach("Resetting hardhat", function () { - resetHardhatContext(); - }); -} - -export function usePersistentEnvironment( - fixtureProjectName: string, - networkName = "hardhat" -) { - before("Loading hardhat environment", function () { - process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName)); - process.env.HARDHAT_NETWORK = networkName; - - this.env = require("hardhat"); - }); - - after("Resetting hardhat", function () { - resetHardhatContext(); - }); -} export function assertWithin( value: number | bigint, diff --git a/packages/hardhat-ethers/test/index.ts b/packages/hardhat-ethers/test/index.ts index a5b9e2fc9b..102aea5055 100644 --- a/packages/hardhat-ethers/test/index.ts +++ b/packages/hardhat-ethers/test/index.ts @@ -6,9 +6,10 @@ import { NomicLabsHardhatPluginError } from "hardhat/plugins"; import { Artifact } from "hardhat/types"; import { HardhatEthersSigner } from "../src/signers"; -import { GreeterContract, TestContractLib } from "./example-contracts"; -import { assertIsNotNull, assertIsSigner, useEnvironment } from "./helpers"; +import { useEnvironment } from "./environment"; +import { GreeterContract, TestContractLib } from "./example-contracts"; +import { assertIsNotNull, assertIsSigner } from "./helpers"; chai.use(chaiAsPromised); diff --git a/packages/hardhat-ethers/test/no-accounts.ts b/packages/hardhat-ethers/test/no-accounts.ts index 067535626f..4a7f8657a3 100644 --- a/packages/hardhat-ethers/test/no-accounts.ts +++ b/packages/hardhat-ethers/test/no-accounts.ts @@ -4,7 +4,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { HardhatEthersSigner } from "../src/signers"; -import { useEnvironment } from "./helpers"; +import { useEnvironment } from "./environment"; describe("hardhat-ethers plugin", function () { describe("hardhat network with no accounts", function () { From cb33dacccd0ac5d626e1e4fe1f78602815be4b8d Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 25 May 2023 10:20:44 +0200 Subject: [PATCH 19/95] Add tests for gas price behavior --- packages/hardhat-ethers/test/gas-price.ts | 184 ++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 packages/hardhat-ethers/test/gas-price.ts diff --git a/packages/hardhat-ethers/test/gas-price.ts b/packages/hardhat-ethers/test/gas-price.ts new file mode 100644 index 0000000000..6fb5ca44d9 --- /dev/null +++ b/packages/hardhat-ethers/test/gas-price.ts @@ -0,0 +1,184 @@ +import { assert, use } from "chai"; +import chaiAsPromised from "chai-as-promised"; + +import { useEnvironment } from "./environment"; + +use(chaiAsPromised); + +describe("gas price overrides", function () { + describe("in-process hardhat network", function () { + useEnvironment("hardhat-project", "hardhat"); + + runTests(); + }); + + describe("hardhat node", function () { + useEnvironment("hardhat-project", "localhost"); + + runTests(); + }); +}); + +function runTests() { + describe("plain transactions", function () { + it("should use the given gas price if specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const tx = await signer.sendTransaction({ + to: signer, + gasPrice: this.env.ethers.parseUnits("10", "gwei"), + }); + + const receipt = await tx.wait(); + + assert.strictEqual(tx.gasPrice, 10n * 10n ** 9n); + assert.strictEqual(receipt?.gasPrice, 10n * 10n ** 9n); + }); + + it("should use EIP-1559 values if maxFeePerGas and maxPriorityFeePerGas are specified, maxFeePerGas = baseFeePerGas", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const baseFeePerGas = this.env.ethers.parseUnits("10", "gwei"); + const maxFeePerGas = baseFeePerGas; + const maxPriorityFeePerGas = this.env.ethers.parseUnits("1", "gwei"); + + await this.env.network.provider.send( + "hardhat_setNextBlockBaseFeePerGas", + [`0x${baseFeePerGas.toString(16)}`] + ); + + const tx = await signer.sendTransaction({ + to: signer, + maxFeePerGas, + maxPriorityFeePerGas, + }); + + const receipt = await tx.wait(); + + assert.strictEqual(tx.maxFeePerGas, maxFeePerGas); + assert.strictEqual(tx.maxPriorityFeePerGas, maxPriorityFeePerGas); + assert.strictEqual(receipt?.gasPrice, maxFeePerGas); + }); + + it("should use EIP-1559 values if maxFeePerGas and maxPriorityFeePerGas are specified, maxFeePerGas > baseFeePerGas", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const baseFeePerGas = this.env.ethers.parseUnits("5", "gwei"); + const maxFeePerGas = this.env.ethers.parseUnits("10", "gwei"); + const maxPriorityFeePerGas = this.env.ethers.parseUnits("1", "gwei"); + + await this.env.network.provider.send( + "hardhat_setNextBlockBaseFeePerGas", + [`0x${baseFeePerGas.toString(16)}`] + ); + + const tx = await signer.sendTransaction({ + to: signer, + maxFeePerGas, + maxPriorityFeePerGas, + }); + + const receipt = await tx.wait(); + + assert.strictEqual(tx.maxFeePerGas, maxFeePerGas); + assert.strictEqual(tx.maxPriorityFeePerGas, maxPriorityFeePerGas); + assert.strictEqual( + receipt?.gasPrice, + baseFeePerGas + maxPriorityFeePerGas + ); + }); + + it("should use a default gas price if no value is specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + // we don't run any assertions here because the strategy + // used to set the default gas prices might change; we + // just check that the transaction is mined correctly + const tx = await signer.sendTransaction({ + to: signer, + }); + + await tx.wait(); + }); + + it("should use a default value for maxPriorityFeePerGas if maxFeePerGas is the only value specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const baseFeePerGas = this.env.ethers.parseUnits("5", "gwei"); + const maxFeePerGas = this.env.ethers.parseUnits("10", "gwei"); + + // make sure that the max fee is enough + await this.env.network.provider.send( + "hardhat_setNextBlockBaseFeePerGas", + [`0x${baseFeePerGas.toString(16)}`] + ); + + const tx = await signer.sendTransaction({ + to: signer, + maxFeePerGas, + }); + + // we just check that the EIP-1559 values are set, because the + // strategy to select a default priority fee might change + assert.exists(tx.maxFeePerGas); + assert.exists(tx.maxPriorityFeePerGas); + }); + + it("should use a default maxFeePerGas if only maxPriorityFeePerGas is specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + const maxPriorityFeePerGas = this.env.ethers.parseUnits("1", "gwei"); + + const tx = await signer.sendTransaction({ + to: signer, + maxPriorityFeePerGas, + }); + + // we just check that the max fee is set, because the + // strategy to select its value might change + assert.exists(tx.maxFeePerGas); + + assert.strictEqual(tx.maxPriorityFeePerGas, maxPriorityFeePerGas); + }); + + it("should throw if both gasPrice and maxFeePerGas are specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + await assert.isRejected( + signer.sendTransaction({ + to: signer, + gasPrice: this.env.ethers.parseUnits("10", "gwei"), + maxFeePerGas: this.env.ethers.parseUnits("10", "gwei"), + }), + "Cannot send both gasPrice and maxFeePerGas params" + ); + }); + + it("should throw if both gasPrice and maxPriorityFeePerGas are specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + await assert.isRejected( + signer.sendTransaction({ + to: signer, + gasPrice: this.env.ethers.parseUnits("10", "gwei"), + maxPriorityFeePerGas: this.env.ethers.parseUnits("10", "gwei"), + }), + "Cannot send both gasPrice and maxPriorityFeePerGas" + ); + }); + + it("should throw if gasPrice, maxFeePerGas and maxPriorityFeePerGas are specified", async function () { + const [signer] = await this.env.ethers.getSigners(); + + await assert.isRejected( + signer.sendTransaction({ + to: signer, + gasPrice: this.env.ethers.parseUnits("10", "gwei"), + maxFeePerGas: this.env.ethers.parseUnits("10", "gwei"), + maxPriorityFeePerGas: this.env.ethers.parseUnits("10", "gwei"), + }), + "Cannot send both gasPrice and maxFeePerGas" + ); + }); + }); +} From 008e95ee0290f27756e09e53fcd6a4ffe036fa87 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 11:40:49 +0200 Subject: [PATCH 20/95] Use ethers.Contract instead of ethers.BaseContract --- .../hardhat-ethers/src/internal/helpers.ts | 18 ++++++++++++------ packages/hardhat-ethers/src/types/index.ts | 6 +++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index 9cb63bcffd..5bc2a74006 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -1,4 +1,4 @@ -import type { ethers as EthersT, BaseContract } from "ethers"; +import type { ethers as EthersT } from "ethers"; import type { HardhatEthersSigner } from "../signers"; import type { FactoryOptions, Libraries } from "../types"; @@ -69,13 +69,19 @@ export async function getImpersonatedSigner( return getSigner(hre, address); } -export function getContractFactory( +export function getContractFactory< + A extends any[] = any[], + I = EthersT.Contract +>( hre: HardhatRuntimeEnvironment, name: string, signerOrOptions?: EthersT.Signer | FactoryOptions ): Promise>; -export function getContractFactory( +export function getContractFactory< + A extends any[] = any[], + I = EthersT.Contract +>( hre: HardhatRuntimeEnvironment, abi: any[], bytecode: EthersT.BytesLike, @@ -84,7 +90,7 @@ export function getContractFactory( export async function getContractFactory< A extends any[] = any[], - I = BaseContract + I = EthersT.Contract >( hre: HardhatRuntimeEnvironment, nameOrAbi: string | any[], @@ -123,7 +129,7 @@ function isFactoryOptions( export async function getContractFactoryFromArtifact< A extends any[] = any[], - I = BaseContract + I = EthersT.Contract >( hre: HardhatRuntimeEnvironment, artifact: Artifact, @@ -282,7 +288,7 @@ Learn more about linking contracts at https://hardhat.org/hardhat-runner/plugins async function getContractFactoryByAbiAndBytecode< A extends any[] = any[], - I = BaseContract + I = EthersT.Contract >( hre: HardhatRuntimeEnvironment, abi: any[], diff --git a/packages/hardhat-ethers/src/types/index.ts b/packages/hardhat-ethers/src/types/index.ts index c8949e62e9..7176df2fc4 100644 --- a/packages/hardhat-ethers/src/types/index.ts +++ b/packages/hardhat-ethers/src/types/index.ts @@ -14,14 +14,14 @@ export interface FactoryOptions { export declare function getContractFactory< A extends any[] = any[], - I = ethers.BaseContract + I = ethers.Contract >( name: string, signerOrOptions?: ethers.Signer | FactoryOptions ): Promise>; export declare function getContractFactory< A extends any[] = any[], - I = ethers.BaseContract + I = ethers.Contract >( abi: any[], bytecode: ethers.BytesLike, @@ -41,7 +41,7 @@ export declare function deployContract( export declare function getContractFactoryFromArtifact< A extends any[] = any[], - I = ethers.BaseContract + I = ethers.Contract >( artifact: Artifact, signerOrOptions?: ethers.Signer | FactoryOptions From e920f516c13cc1971a595dfde7bbebb867d35668 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 11:41:57 +0200 Subject: [PATCH 21/95] Revert chai matchers version change Changesets should do this --- packages/hardhat-chai-matchers/package.json | 2 +- yarn.lock | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index 7bc0a965b6..e4849e3d33 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-chai-matchers", - "version": "2.0.0", + "version": "1.0.6", "description": "Hardhat utils for testing", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-chai-matchers", "repository": "github:nomicfoundation/hardhat", diff --git a/yarn.lock b/yarn.lock index 636451fe90..d6a0fa9f34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1185,17 +1185,6 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-chai-matchers@^1.0.0": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" - integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@types/chai-as-promised" "^7.1.3" - chai-as-promised "^7.1.1" - deep-eql "^4.0.1" - ordinal "^1.0.3" - "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" From b088bbb7253c90d01c44f61ca8427c5206d62740 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 12:04:44 +0200 Subject: [PATCH 22/95] Use explicit versions for ethers and hh-chai-matchers --- .../hardhat-chai-matchers/docs/migrate-from-waffle.md | 6 +++--- docs/src/content/hardhat-chai-matchers/docs/overview.md | 6 +++--- .../src/content/hardhat-runner/docs/advanced/create-task.md | 4 ++-- .../docs/guides/migrating-from-hardhat-waffle.md | 4 ++-- .../hardhat-runner/docs/other-guides/waffle-testing.md | 4 ++-- docs/src/content/tutorial/creating-a-new-hardhat-project.md | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md b/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md index 485704db0d..f3980f1341 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md +++ b/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md @@ -43,7 +43,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value="npm 7+"} ``` - npm install --save-dev @nomicfoundation/hardhat-chai-matchers + npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: @@ -51,7 +51,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value="npm 6"} ``` - npm install --save-dev @nomicfoundation/hardhat-chai-matchers + npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: @@ -59,7 +59,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value=yarn} ``` - yarn add --dev @nomicfoundation/hardhat-chai-matchers + yarn add --dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: diff --git a/docs/src/content/hardhat-chai-matchers/docs/overview.md b/docs/src/content/hardhat-chai-matchers/docs/overview.md index a61f57b0c8..ed284fd6b7 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/overview.md +++ b/docs/src/content/hardhat-chai-matchers/docs/overview.md @@ -16,7 +16,7 @@ Among other things, you can assert that a contract fired certain events, or that :::tab{value="npm 7+"} ``` -npm install --save-dev @nomicfoundation/hardhat-chai-matchers +npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: @@ -24,7 +24,7 @@ npm install --save-dev @nomicfoundation/hardhat-chai-matchers :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-chai-matchers +npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: @@ -32,7 +32,7 @@ npm install --save-dev @nomicfoundation/hardhat-chai-matchers :::tab{value=yarn} ``` -yarn add --dev @nomicfoundation/hardhat-chai-matchers +yarn add --dev @nomicfoundation/hardhat-chai-matchers@1 ``` ::: diff --git a/docs/src/content/hardhat-runner/docs/advanced/create-task.md b/docs/src/content/hardhat-runner/docs/advanced/create-task.md index 33c7972df1..37aeaf4bdb 100644 --- a/docs/src/content/hardhat-runner/docs/advanced/create-task.md +++ b/docs/src/content/hardhat-runner/docs/advanced/create-task.md @@ -63,7 +63,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: @@ -71,7 +71,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat :::tab{value="yarn"} ``` -yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: diff --git a/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md b/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md index 5d2a12c130..7abec2e16c 100644 --- a/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md +++ b/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md @@ -55,7 +55,7 @@ Follow these steps to migrate your project to Hardhat Toolbox. :::tab{value="npm 6"} ``` - npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers + npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: @@ -63,7 +63,7 @@ Follow these steps to migrate your project to Hardhat Toolbox. :::tab{value="yarn"} ``` - yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers + yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: diff --git a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md index 1c8521bd04..ada090eb40 100644 --- a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md +++ b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md @@ -59,7 +59,7 @@ npm install --save-dev chai @nomiclabs/hardhat-waffle :::tab{value="npm 6"} ``` -npm install --save-dev chai @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers ethers +npm install --save-dev chai @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers ethers@5 ``` ::: @@ -67,7 +67,7 @@ npm install --save-dev chai @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs :::tab{value="yarn"} ``` -yarn add --dev chai @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers ethers +yarn add --dev chai @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers ethers@5 ``` ::: diff --git a/docs/src/content/tutorial/creating-a-new-hardhat-project.md b/docs/src/content/tutorial/creating-a-new-hardhat-project.md index 8f6d0d39a5..b5323742c5 100644 --- a/docs/src/content/tutorial/creating-a-new-hardhat-project.md +++ b/docs/src/content/tutorial/creating-a-new-hardhat-project.md @@ -142,7 +142,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: @@ -150,7 +150,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat :::tab{value=yarn} ``` -yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers ``` ::: From 523235b83ae5bf111db8e65871a953278e3e5ee9 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 12:07:31 +0200 Subject: [PATCH 23/95] Create yellow-suits-fail.md --- .changeset/yellow-suits-fail.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/yellow-suits-fail.md diff --git a/.changeset/yellow-suits-fail.md b/.changeset/yellow-suits-fail.md new file mode 100644 index 0000000000..9ccb3035cf --- /dev/null +++ b/.changeset/yellow-suits-fail.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-chai-matchers": major +--- + +Added support for ethers v6 From 3c916ea14572999a70f4feb3a02bea70e991e760 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 12:42:57 +0200 Subject: [PATCH 24/95] Update ethers devDep in core --- packages/hardhat-core/package.json | 2 +- .../helpers/ethers-provider-wrapper.ts | 34 ------------------- .../provider/modules/eth/methods/subscribe.ts | 4 +-- .../provider/modules/eth/websocket.ts | 12 +++---- .../provider/modules/hardhat.ts | 6 ++-- .../internal/hardhat-network/provider/node.ts | 2 +- 6 files changed, 12 insertions(+), 48 deletions(-) delete mode 100644 packages/hardhat-core/test/internal/hardhat-network/helpers/ethers-provider-wrapper.ts diff --git a/packages/hardhat-core/package.json b/packages/hardhat-core/package.json index b60fde820a..cbf427ca46 100644 --- a/packages/hardhat-core/package.json +++ b/packages/hardhat-core/package.json @@ -87,7 +87,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^5.0.0", + "ethers": "^6.1.0", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-core/test/internal/hardhat-network/helpers/ethers-provider-wrapper.ts b/packages/hardhat-core/test/internal/hardhat-network/helpers/ethers-provider-wrapper.ts deleted file mode 100644 index 3a5740cf25..0000000000 --- a/packages/hardhat-core/test/internal/hardhat-network/helpers/ethers-provider-wrapper.ts +++ /dev/null @@ -1,34 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { ethers } from "ethers"; - -import { EthereumProvider } from "../../../../src/types"; - -// This class has been copied from @nomiclabs/hardhat-ethers package to avoid circular dependency - -export class EthersProviderWrapper extends ethers.providers.JsonRpcProvider { - private readonly _hardhatProvider: EthereumProvider; - - constructor(hardhatProvider: EthereumProvider) { - super(); - this._hardhatProvider = hardhatProvider; - } - - public async send(method: string, params: any): Promise { - const result = await this._hardhatProvider.send(method, params); - - // We replicate ethers' behavior. - this.emit("debug", { - action: "send", - request: { - id: 42, - jsonrpc: "2.0", - method, - params, - }, - response: result, - provider: this, - }); - - return result; - } -} diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/subscribe.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/subscribe.ts index 18e60ca840..a6c1e1ce81 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/subscribe.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/methods/subscribe.ts @@ -182,12 +182,12 @@ describe("Eth module", function () { DEFAULT_ACCOUNTS_ADDRESSES[0] ); - const abiEncoder = new ethers.utils.Interface(contractA.abi); + const abiEncoder = new ethers.Interface(contractA.abi); const filterId = await this.provider.send("eth_subscribe", [ "logs", { address, - topic: abiEncoder.getEventTopic("TokensMinted"), + topic: abiEncoder.getEvent("TokensMinted")?.topicHash, }, ]); diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/websocket.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/websocket.ts index f3db1e7613..ef3de84d18 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/websocket.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth/websocket.ts @@ -342,14 +342,12 @@ describe("Eth module", function () { }); describe("ethers.WebSocketProvider", function () { - let provider: ethers.providers.WebSocketProvider; + let provider: ethers.WebSocketProvider; beforeEach(async function () { if (this.serverInfo !== undefined) { const { address, port } = this.serverInfo; - provider = new ethers.providers.WebSocketProvider( - `ws://${address}:${port}` - ); + provider = new ethers.WebSocketProvider(`ws://${address}:${port}`); } else { this.skip(); } @@ -375,7 +373,7 @@ describe("Eth module", function () { ); await sleep(100); - const signer = provider.getSigner(); + const signer = await provider.getSigner(); await signer.sendTransaction({ to: await signer.getAddress(), }); @@ -384,8 +382,8 @@ describe("Eth module", function () { }); it("contract events work", async function () { - const signer = provider.getSigner(); - const Factory = new ethers.ContractFactory( + const signer = await provider.getSigner(); + const Factory = new ethers.ContractFactory<[], ethers.Contract>( EXAMPLE_CONTRACT.abi, EXAMPLE_CONTRACT.bytecode, signer diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts index 5e63e06746..bd24a7de1b 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/modules/hardhat.ts @@ -1701,7 +1701,7 @@ describe("Hardhat module", function () { describe("hardhat_setCode", function () { let contractNine: CompilerOutputContract; - let abiEncoder: ethers.utils.Interface; + let abiEncoder: ethers.Interface; before(async function () { [ , @@ -1715,7 +1715,7 @@ describe("Hardhat module", function () { function returnNine() public pure returns (int) { return 9; } } `); - abiEncoder = new ethers.utils.Interface(contractNine.abi); + abiEncoder = new ethers.Interface(contractNine.abi); }); it("should reject an invalid address", async function () { @@ -2182,7 +2182,7 @@ describe("Hardhat module", function () { ]); // Assert: Verify that the contract retrieves the modified value. - const abiEncoder = new ethers.utils.Interface(storageContract.abi); + const abiEncoder = new ethers.Interface(storageContract.abi); assert.equal( await this.provider.send("eth_call", [ { diff --git a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts index 9a59f18583..430721e182 100644 --- a/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts +++ b/packages/hardhat-core/test/internal/hardhat-network/provider/node.ts @@ -845,7 +845,7 @@ describe("HardhatNode", () => { block: bigint, targetNode: HardhatNode ): Promise { - const contractInterface = new ethers.utils.Interface([ + const contractInterface = new ethers.Interface([ "function Hello() public pure returns (string)", ]); From dcb9677277f6cefeb3bd2c7cdd8db2acc208b57c Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 12:43:37 +0200 Subject: [PATCH 25/95] Use aliased ethers for v5 This is both for making the check-dependencies script pass and to make it more explicit that the BigNumber support in the helpers is for ethers v5. --- packages/hardhat-core/package.json | 1 + packages/hardhat-core/src/common/bigInt.ts | 2 +- packages/hardhat-network-helpers/package.json | 2 +- .../test/helpers/getStorageAt.ts | 2 +- .../test/helpers/mine.ts | 2 +- .../test/helpers/mineUpTo.ts | 2 +- .../test/helpers/setBalance.ts | 2 +- .../test/helpers/setBlockGasLimit.ts | 2 +- .../test/helpers/setNextBlockBaseFeePerGas.ts | 2 +- .../test/helpers/setNonce.ts | 2 +- .../test/helpers/setPrevRandao.ts | 2 +- .../test/helpers/setStorageAt.ts | 2 +- .../test/helpers/time/advanceBlock.ts | 2 +- .../test/helpers/time/advanceBlockTo.ts | 2 +- .../test/helpers/time/increase.ts | 2 +- .../test/helpers/time/increaseTo.ts | 2 +- yarn.lock | 36 +++++++++++++++++++ 17 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/hardhat-core/package.json b/packages/hardhat-core/package.json index cbf427ca46..104267605f 100644 --- a/packages/hardhat-core/package.json +++ b/packages/hardhat-core/package.json @@ -88,6 +88,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^6.1.0", + "ethers-v5": "npm:ethers@5", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-core/src/common/bigInt.ts b/packages/hardhat-core/src/common/bigInt.ts index 95cd0958af..5546a488bd 100644 --- a/packages/hardhat-core/src/common/bigInt.ts +++ b/packages/hardhat-core/src/common/bigInt.ts @@ -1,4 +1,4 @@ -import type { BigNumber as EthersBigNumberType } from "ethers"; +import type { BigNumber as EthersBigNumberType } from "ethers-v5"; // eslint-disable-next-line import/no-extraneous-dependencies import type { BigNumber as BigNumberJsType } from "bignumber.js"; // eslint-disable-next-line import/no-extraneous-dependencies diff --git a/packages/hardhat-network-helpers/package.json b/packages/hardhat-network-helpers/package.json index 18d28fe319..6aaac35109 100644 --- a/packages/hardhat-network-helpers/package.json +++ b/packages/hardhat-network-helpers/package.json @@ -52,7 +52,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^5.0.0", + "ethers-v5": "npm:ethers@5", "hardhat": "^2.9.5", "mocha": "^10.0.0", "prettier": "2.4.1", diff --git a/packages/hardhat-network-helpers/test/helpers/getStorageAt.ts b/packages/hardhat-network-helpers/test/helpers/getStorageAt.ts index 46de0a1624..06236298dc 100644 --- a/packages/hardhat-network-helpers/test/helpers/getStorageAt.ts +++ b/packages/hardhat-network-helpers/test/helpers/getStorageAt.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { BlockTag, NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/mine.ts b/packages/hardhat-network-helpers/test/helpers/mine.ts index 97945826d1..8cf7674389 100644 --- a/packages/hardhat-network-helpers/test/helpers/mine.ts +++ b/packages/hardhat-network-helpers/test/helpers/mine.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/mineUpTo.ts b/packages/hardhat-network-helpers/test/helpers/mineUpTo.ts index bce852065a..3010630e27 100644 --- a/packages/hardhat-network-helpers/test/helpers/mineUpTo.ts +++ b/packages/hardhat-network-helpers/test/helpers/mineUpTo.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { useEnvironment } from "../test-utils"; diff --git a/packages/hardhat-network-helpers/test/helpers/setBalance.ts b/packages/hardhat-network-helpers/test/helpers/setBalance.ts index 040a26a770..1af4b3c88d 100644 --- a/packages/hardhat-network-helpers/test/helpers/setBalance.ts +++ b/packages/hardhat-network-helpers/test/helpers/setBalance.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/setBlockGasLimit.ts b/packages/hardhat-network-helpers/test/helpers/setBlockGasLimit.ts index 5604bf0f48..0a717d924c 100644 --- a/packages/hardhat-network-helpers/test/helpers/setBlockGasLimit.ts +++ b/packages/hardhat-network-helpers/test/helpers/setBlockGasLimit.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/setNextBlockBaseFeePerGas.ts b/packages/hardhat-network-helpers/test/helpers/setNextBlockBaseFeePerGas.ts index 85b078a25a..e9404cb891 100644 --- a/packages/hardhat-network-helpers/test/helpers/setNextBlockBaseFeePerGas.ts +++ b/packages/hardhat-network-helpers/test/helpers/setNextBlockBaseFeePerGas.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/setNonce.ts b/packages/hardhat-network-helpers/test/helpers/setNonce.ts index b1f5ea7a45..2e619a7237 100644 --- a/packages/hardhat-network-helpers/test/helpers/setNonce.ts +++ b/packages/hardhat-network-helpers/test/helpers/setNonce.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/setPrevRandao.ts b/packages/hardhat-network-helpers/test/helpers/setPrevRandao.ts index a42db5b6ce..18f1a68516 100644 --- a/packages/hardhat-network-helpers/test/helpers/setPrevRandao.ts +++ b/packages/hardhat-network-helpers/test/helpers/setPrevRandao.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { NumberLike } from "../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/setStorageAt.ts b/packages/hardhat-network-helpers/test/helpers/setStorageAt.ts index 18aac66834..62de311629 100644 --- a/packages/hardhat-network-helpers/test/helpers/setStorageAt.ts +++ b/packages/hardhat-network-helpers/test/helpers/setStorageAt.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../src"; import { toPaddedRpcQuantity } from "../../src/utils"; diff --git a/packages/hardhat-network-helpers/test/helpers/time/advanceBlock.ts b/packages/hardhat-network-helpers/test/helpers/time/advanceBlock.ts index 352462d271..ea7ffebbc6 100644 --- a/packages/hardhat-network-helpers/test/helpers/time/advanceBlock.ts +++ b/packages/hardhat-network-helpers/test/helpers/time/advanceBlock.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../../src"; import { NumberLike } from "../../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/time/advanceBlockTo.ts b/packages/hardhat-network-helpers/test/helpers/time/advanceBlockTo.ts index 44c4031bee..6d6d6315e4 100644 --- a/packages/hardhat-network-helpers/test/helpers/time/advanceBlockTo.ts +++ b/packages/hardhat-network-helpers/test/helpers/time/advanceBlockTo.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../../src"; import { useEnvironment } from "../../test-utils"; diff --git a/packages/hardhat-network-helpers/test/helpers/time/increase.ts b/packages/hardhat-network-helpers/test/helpers/time/increase.ts index 719fa169a9..ce14bc809c 100644 --- a/packages/hardhat-network-helpers/test/helpers/time/increase.ts +++ b/packages/hardhat-network-helpers/test/helpers/time/increase.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../../src"; import { NumberLike } from "../../../src/types"; diff --git a/packages/hardhat-network-helpers/test/helpers/time/increaseTo.ts b/packages/hardhat-network-helpers/test/helpers/time/increaseTo.ts index 9e4301cd79..d0bbb1b4f6 100644 --- a/packages/hardhat-network-helpers/test/helpers/time/increaseTo.ts +++ b/packages/hardhat-network-helpers/test/helpers/time/increaseTo.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { BN } from "ethereumjs-util"; -import { ethers } from "ethers"; +import { ethers } from "ethers-v5"; import * as hh from "../../../src"; import { useEnvironment } from "../../test-utils"; diff --git a/yarn.lock b/yarn.lock index d6a0fa9f34..d2bbd91d9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4196,6 +4196,42 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" +"ethers-v5@npm:ethers@5": + version "5.7.2" + resolved "http://localhost:4873/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + ethers@^4.0.0-beta.1, ethers@^4.0.32, ethers@^4.0.40: version "4.0.49" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" From 16ea02d060a2d5c3e308aff314ac5e2c91606f37 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 13:10:52 +0200 Subject: [PATCH 26/95] Fix yarn.lock --- yarn.lock | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/yarn.lock b/yarn.lock index d2bbd91d9e..72b8b12598 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4196,9 +4196,9 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -"ethers-v5@npm:ethers@5": +"ethers-v5@npm:ethers@5", ethers@^5.0.0, ethers@^5.0.13, ethers@^5.4.7, ethers@^5.7.1: version "5.7.2" - resolved "http://localhost:4873/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== dependencies: "@ethersproject/abi" "5.7.0" @@ -4247,42 +4247,6 @@ ethers@^4.0.0-beta.1, ethers@^4.0.32, ethers@^4.0.40: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.0, ethers@^5.0.13, ethers@^5.4.7, ethers@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethers@^6.1.0: version "6.2.3" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.2.3.tgz#9ddee438b5949e9724ba4c5d2c3b8deb5202ce96" From a75de2d9d557eb98bd3faebece0b62c755024974 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 14:05:42 +0200 Subject: [PATCH 27/95] Use new hh-ethers in hh-verify --- packages/hardhat-verify/package.json | 2 +- packages/hardhat-verify/src/errors.ts | 2 +- .../fixture-projects/hardhat-project/hardhat.config.js | 2 +- packages/hardhat-verify/test/helpers.ts | 9 +++++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/hardhat-verify/package.json b/packages/hardhat-verify/package.json index 029218e3e3..098098cffe 100644 --- a/packages/hardhat-verify/package.json +++ b/packages/hardhat-verify/package.json @@ -44,7 +44,7 @@ "undici": "^5.14.0" }, "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", "@types/chai": "^4.2.0", "@types/chai-as-promised": "^7.1.3", "@types/lodash.clonedeep": "^4.5.7", diff --git a/packages/hardhat-verify/src/errors.ts b/packages/hardhat-verify/src/errors.ts index 54c0cd7fed..6846d844c5 100644 --- a/packages/hardhat-verify/src/errors.ts +++ b/packages/hardhat-verify/src/errors.ts @@ -375,7 +375,7 @@ ${missingLibraries.map((x) => ` * ${x}`).join("\n")} ${ missingLibraries.length === undetectableLibraries.length - ? "Visit https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-etherscan#libraries-with-undetectable-addresses to learn how to solve this." + ? "Visit https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#libraries-with-undetectable-addresses to learn how to solve this." : "To solve this, you can add them to your --libraries dictionary with their corresponding addresses." }`); } diff --git a/packages/hardhat-verify/test/fixture-projects/hardhat-project/hardhat.config.js b/packages/hardhat-verify/test/fixture-projects/hardhat-project/hardhat.config.js index 1904ad4739..a04064c1fd 100644 --- a/packages/hardhat-verify/test/fixture-projects/hardhat-project/hardhat.config.js +++ b/packages/hardhat-verify/test/fixture-projects/hardhat-project/hardhat.config.js @@ -1,4 +1,4 @@ -require("@nomiclabs/hardhat-ethers"); +require("@nomicfoundation/hardhat-ethers"); require("../../../src/index"); diff --git a/packages/hardhat-verify/test/helpers.ts b/packages/hardhat-verify/test/helpers.ts index 34b0a46032..5754ce1b5b 100644 --- a/packages/hardhat-verify/test/helpers.ts +++ b/packages/hardhat-verify/test/helpers.ts @@ -1,7 +1,7 @@ import path from "path"; import { resetHardhatContext } from "hardhat/plugins-testing"; -import type {} from "@nomiclabs/hardhat-ethers"; +import type {} from "@nomicfoundation/hardhat-ethers"; import { FactoryOptions, HardhatRuntimeEnvironment } from "hardhat/types"; declare module "mocha" { @@ -34,9 +34,10 @@ export const deployContract = async ( ): Promise => { const factory = await ethers.getContractFactory(contractName, options); const contract = await factory.deploy(...constructorArguments); - await contract.deployTransaction.wait(confirmations); - console.log(`Deployed ${contractName} at ${contract.address}`); - return contract.address; + await contract.deploymentTransaction()?.wait(confirmations); + const contractAddress = await contract.getAddress(); + console.log(`Deployed ${contractName} at ${contractAddress}`); + return contractAddress; }; export const getRandomAddress = (hre: HardhatRuntimeEnvironment): string => From a62dbfdb02a5b64b8012ba91479296249048237d Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 18:47:23 +0200 Subject: [PATCH 28/95] Create common with proper hardfork before manipulating the block This prevents the following bug: - We use the merge hardfork locally - We fork a shanghai block - We run a call in a block before the forked block In this case, the remote block will be fetched and will have withdrawals. But when Block.fromBlockData is called with the current common (which has a merge hardfork) it will fail. If we create the right common before doing the block context manipulation, this doesn't happen. There is already a test for this scenario. I don't know why it wasn't failing before this. --- .../internal/hardhat-network/provider/node.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/hardhat-core/src/internal/hardhat-network/provider/node.ts b/packages/hardhat-core/src/internal/hardhat-network/provider/node.ts index 98c49665ca..0152e16d58 100644 --- a/packages/hardhat-core/src/internal/hardhat-network/provider/node.ts +++ b/packages/hardhat-core/src/internal/hardhat-network/provider/node.ts @@ -2387,6 +2387,22 @@ Hardhat Network's forking functionality only works with blocks from at least spu // know anything about the txs in the current block } + originalCommon = (this._vm as any)._common; + + (this._vm as any)._common = Common.custom( + { + chainId: + this._forkBlockNumber === undefined || + blockContext.header.number >= this._forkBlockNumber + ? this._configChainId + : this._forkNetworkId, + networkId: this._forkNetworkId ?? this._configNetworkId, + }, + { + hardfork: this._selectHardfork(blockContext.header.number), + } + ); + // If this VM is running without EIP4895, but the block has withdrawals, // we remove them and the withdrawal root from the block if ( @@ -2438,22 +2454,6 @@ Hardhat Network's forking functionality only works with blocks from at least spu (blockContext.header as any).baseFeePerGas = 0n; } - originalCommon = (this._vm as any)._common; - - (this._vm as any)._common = Common.custom( - { - chainId: - this._forkBlockNumber === undefined || - blockContext.header.number >= this._forkBlockNumber - ? this._configChainId - : this._forkNetworkId, - networkId: this._forkNetworkId ?? this._configNetworkId, - }, - { - hardfork: this._selectHardfork(blockContext.header.number), - } - ); - return await this._vm.runTx({ block: blockContext, tx, From a36750223342e37faeaea9504a134ef8cdd31fa5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 30 May 2023 18:16:19 +0000 Subject: [PATCH 29/95] Version Packages --- .changeset/lazy-hornets-clap.md | 5 ----- .changeset/silly-ghosts-sing.md | 5 ----- .changeset/yellow-suits-fail.md | 5 ----- packages/hardhat-chai-matchers/CHANGELOG.md | 10 ++++++++++ packages/hardhat-chai-matchers/package.json | 2 +- packages/hardhat-core/CHANGELOG.md | 6 ++++++ packages/hardhat-core/package.json | 2 +- packages/hardhat-toolbox/CHANGELOG.md | 8 ++++++++ packages/hardhat-toolbox/package.json | 6 +++--- 9 files changed, 29 insertions(+), 20 deletions(-) delete mode 100644 .changeset/lazy-hornets-clap.md delete mode 100644 .changeset/silly-ghosts-sing.md delete mode 100644 .changeset/yellow-suits-fail.md diff --git a/.changeset/lazy-hornets-clap.md b/.changeset/lazy-hornets-clap.md deleted file mode 100644 index 61606d5fb9..0000000000 --- a/.changeset/lazy-hornets-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-chai-matchers": patch ---- - -Fixed a problem when `.withArgs` was used with arrays with different length diff --git a/.changeset/silly-ghosts-sing.md b/.changeset/silly-ghosts-sing.md deleted file mode 100644 index 4653a5dfc2..0000000000 --- a/.changeset/silly-ghosts-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"hardhat": patch ---- - -Added block numbers for all mainnet hardforks diff --git a/.changeset/yellow-suits-fail.md b/.changeset/yellow-suits-fail.md deleted file mode 100644 index 9ccb3035cf..0000000000 --- a/.changeset/yellow-suits-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-chai-matchers": major ---- - -Added support for ethers v6 diff --git a/packages/hardhat-chai-matchers/CHANGELOG.md b/packages/hardhat-chai-matchers/CHANGELOG.md index 5da3f4d0ba..8f336aaec7 100644 --- a/packages/hardhat-chai-matchers/CHANGELOG.md +++ b/packages/hardhat-chai-matchers/CHANGELOG.md @@ -1,5 +1,15 @@ # @nomicfoundation/hardhat-chai-matchers +## 2.0.0 + +### Major Changes + +- 523235b83: Added support for ethers v6 + +### Patch Changes + +- 06c4797a7: Fixed a problem when `.withArgs` was used with arrays with different length + ## 1.0.6 ### Patch Changes diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index e4849e3d33..7bc0a965b6 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-chai-matchers", - "version": "1.0.6", + "version": "2.0.0", "description": "Hardhat utils for testing", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-chai-matchers", "repository": "github:nomicfoundation/hardhat", diff --git a/packages/hardhat-core/CHANGELOG.md b/packages/hardhat-core/CHANGELOG.md index 6d618fd1f4..d0979e1b87 100644 --- a/packages/hardhat-core/CHANGELOG.md +++ b/packages/hardhat-core/CHANGELOG.md @@ -1,5 +1,11 @@ # hardhat +## 2.14.1 + +### Patch Changes + +- e99498638: Added block numbers for all mainnet hardforks + ## 2.14.0 ### Minor Changes diff --git a/packages/hardhat-core/package.json b/packages/hardhat-core/package.json index 104267605f..6aa554aaef 100644 --- a/packages/hardhat-core/package.json +++ b/packages/hardhat-core/package.json @@ -1,6 +1,6 @@ { "name": "hardhat", - "version": "2.14.0", + "version": "2.14.1", "author": "Nomic Labs LLC", "license": "MIT", "homepage": "https://hardhat.org", diff --git a/packages/hardhat-toolbox/CHANGELOG.md b/packages/hardhat-toolbox/CHANGELOG.md index f0e56c3a1c..cea51a9699 100644 --- a/packages/hardhat-toolbox/CHANGELOG.md +++ b/packages/hardhat-toolbox/CHANGELOG.md @@ -1,5 +1,13 @@ # @nomicfoundation/hardhat-toolbox +## 3.0.0 + +### Patch Changes + +- Updated dependencies [06c4797a7] +- Updated dependencies [523235b83] + - @nomicfoundation/hardhat-chai-matchers@2.0.0 + ## 2.0.2 ### Patch Changes diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 756773bb13..5782043eb5 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-toolbox", - "version": "2.0.2", + "version": "3.0.0", "description": "Nomic Foundation's recommended bundle of Hardhat plugins", "repository": "github:nomicfoundation/hardhat", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-toolbox", @@ -38,7 +38,7 @@ "@ethersproject/abi": "^5.4.7", "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", "@typechain/ethers-v5": "^10.1.0", @@ -69,7 +69,7 @@ "@ethersproject/abi": "^5.4.7", "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", "@types/chai": "^4.2.0", From 9cd921160612b2e01c892513e8a83af4a99b0fef Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 30 May 2023 22:26:33 +0200 Subject: [PATCH 30/95] Don't modify the toolbox --- packages/hardhat-toolbox/CHANGELOG.md | 8 -------- packages/hardhat-toolbox/package.json | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/hardhat-toolbox/CHANGELOG.md b/packages/hardhat-toolbox/CHANGELOG.md index cea51a9699..f0e56c3a1c 100644 --- a/packages/hardhat-toolbox/CHANGELOG.md +++ b/packages/hardhat-toolbox/CHANGELOG.md @@ -1,13 +1,5 @@ # @nomicfoundation/hardhat-toolbox -## 3.0.0 - -### Patch Changes - -- Updated dependencies [06c4797a7] -- Updated dependencies [523235b83] - - @nomicfoundation/hardhat-chai-matchers@2.0.0 - ## 2.0.2 ### Patch Changes diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 5782043eb5..756773bb13 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-toolbox", - "version": "3.0.0", + "version": "2.0.2", "description": "Nomic Foundation's recommended bundle of Hardhat plugins", "repository": "github:nomicfoundation/hardhat", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-toolbox", @@ -38,7 +38,7 @@ "@ethersproject/abi": "^5.4.7", "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", "@typechain/ethers-v5": "^10.1.0", @@ -69,7 +69,7 @@ "@ethersproject/abi": "^5.4.7", "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", "@types/chai": "^4.2.0", From fb3fe0ea6c9f980d7aa1dfc393a7999de53ddf7b Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 09:30:19 +0200 Subject: [PATCH 31/95] Update yarn.lock after publishing --- yarn.lock | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/yarn.lock b/yarn.lock index 72b8b12598..c51602c832 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1185,6 +1185,17 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" +"@nomicfoundation/hardhat-chai-matchers@^1.0.0": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" + integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@types/chai-as-promised" "^7.1.3" + chai-as-promised "^7.1.1" + deep-eql "^4.0.1" + ordinal "^1.0.3" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" @@ -4197,6 +4208,7 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum rlp "^2.2.4" "ethers-v5@npm:ethers@5", ethers@^5.0.0, ethers@^5.0.13, ethers@^5.4.7, ethers@^5.7.1: + name ethers-v5 version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== From 8626c876a382bee74d9dc38d6958c965fd57b8e1 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 11:16:09 +0200 Subject: [PATCH 32/95] Use more future-proof type imports from ethers The way we were doing these imports doesn't work starting from ethers v6.4.0 --- packages/hardhat-ethers/src/internal/ethers-utils.ts | 2 +- .../hardhat-ethers/src/internal/hardhat-ethers-provider.ts | 6 +++--- packages/hardhat-ethers/src/signers.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/hardhat-ethers/src/internal/ethers-utils.ts b/packages/hardhat-ethers/src/internal/ethers-utils.ts index a94e452c12..ad83009d0c 100644 --- a/packages/hardhat-ethers/src/internal/ethers-utils.ts +++ b/packages/hardhat-ethers/src/internal/ethers-utils.ts @@ -8,7 +8,7 @@ import type { TransactionReceiptParams, LogParams, JsonRpcTransactionRequest, -} from "ethers/types/providers"; +} from "ethers"; import { accessListify, diff --git a/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts index 7181ffac94..6523fe0bd2 100644 --- a/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts +++ b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts @@ -1,9 +1,10 @@ -import type { AddressLike } from "ethers/types/address"; import type { + AddressLike, BlockTag, TransactionRequest, Filter, FilterByBlockHash, + Listener, ProviderEvent, PerformActionTransaction, TransactionResponseParams, @@ -11,8 +12,7 @@ import type { TransactionReceiptParams, LogParams, PerformActionFilter, -} from "ethers/types/providers"; -import type { Listener } from "ethers/types/utils"; +} from "ethers"; import { Block, diff --git a/packages/hardhat-ethers/src/signers.ts b/packages/hardhat-ethers/src/signers.ts index 1986358fab..e4ef81550b 100644 --- a/packages/hardhat-ethers/src/signers.ts +++ b/packages/hardhat-ethers/src/signers.ts @@ -1,4 +1,4 @@ -import type { BlockTag, TransactionRequest } from "ethers/types/providers"; +import type { BlockTag, TransactionRequest } from "ethers"; import { assertArgument, ethers, From 61feb2cdc85c24d76217010a724c7adfa5006785 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:11:44 +0100 Subject: [PATCH 33/95] Update LICENSE Update organization name --- packages/hardhat-chai-matchers/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-chai-matchers/LICENSE b/packages/hardhat-chai-matchers/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-chai-matchers/LICENSE +++ b/packages/hardhat-chai-matchers/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From b3d916e062bc53cf2e011a1d25aa93d9ac7ff7c3 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:13:29 +0100 Subject: [PATCH 34/95] Update LICENSE change organization name --- packages/hardhat-core/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-core/LICENSE b/packages/hardhat-core/LICENSE index 845dc73d24..9156bcfc0b 100644 --- a/packages/hardhat-core/LICENSE +++ b/packages/hardhat-core/LICENSE @@ -5,7 +5,7 @@ the MIT License as defined below. The MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 7f7114fc5d554b320e3824562524c6a1163f45c0 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:17:25 +0100 Subject: [PATCH 35/95] Update LICENSE change organization name --- packages/hardhat-ethers/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-ethers/LICENSE b/packages/hardhat-ethers/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-ethers/LICENSE +++ b/packages/hardhat-ethers/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From f1272b3d4b660e0c46a1ebd6ca83591a6c54b7f0 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:20:26 +0100 Subject: [PATCH 36/95] Update LICENSE change organization name --- packages/hardhat-network-helpers/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-network-helpers/LICENSE b/packages/hardhat-network-helpers/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-network-helpers/LICENSE +++ b/packages/hardhat-network-helpers/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 75b1b43a09527dc5a26daadf0be60bf6055890db Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:23:11 +0100 Subject: [PATCH 37/95] Update LICENSE change org name --- packages/hardhat-shorthand/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-shorthand/LICENSE b/packages/hardhat-shorthand/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-shorthand/LICENSE +++ b/packages/hardhat-shorthand/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From aedd460ff1c0274bbf3ec4590b7b4eb9b22eec09 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:24:31 +0100 Subject: [PATCH 38/95] Update LICENSE change org name --- packages/hardhat-solhint/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-solhint/LICENSE b/packages/hardhat-solhint/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-solhint/LICENSE +++ b/packages/hardhat-solhint/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 8bf0f10b3d34c37883315ad4bb94e4e6094d6456 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:29:28 +0100 Subject: [PATCH 39/95] Update LICENSE change org name --- packages/hardhat-solpp/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-solpp/LICENSE b/packages/hardhat-solpp/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-solpp/LICENSE +++ b/packages/hardhat-solpp/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 09e71b292d58b43c73981529fb576f80019cf5f8 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:30:07 +0100 Subject: [PATCH 40/95] Update LICENSE --- packages/hardhat-toolbox/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-toolbox/LICENSE b/packages/hardhat-toolbox/LICENSE index d5cab88817..3b7e8c7eab 100644 --- a/packages/hardhat-toolbox/LICENSE +++ b/packages/hardhat-toolbox/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2a2574355085966c13fab32314b0d16a0194fd0e Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:30:48 +0100 Subject: [PATCH 41/95] Update LICENSE --- packages/hardhat-truffle4/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-truffle4/LICENSE b/packages/hardhat-truffle4/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-truffle4/LICENSE +++ b/packages/hardhat-truffle4/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From aaf6dcee15786e4c57c462ad3cabe6accd72203f Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:31:15 +0100 Subject: [PATCH 42/95] Update LICENSE change org name --- packages/hardhat-truffle5/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-truffle5/LICENSE b/packages/hardhat-truffle5/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-truffle5/LICENSE +++ b/packages/hardhat-truffle5/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From b7b88559a49b91e69f86ff1d4e4a929cfb759013 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:31:45 +0100 Subject: [PATCH 43/95] Update LICENSE change org name --- packages/hardhat-verify/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-verify/LICENSE b/packages/hardhat-verify/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-verify/LICENSE +++ b/packages/hardhat-verify/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 56c4a3d97d2e6ccde6e91861ef8c7907b7285897 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:32:18 +0100 Subject: [PATCH 44/95] Update LICENSE change org name --- packages/hardhat-vyper/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-vyper/LICENSE b/packages/hardhat-vyper/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-vyper/LICENSE +++ b/packages/hardhat-vyper/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 32e29355668812cc40a8a6aebc3804f46be3a658 Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:32:50 +0100 Subject: [PATCH 45/95] Update LICENSE change org name --- packages/hardhat-web3-legacy/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-web3-legacy/LICENSE b/packages/hardhat-web3-legacy/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-web3-legacy/LICENSE +++ b/packages/hardhat-web3-legacy/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From c1398310d3cbe6bd35770bd7723ee51e1f53c1cb Mon Sep 17 00:00:00 2001 From: freiremanuel91 <114952526+freiremanuel91@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:33:17 +0100 Subject: [PATCH 46/95] Update LICENSE change org name --- packages/hardhat-web3/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-web3/LICENSE b/packages/hardhat-web3/LICENSE index 3b8858c555..3b7e8c7eab 100644 --- a/packages/hardhat-web3/LICENSE +++ b/packages/hardhat-web3/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Nomic Labs LLC +Copyright (c) 2023 Nomic Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From af7ace977c835087118f5e107d13c69e1d1f0f86 Mon Sep 17 00:00:00 2001 From: Luis Schaab Date: Tue, 6 Jun 2023 11:12:29 -0300 Subject: [PATCH 47/95] Rename error class & avoid compiling --- packages/hardhat-verify/src/errors.ts | 92 +++++++++---------- packages/hardhat-verify/src/etherscan.ts | 4 +- packages/hardhat-verify/src/index.ts | 25 +---- .../hardhat-verify/test/integration/index.ts | 4 +- packages/hardhat-verify/test/unit/index.ts | 2 - 5 files changed, 50 insertions(+), 77 deletions(-) diff --git a/packages/hardhat-verify/src/errors.ts b/packages/hardhat-verify/src/errors.ts index 6846d844c5..039fcb4551 100644 --- a/packages/hardhat-verify/src/errors.ts +++ b/packages/hardhat-verify/src/errors.ts @@ -6,13 +6,13 @@ import { } from "./abi-validation-extras"; import { TASK_VERIFY_VERIFY } from "./task-names"; -export class HardhatEtherscanError extends NomicLabsHardhatPluginError { +export class HardhatVerifyError extends NomicLabsHardhatPluginError { constructor(message: string, parent?: Error) { super("@nomicfoundation/hardhat-verify", message, parent); } } -export class MissingAddressError extends HardhatEtherscanError { +export class MissingAddressError extends HardhatVerifyError { constructor() { super( "You didn’t provide any address. Please re-run the 'verify' task with the address of the contract you want to verify." @@ -20,20 +20,20 @@ export class MissingAddressError extends HardhatEtherscanError { } } -export class InvalidAddressError extends HardhatEtherscanError { +export class InvalidAddressError extends HardhatVerifyError { constructor(address: string) { super(`${address} is an invalid address.`); } } -export class InvalidContractNameError extends HardhatEtherscanError { +export class InvalidContractNameError extends HardhatVerifyError { constructor(contractName: string) { super(`A valid fully qualified name was expected. Fully qualified names look like this: "contracts/AContract.sol:TheContract" Instead, this name was received: ${contractName}`); } } -export class MissingApiKeyError extends HardhatEtherscanError { +export class MissingApiKeyError extends HardhatVerifyError { constructor(network: string) { super(`You are trying to verify a contract in '${network}', but no API token was found for this network. Please provide one in your hardhat config. For example: @@ -50,7 +50,7 @@ See https://etherscan.io/apis`); } } -export class InvalidConstructorArgumentsError extends HardhatEtherscanError { +export class InvalidConstructorArgumentsError extends HardhatVerifyError { constructor() { super(`The constructorArguments parameter should be an array. If your constructor has no arguments pass an empty array. E.g: @@ -62,7 +62,7 @@ If your constructor has no arguments pass an empty array. E.g: } } -export class ExclusiveConstructorArgumentsError extends HardhatEtherscanError { +export class ExclusiveConstructorArgumentsError extends HardhatVerifyError { constructor() { super( "The parameters constructorArgsParams and constructorArgsModule are exclusive. Please provide only one of them." @@ -70,7 +70,7 @@ export class ExclusiveConstructorArgumentsError extends HardhatEtherscanError { } } -export class InvalidConstructorArgumentsModuleError extends HardhatEtherscanError { +export class InvalidConstructorArgumentsModuleError extends HardhatVerifyError { constructor(constructorArgsModulePath: string) { super(`The module ${constructorArgsModulePath} doesn't export a list. The module should look like this: @@ -78,7 +78,7 @@ module.exports = [ arg1, arg2, ... ];`); } } -export class InvalidLibrariesError extends HardhatEtherscanError { +export class InvalidLibrariesError extends HardhatVerifyError { constructor() { super(`The libraries parameter should be a dictionary. If your contract does not have undetectable libraries pass an empty object or omit the argument. E.g: @@ -90,7 +90,7 @@ If your contract does not have undetectable libraries pass an empty object or om } } -export class InvalidLibrariesModuleError extends HardhatEtherscanError { +export class InvalidLibrariesModuleError extends HardhatVerifyError { constructor(librariesModulePath: string) { super(`The module ${librariesModulePath} doesn't export a dictionary. The module should look like this: @@ -98,7 +98,7 @@ module.exports = { lib1: "0x...", lib2: "0x...", ... };`); } } -export class ImportingModuleError extends HardhatEtherscanError { +export class ImportingModuleError extends HardhatVerifyError { constructor(module: string, parent: Error) { super( `Importing the module for the ${module} failed. @@ -108,7 +108,7 @@ Reason: ${parent.message}`, } } -export class NetworkNotSupportedError extends HardhatEtherscanError { +export class NetworkNotSupportedError extends HardhatVerifyError { constructor(network: string) { super( `The selected network is ${network}. Please select a network supported by Etherscan.` @@ -116,7 +116,7 @@ export class NetworkNotSupportedError extends HardhatEtherscanError { } } -export class ChainConfigNotFoundError extends HardhatEtherscanError { +export class ChainConfigNotFoundError extends HardhatVerifyError { constructor(chainId: number) { super(`Trying to verify a contract in a network with chain id ${chainId}, but the plugin doesn't recognize it as a supported chain. @@ -128,7 +128,7 @@ To see the list of supported networks, run this command: } } -export class ContractVerificationRequestError extends HardhatEtherscanError { +export class ContractVerificationRequestError extends HardhatVerifyError { constructor(url: string, parent: Error) { super( `Failed to send contract verification request. @@ -139,7 +139,7 @@ Reason: ${parent.message}`, } } -export class ContractVerificationInvalidStatusCodeError extends HardhatEtherscanError { +export class ContractVerificationInvalidStatusCodeError extends HardhatVerifyError { constructor(url: string, statusCode: number, responseText: string) { super(`Failed to send contract verification request. Endpoint URL: ${url} @@ -147,7 +147,7 @@ The HTTP server response is not ok. Status code: ${statusCode} Response text: ${ } } -export class ContractVerificationMissingBytecodeError extends HardhatEtherscanError { +export class ContractVerificationMissingBytecodeError extends HardhatVerifyError { constructor(url: string, contractAddress: string) { super(`Failed to send contract verification request. Endpoint URL: ${url} @@ -158,7 +158,7 @@ try to wait for five confirmations of your contract deployment transaction befor } } -export class ContractStatusPollingError extends HardhatEtherscanError { +export class ContractStatusPollingError extends HardhatVerifyError { constructor(url: string, parent: Error) { super( `Failure during etherscan status polling. The verification may still succeed but @@ -170,7 +170,7 @@ Reason: ${parent.message}`, } } -export class ContractStatusPollingInvalidStatusCodeError extends HardhatEtherscanError { +export class ContractStatusPollingInvalidStatusCodeError extends HardhatVerifyError { constructor(statusCode: number, responseText: string) { super( `The HTTP server response is not ok. Status code: ${statusCode} Response text: ${responseText}` @@ -178,7 +178,7 @@ export class ContractStatusPollingInvalidStatusCodeError extends HardhatEthersca } } -export class ContractStatusPollingResponseNotOkError extends HardhatEtherscanError { +export class ContractStatusPollingResponseNotOkError extends HardhatVerifyError { constructor(message: string) { super(`The Etherscan API responded with a failure status. The verification may still succeed but should be checked manually. @@ -186,21 +186,21 @@ Reason: ${message}`); } } -export class EtherscanVersionNotSupportedError extends HardhatEtherscanError { +export class EtherscanVersionNotSupportedError extends HardhatVerifyError { constructor() { super(`Etherscan only supports compiler versions 0.4.11 and higher. See https://etherscan.io/solcversions for more information.`); } } -export class DeployedBytecodeNotFoundError extends HardhatEtherscanError { +export class DeployedBytecodeNotFoundError extends HardhatVerifyError { constructor(address: string, network: string) { super(`The address ${address} has no bytecode. Is the contract deployed to this network? The selected network is ${network}.`); } } -export class CompilerVersionsMismatchError extends HardhatEtherscanError { +export class CompilerVersionsMismatchError extends HardhatVerifyError { constructor( configCompilerVersions: string[], inferredCompilerVersion: string, @@ -221,20 +221,20 @@ Possible causes are: } } -export class ContractNotFoundError extends HardhatEtherscanError { +export class ContractNotFoundError extends HardhatVerifyError { constructor(contractFQN: string) { super(`The contract ${contractFQN} is not present in your project.`); } } -export class BuildInfoNotFoundError extends HardhatEtherscanError { +export class BuildInfoNotFoundError extends HardhatVerifyError { constructor(contractFQN: string) { super(`The contract ${contractFQN} is present in your project, but we couldn't find its sources. Please make sure that it has been compiled by Hardhat and that it is written in Solidity.`); } } -export class BuildInfoCompilerVersionMismatchError extends HardhatEtherscanError { +export class BuildInfoCompilerVersionMismatchError extends HardhatVerifyError { constructor( contractFQN: string, compilerVersion: string, @@ -256,20 +256,20 @@ Possible causes are: } } -export class DeployedBytecodeMismatchError extends HardhatEtherscanError { +export class DeployedBytecodeMismatchError extends HardhatVerifyError { constructor(network: string) { super(`The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts. Possible causes are: - - Contract code changed after the deployment was executed. This includes code for seemingly unrelated contracts. - - A solidity file was added, moved, deleted or renamed after the deployment was executed. This includes files for seemingly unrelated contracts. - - Solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.). + - The artifact for that contract is outdated or missing. You can try compiling the project again with the --force flag before re-running the verification. + - The contract's code changed after the deployment was executed. Sometimes this happens by changes in seemingly unrelated contracts. + - The solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.) - The given address is wrong. - The selected network (${network}) is wrong.`); } } -export class DeployedBytecodeMultipleMatchesError extends HardhatEtherscanError { +export class DeployedBytecodeMultipleMatchesError extends HardhatVerifyError { constructor(fqnMatches: string[]) { super(`More than one contract was found to match the deployed bytecode. Please use the contract parameter with one of the following contracts: @@ -288,20 +288,20 @@ contract: "contracts/Example.sol:ExampleContract" } } -export class DeployedBytecodeDoesNotMatchFQNError extends HardhatEtherscanError { +export class DeployedBytecodeDoesNotMatchFQNError extends HardhatVerifyError { constructor(contractFQN: string, network: string) { super(`The address provided as argument contains a contract, but its bytecode doesn't match the contract ${contractFQN}. Possible causes are: - - Contract code changed after the deployment was executed. This includes code for seemingly unrelated contracts. - - A solidity file was added, moved, deleted or renamed after the deployment was executed. This includes files for seemingly unrelated contracts. - - Solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.). + - The artifact for that contract is outdated or missing. You can try compiling the project again with the --force flag before re-running the verification. + - The contract's code changed after the deployment was executed. Sometimes this happens by changes in seemingly unrelated contracts. + - The solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.) - The given address is wrong. - The selected network (${network}) is wrong.`); } } -export class InvalidLibraryAddressError extends HardhatEtherscanError { +export class InvalidLibraryAddressError extends HardhatVerifyError { constructor( contractName: string, libraryName: string, @@ -313,7 +313,7 @@ export class InvalidLibraryAddressError extends HardhatEtherscanError { } } -export class DuplicatedLibraryError extends HardhatEtherscanError { +export class DuplicatedLibraryError extends HardhatVerifyError { constructor(libraryName: string, libraryFQN: string) { super( `The library names ${libraryName} and ${libraryFQN} refer to the same library and were given as two entries in the libraries dictionary. @@ -322,7 +322,7 @@ Remove one of them and review your libraries dictionary before proceeding.` } } -export class LibraryNotFoundError extends HardhatEtherscanError { +export class LibraryNotFoundError extends HardhatVerifyError { constructor( contractName: string, libraryName: string, @@ -348,7 +348,7 @@ ${ } } -export class LibraryMultipleMatchesError extends HardhatEtherscanError { +export class LibraryMultipleMatchesError extends HardhatVerifyError { constructor(contractName: string, libraryName: string, fqnMatches: string[]) { super(`The library name ${libraryName} is ambiguous for the contract ${contractName}. It may resolve to one of the following libraries: @@ -358,7 +358,7 @@ To fix this, choose one of these fully qualified library names and replace it in } } -export class MissingLibrariesError extends HardhatEtherscanError { +export class MissingLibrariesError extends HardhatVerifyError { constructor( contractName: string, allLibraries: string[], @@ -381,7 +381,7 @@ ${ } } -export class LibraryAddressesMismatchError extends HardhatEtherscanError { +export class LibraryAddressesMismatchError extends HardhatVerifyError { constructor( conflicts: Array<{ library: string; @@ -403,7 +403,7 @@ You can either fix these addresses in your libraries dictionary or simply remove } } -export class UnexpectedNumberOfFilesError extends HardhatEtherscanError { +export class UnexpectedNumberOfFilesError extends HardhatVerifyError { constructor() { super( "The plugin found an unexpected number of files for this contract. Please report this issue to the Hardhat team." @@ -411,7 +411,7 @@ export class UnexpectedNumberOfFilesError extends HardhatEtherscanError { } } -export class ABIArgumentLengthError extends HardhatEtherscanError { +export class ABIArgumentLengthError extends HardhatVerifyError { constructor( sourceName: string, contractName: string, @@ -426,7 +426,7 @@ but ${providedArgs} arguments were provided instead.`, } } -export class ABIArgumentTypeError extends HardhatEtherscanError { +export class ABIArgumentTypeError extends HardhatVerifyError { constructor(error: ABIArgumentTypeErrorType) { const { value: argValue, argument: argName, reason } = error; super( @@ -437,7 +437,7 @@ Encoder error reason: ${reason}`, } } -export class ABIArgumentOverflowError extends HardhatEtherscanError { +export class ABIArgumentOverflowError extends HardhatVerifyError { constructor(error: ABIArgumentOverflowErrorType) { const { value: argValue, fault: reason, operation } = error; super( @@ -449,7 +449,7 @@ Encoder error reason: ${reason} fault in ${operation}`, } } -export class VerificationAPIUnexpectedMessageError extends HardhatEtherscanError { +export class VerificationAPIUnexpectedMessageError extends HardhatVerifyError { constructor(message: string) { super(`The API responded with an unexpected message. Please report this issue to the Hardhat team. @@ -458,7 +458,7 @@ Message: ${message}`); } } -export class ContractVerificationFailedError extends HardhatEtherscanError { +export class ContractVerificationFailedError extends HardhatVerifyError { constructor(message: string, undetectableLibraries: string[]) { super(`The contract verification failed. Reason: ${message} diff --git a/packages/hardhat-verify/src/etherscan.ts b/packages/hardhat-verify/src/etherscan.ts index 17cdd8b1c5..93b79d481d 100644 --- a/packages/hardhat-verify/src/etherscan.ts +++ b/packages/hardhat-verify/src/etherscan.ts @@ -6,7 +6,7 @@ import { ContractVerificationRequestError, ContractVerificationMissingBytecodeError, ContractVerificationInvalidStatusCodeError, - HardhatEtherscanError, + HardhatVerifyError, MissingApiKeyError, ContractStatusPollingResponseNotOkError, } from "./errors"; @@ -109,7 +109,7 @@ export class Etherscan { } if (!etherscanResponse.isOk()) { - throw new HardhatEtherscanError(etherscanResponse.message); + throw new HardhatVerifyError(etherscanResponse.message); } return etherscanResponse; diff --git a/packages/hardhat-verify/src/index.ts b/packages/hardhat-verify/src/index.ts index 5c78cb59ca..bbb60a4059 100644 --- a/packages/hardhat-verify/src/index.ts +++ b/packages/hardhat-verify/src/index.ts @@ -8,7 +8,6 @@ import type { import { extendConfig, subtask, task, types } from "hardhat/config"; import { isFullyQualifiedName } from "hardhat/utils/contract-names"; import { - TASK_COMPILE, TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT, TASK_COMPILE_SOLIDITY_GET_DEPENDENCY_GRAPH, @@ -69,7 +68,6 @@ interface VerifyTaskArgs { libraries?: string; contract?: string; listNetworks: boolean; - noCompile: boolean; } // verify:verify subtask args @@ -78,7 +76,6 @@ interface VerifySubtaskArgs { constructorArguments: string[]; libraries: LibraryToAddress; contract?: string; - noCompile: boolean; } // parsed verification args @@ -88,7 +85,6 @@ interface VerificationArgs { libraries: LibraryToAddress; contractFQN?: string; listNetworks: boolean; - noCompile: boolean; } interface GetContractInformationArgs { @@ -150,7 +146,6 @@ task(TASK_VERIFY, "Verifies a contract on Etherscan") "Use if the deployed bytecode matches more than one contract in your project" ) .addFlag("listNetworks", "Print the list of supported networks") - .addFlag("noCompile", "Don't compile before running the task") .setAction(async (taskArgs: VerifyTaskArgs, { run }) => { const verificationArgs: VerificationArgs = await run( TASK_VERIFY_RESOLVE_ARGUMENTS, @@ -173,7 +168,6 @@ subtask(TASK_VERIFY_RESOLVE_ARGUMENTS) .addOptionalParam("libraries", undefined, undefined, types.inputFile) .addOptionalParam("contract") .addFlag("listNetworks") - .addFlag("noCompile") .setAction( async ({ address, @@ -182,7 +176,6 @@ subtask(TASK_VERIFY_RESOLVE_ARGUMENTS) contract, libraries: librariesModule, listNetworks, - noCompile, }: VerifyTaskArgs): Promise => { if (address === undefined) { throw new MissingAddressError(); @@ -210,7 +203,6 @@ subtask(TASK_VERIFY_RESOLVE_ARGUMENTS) libraries, contractFQN: contract, listNetworks, - noCompile, }; } ); @@ -234,7 +226,6 @@ subtask(TASK_VERIFY_ETHERSCAN) .addParam("libraries", undefined, undefined, types.any) .addOptionalParam("contractFQN") .addFlag("listNetworks") - .addFlag("noCompile") .setAction( async ( { @@ -243,7 +234,6 @@ subtask(TASK_VERIFY_ETHERSCAN) libraries, contractFQN, listNetworks, - noCompile, }: VerificationArgs, { config, network, run } ) => { @@ -286,11 +276,6 @@ ${contractURL}`); ); } - // Make sure that contract artifacts are up-to-date - if (!noCompile) { - await run(TASK_COMPILE, { quiet: true }); - } - const contractInformation: ExtendedContractInformation = await run( TASK_VERIFY_ETHERSCAN_GET_CONTRACT_INFORMATION, { @@ -542,16 +527,9 @@ subtask(TASK_VERIFY_VERIFY) .addOptionalParam("constructorArguments", undefined, [], types.any) .addOptionalParam("libraries", undefined, {}, types.any) .addOptionalParam("contract") - .addFlag("noCompile") .setAction( async ( - { - address, - constructorArguments, - libraries, - contract, - noCompile, - }: VerifySubtaskArgs, + { address, constructorArguments, libraries, contract }: VerifySubtaskArgs, { run } ) => { if (address === undefined) { @@ -581,7 +559,6 @@ subtask(TASK_VERIFY_VERIFY) constructorArgs: constructorArguments, libraries, contractFQN: contract, - noCompile, }); } ); diff --git a/packages/hardhat-verify/test/integration/index.ts b/packages/hardhat-verify/test/integration/index.ts index 1ff457aa67..0a899507d5 100644 --- a/packages/hardhat-verify/test/integration/index.ts +++ b/packages/hardhat-verify/test/integration/index.ts @@ -168,7 +168,7 @@ https://hardhat.etherscan.io/address/${address}#code` }); describe("with deleted artifacts", () => { - it("should not compile the project when the noCompile is provided", async function () { + it("should throw if the artifacts are missing", async function () { await this.hre.run(TASK_CLEAN); // task will fail since we deleted all the artifacts @@ -176,7 +176,6 @@ https://hardhat.etherscan.io/address/${address}#code` this.hre.run(TASK_VERIFY, { address: simpleContractAddress, constructorArgsParams: [], - noCompile: true, }) ).to.be.rejectedWith( /The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts./ @@ -589,7 +588,6 @@ for verification on the block explorer. Waiting for verification result... NormalLib: normalLibAddress, ConstructorLib: constructorLibAddress, }, - // noCompile: true, }); assert.equal(logStub.callCount, 2); diff --git a/packages/hardhat-verify/test/unit/index.ts b/packages/hardhat-verify/test/unit/index.ts index 46ec2fe913..cc3dd49783 100644 --- a/packages/hardhat-verify/test/unit/index.ts +++ b/packages/hardhat-verify/test/unit/index.ts @@ -61,7 +61,6 @@ describe("verify task", () => { }, contractFQN: "contracts/TestContract.sol:TestContract", listNetworks: true, - noCompile: true, }; const proccesedArgs = await this.hre.run(TASK_VERIFY_RESOLVE_ARGUMENTS, { address, @@ -70,7 +69,6 @@ describe("verify task", () => { libraries: "libraries.js", contract: "contracts/TestContract.sol:TestContract", listNetworks: true, - noCompile: true, }); assert.deepEqual(proccesedArgs, expectedArgs); From 40b371bcab31129f6d8115e20489db26cc28d27e Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 19:28:02 +0200 Subject: [PATCH 48/95] Add changeset --- .changeset/cuddly-grapes-wink.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cuddly-grapes-wink.md diff --git a/.changeset/cuddly-grapes-wink.md b/.changeset/cuddly-grapes-wink.md new file mode 100644 index 0000000000..4040f454f9 --- /dev/null +++ b/.changeset/cuddly-grapes-wink.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-verify": patch +--- + +Removed the compilation step from the verify task, and removed the noCompile flag From c16d40529ea09a376360b5660b4f28976e96f612 Mon Sep 17 00:00:00 2001 From: Luis Schaab Date: Tue, 6 Jun 2023 16:09:02 -0300 Subject: [PATCH 49/95] Remove duplicated error --- packages/hardhat-verify/src/errors.ts | 21 ++++++--------------- packages/hardhat-verify/src/index.ts | 7 ++----- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/packages/hardhat-verify/src/errors.ts b/packages/hardhat-verify/src/errors.ts index 039fcb4551..bb6a727135 100644 --- a/packages/hardhat-verify/src/errors.ts +++ b/packages/hardhat-verify/src/errors.ts @@ -257,8 +257,12 @@ Possible causes are: } export class DeployedBytecodeMismatchError extends HardhatVerifyError { - constructor(network: string) { - super(`The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts. + constructor(network: string, contractFQN?: string) { + const contractDetails = + typeof contractFQN === "string" + ? `the contract ${contractFQN}.` + : `any of your local contracts.`; + super(`The address provided as argument contains a contract, but its bytecode doesn't match ${contractDetails} Possible causes are: - The artifact for that contract is outdated or missing. You can try compiling the project again with the --force flag before re-running the verification. @@ -288,19 +292,6 @@ contract: "contracts/Example.sol:ExampleContract" } } -export class DeployedBytecodeDoesNotMatchFQNError extends HardhatVerifyError { - constructor(contractFQN: string, network: string) { - super(`The address provided as argument contains a contract, but its bytecode doesn't match the contract ${contractFQN}. - -Possible causes are: - - The artifact for that contract is outdated or missing. You can try compiling the project again with the --force flag before re-running the verification. - - The contract's code changed after the deployment was executed. Sometimes this happens by changes in seemingly unrelated contracts. - - The solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.) - - The given address is wrong. - - The selected network (${network}) is wrong.`); - } -} - export class InvalidLibraryAddressError extends HardhatVerifyError { constructor( contractName: string, diff --git a/packages/hardhat-verify/src/index.ts b/packages/hardhat-verify/src/index.ts index bbb60a4059..bbe8d9c147 100644 --- a/packages/hardhat-verify/src/index.ts +++ b/packages/hardhat-verify/src/index.ts @@ -34,7 +34,7 @@ import { ContractNotFoundError, BuildInfoNotFoundError, BuildInfoCompilerVersionMismatchError, - DeployedBytecodeDoesNotMatchFQNError, + DeployedBytecodeMismatchError, UnexpectedNumberOfFilesError, VerificationAPIUnexpectedMessageError, ContractVerificationFailedError, @@ -399,10 +399,7 @@ subtask(TASK_VERIFY_ETHERSCAN_GET_CONTRACT_INFORMATION) ); if (contractInformation === null) { - throw new DeployedBytecodeDoesNotMatchFQNError( - contractFQN, - network.name - ); + throw new DeployedBytecodeMismatchError(network.name, contractFQN); } } else { contractInformation = await extractInferredContractInformation( From e8a5d154b0f78a50a5a1ef86df39b103b7716719 Mon Sep 17 00:00:00 2001 From: Mikhail Melnik Date: Wed, 7 Jun 2023 17:27:28 +0300 Subject: [PATCH 50/95] fix aurora browser urls --- packages/hardhat-verify/src/chain-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hardhat-verify/src/chain-config.ts b/packages/hardhat-verify/src/chain-config.ts index 434b2a00ca..e6ac9cea5f 100644 --- a/packages/hardhat-verify/src/chain-config.ts +++ b/packages/hardhat-verify/src/chain-config.ts @@ -258,7 +258,7 @@ export const builtinChains: ChainConfig[] = [ chainId: 1313161554, urls: { apiURL: "https://explorer.mainnet.aurora.dev/api", - browserURL: "https://aurorascan.dev/", + browserURL: "https://explorer.mainnet.aurora.dev", }, }, { @@ -266,7 +266,7 @@ export const builtinChains: ChainConfig[] = [ chainId: 1313161555, urls: { apiURL: "https://explorer.testnet.aurora.dev/api", - browserURL: "https://testnet.aurorascan.dev", + browserURL: "https://explorer.testnet.aurora.dev", }, }, { From 1fe175fce57e939123bb44e9915b6b6b08c293a3 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 11:40:47 +0200 Subject: [PATCH 51/95] Update toolbox to use new plugins --- packages/hardhat-toolbox/package.json | 30 ++++++++++++--------------- packages/hardhat-toolbox/src/index.ts | 4 ++-- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 756773bb13..93d0a215c5 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-toolbox", - "version": "2.0.2", + "version": "3.0.0", "description": "Nomic Foundation's recommended bundle of Hardhat plugins", "repository": "github:nomicfoundation/hardhat", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-toolbox", @@ -35,14 +35,12 @@ ], "dependencies": {}, "devDependencies": { - "@ethersproject/abi": "^5.4.7", - "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", - "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.0.0", - "@typechain/ethers-v5": "^10.1.0", - "@typechain/hardhat": "^6.1.2", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^1.0.0", + "@typechain/ethers-v6": "^0.3.3", + "@typechain/hardhat": "^8.0.0", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", "@types/node": "^14.0.0", @@ -54,7 +52,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^5.4.7", + "ethers": "^6.3.0", "hardhat": "^2.11.0", "hardhat-gas-reporter": "^1.0.8", "mocha": "^10.0.0", @@ -66,19 +64,17 @@ "typescript": "~4.7.4" }, "peerDependencies": { - "@ethersproject/abi": "^5.4.7", - "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", - "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^1.0.0", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", "@types/node": ">=12.0.0", - "@typechain/ethers-v5": "^10.1.0", - "@typechain/hardhat": "^6.1.2", + "@typechain/ethers-v6": "^0.3.3", + "@typechain/hardhat": "^8.0.0", "chai": "^4.2.0", - "ethers": "^5.4.7", + "ethers": "^6.3.0", "hardhat": "^2.11.0", "hardhat-gas-reporter": "^1.0.8", "solidity-coverage": "^0.8.1", diff --git a/packages/hardhat-toolbox/src/index.ts b/packages/hardhat-toolbox/src/index.ts index 8efa0d2902..0a58d631e4 100644 --- a/packages/hardhat-toolbox/src/index.ts +++ b/packages/hardhat-toolbox/src/index.ts @@ -1,6 +1,6 @@ import "@nomicfoundation/hardhat-chai-matchers"; -import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-etherscan"; +import "@nomicfoundation/hardhat-ethers"; +import "@nomicfoundation/hardhat-verify"; import "@typechain/hardhat"; import "hardhat-gas-reporter"; import "solidity-coverage"; From ce4eddceb5aa387c74fac8ea735ccd29b48e5f19 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 19:57:24 +0200 Subject: [PATCH 52/95] Use ethers@^6.4.0 in Toolbox --- packages/hardhat-toolbox/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 93d0a215c5..7dfb99fa53 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -52,7 +52,7 @@ "eslint-plugin-import": "2.24.1", "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", - "ethers": "^6.3.0", + "ethers": "^6.4.0", "hardhat": "^2.11.0", "hardhat-gas-reporter": "^1.0.8", "mocha": "^10.0.0", @@ -74,7 +74,7 @@ "@typechain/ethers-v6": "^0.3.3", "@typechain/hardhat": "^8.0.0", "chai": "^4.2.0", - "ethers": "^6.3.0", + "ethers": "^6.4.0", "hardhat": "^2.11.0", "hardhat-gas-reporter": "^1.0.8", "solidity-coverage": "^0.8.1", From 290b16ac18c28d5c12a04cad71227fcf895aaf28 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 19:57:39 +0200 Subject: [PATCH 53/95] Use correct (tentative, future) version of @typechain/ethers-v6 --- packages/hardhat-toolbox/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 7dfb99fa53..21f02601bc 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -71,7 +71,7 @@ "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", "@types/node": ">=12.0.0", - "@typechain/ethers-v6": "^0.3.3", + "@typechain/ethers-v6": "^0.3.4", "@typechain/hardhat": "^8.0.0", "chai": "^4.2.0", "ethers": "^6.4.0", From 726be05dd1d8663237cd26872c25743642967ada Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 31 May 2023 19:58:32 +0200 Subject: [PATCH 54/95] Adapt project initialization to new Toolbox version --- .../javascript-esm/scripts/deploy.js | 8 ++++---- .../javascript-esm/test/Lock.js | 2 +- .../javascript/scripts/deploy.js | 8 ++++---- .../sample-projects/javascript/test/Lock.js | 2 +- .../typescript/scripts/deploy.ts | 8 +++++--- .../sample-projects/typescript/test/Lock.ts | 2 +- .../src/internal/cli/project-creation.ts | 18 ++++++++---------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js index 05f8a19cd9..00ceb3169e 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js @@ -9,15 +9,15 @@ import hre from "hardhat"; const currentTimestampInSeconds = Math.round(Date.now() / 1000); const unlockTime = currentTimestampInSeconds + 60; -const lockedAmount = hre.ethers.utils.parseEther("0.001"); +const lockedAmount = hre.ethers.parseEther("0.001"); const Lock = await hre.ethers.getContractFactory("Lock"); const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); -await lock.deployed(); +await lock.waitForDeploymet(); console.log( - `Lock with ${ethers.utils.formatEther( + `Lock with ${ethers.formatEther( lockedAmount - )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.address}` + )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}` ); diff --git a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js index a046170d20..1d192fe850 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js @@ -40,7 +40,7 @@ describe("Lock", function () { deployOneYearLockFixture ); - expect(await ethers.provider.getBalance(lock.address)).to.equal( + expect(await ethers.provider.getBalance(lock.target)).to.equal( lockedAmount ); }); diff --git a/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js b/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js index 745b18d4f7..bd3592fab4 100644 --- a/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js +++ b/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js @@ -10,17 +10,17 @@ async function main() { const currentTimestampInSeconds = Math.round(Date.now() / 1000); const unlockTime = currentTimestampInSeconds + 60; - const lockedAmount = hre.ethers.utils.parseEther("0.001"); + const lockedAmount = hre.ethers.parseEther("0.001"); const Lock = await hre.ethers.getContractFactory("Lock"); const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); - await lock.deployed(); + await lock.waitForDeployment(); console.log( - `Lock with ${ethers.utils.formatEther( + `Lock with ${ethers.formatEther( lockedAmount - )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.address}` + )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}` ); } diff --git a/packages/hardhat-core/sample-projects/javascript/test/Lock.js b/packages/hardhat-core/sample-projects/javascript/test/Lock.js index 6a161e6d44..ce4a74e4f1 100644 --- a/packages/hardhat-core/sample-projects/javascript/test/Lock.js +++ b/packages/hardhat-core/sample-projects/javascript/test/Lock.js @@ -43,7 +43,7 @@ describe("Lock", function () { deployOneYearLockFixture ); - expect(await ethers.provider.getBalance(lock.address)).to.equal( + expect(await ethers.provider.getBalance(lock.target)).to.equal( lockedAmount ); }); diff --git a/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts b/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts index cf9c177ea7..8288941bcf 100644 --- a/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts +++ b/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts @@ -4,15 +4,17 @@ async function main() { const currentTimestampInSeconds = Math.round(Date.now() / 1000); const unlockTime = currentTimestampInSeconds + 60; - const lockedAmount = ethers.utils.parseEther("0.001"); + const lockedAmount = ethers.parseEther("0.001"); const Lock = await ethers.getContractFactory("Lock"); const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); - await lock.deployed(); + await lock.waitForDeployment(); console.log( - `Lock with ${ethers.utils.formatEther(lockedAmount)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.address}` + `Lock with ${ethers.formatEther( + lockedAmount + )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}` ); } diff --git a/packages/hardhat-core/sample-projects/typescript/test/Lock.ts b/packages/hardhat-core/sample-projects/typescript/test/Lock.ts index 92e0dc7f40..6e0300bf24 100644 --- a/packages/hardhat-core/sample-projects/typescript/test/Lock.ts +++ b/packages/hardhat-core/sample-projects/typescript/test/Lock.ts @@ -41,7 +41,7 @@ describe("Lock", function () { deployOneYearLockFixture ); - expect(await ethers.provider.getBalance(lock.address)).to.equal( + expect(await ethers.provider.getBalance(lock.target)).to.equal( lockedAmount ); }); diff --git a/packages/hardhat-core/src/internal/cli/project-creation.ts b/packages/hardhat-core/src/internal/cli/project-creation.ts index 513438b2db..4e0bd8bdd4 100644 --- a/packages/hardhat-core/src/internal/cli/project-creation.ts +++ b/packages/hardhat-core/src/internal/cli/project-creation.ts @@ -41,24 +41,22 @@ type SampleProjectTypeCreationAction = const HARDHAT_PACKAGE_NAME = "hardhat"; const PROJECT_DEPENDENCIES: Dependencies = { - "@nomicfoundation/hardhat-toolbox": "^2.0.0", + "@nomicfoundation/hardhat-toolbox": "^3.0.0", }; const PEER_DEPENDENCIES: Dependencies = { - hardhat: "^2.11.1", + hardhat: "^2.14.0", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", - "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^1.0.0", chai: "^4.2.0", - ethers: "^5.4.7", + ethers: "^6.4.0", "hardhat-gas-reporter": "^1.0.8", "solidity-coverage": "^0.8.0", - "@typechain/hardhat": "^6.1.2", + "@typechain/hardhat": "^8.0.0", typechain: "^8.1.0", - "@typechain/ethers-v5": "^10.1.0", - "@ethersproject/abi": "^5.4.7", - "@ethersproject/providers": "^5.4.7", + "@typechain/ethers-v6": "^0.3.4", }; const TYPESCRIPT_DEPENDENCIES: Dependencies = {}; From d8056fb8bc1116338f61974a8a44cd0defcb2555 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 2 Jun 2023 15:54:29 +0200 Subject: [PATCH 55/95] Accept overrides in ethers.deployContract --- .../javascript-esm/scripts/deploy.js | 5 +- .../javascript/scripts/deploy.js | 5 +- .../typescript/scripts/deploy.ts | 5 +- .../hardhat-ethers/src/internal/helpers.ts | 52 ++++++++++++++++--- packages/hardhat-ethers/src/types/index.ts | 6 ++- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js index 00ceb3169e..119a4b791c 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js @@ -11,8 +11,9 @@ const unlockTime = currentTimestampInSeconds + 60; const lockedAmount = hre.ethers.parseEther("0.001"); -const Lock = await hre.ethers.getContractFactory("Lock"); -const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); +const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, +}); await lock.waitForDeploymet(); diff --git a/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js b/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js index bd3592fab4..39c08d67b2 100644 --- a/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js +++ b/packages/hardhat-core/sample-projects/javascript/scripts/deploy.js @@ -12,8 +12,9 @@ async function main() { const lockedAmount = hre.ethers.parseEther("0.001"); - const Lock = await hre.ethers.getContractFactory("Lock"); - const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + const lock = await hre.ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); await lock.waitForDeployment(); diff --git a/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts b/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts index 8288941bcf..181925391f 100644 --- a/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts +++ b/packages/hardhat-core/sample-projects/typescript/scripts/deploy.ts @@ -6,8 +6,9 @@ async function main() { const lockedAmount = ethers.parseEther("0.001"); - const Lock = await ethers.getContractFactory("Lock"); - const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); await lock.waitForDeployment(); diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index 5bc2a74006..4cfcde5917 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -1,6 +1,10 @@ import type { ethers as EthersT } from "ethers"; import type { HardhatEthersSigner } from "../signers"; -import type { FactoryOptions, Libraries } from "../types"; +import type { + DeployContractOptions, + FactoryOptions, + Libraries, +} from "../types"; import { Artifact, HardhatRuntimeEnvironment } from "hardhat/types"; import { HardhatEthersError } from "./errors"; @@ -343,20 +347,20 @@ export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, args?: any[], - signerOrOptions?: EthersT.Signer | FactoryOptions + signerOrOptions?: EthersT.Signer | DeployContractOptions ): Promise; export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, - signerOrOptions?: EthersT.Signer | FactoryOptions + signerOrOptions?: EthersT.Signer | DeployContractOptions ): Promise; export async function deployContract( hre: HardhatRuntimeEnvironment, name: string, - argsOrSignerOrOptions?: any[] | EthersT.Signer | FactoryOptions, - signerOrOptions?: EthersT.Signer | FactoryOptions + argsOrSignerOrOptions?: any[] | EthersT.Signer | DeployContractOptions, + signerOrOptions?: EthersT.Signer | DeployContractOptions ): Promise { let args = []; if (Array.isArray(argsOrSignerOrOptions)) { @@ -364,8 +368,44 @@ export async function deployContract( } else { signerOrOptions = argsOrSignerOrOptions; } + + let overrides: EthersT.Overrides = {}; + if (signerOrOptions !== undefined && !("getAddress" in signerOrOptions)) { + // the DeployContractOptions type combines the properties of FactoryOptions + // and of EthersT.Overrides, but we only want to use the latter. + // + // This seems to be the type-safest way to extract only those. + const overridesExplicitProperties: { + [K in keyof Required]: EthersT.Overrides[K]; + } = { + type: signerOrOptions.type, + + from: signerOrOptions.from, + + nonce: signerOrOptions.nonce, + + gasLimit: signerOrOptions.gasLimit, + gasPrice: signerOrOptions.gasPrice, + + maxPriorityFeePerGas: signerOrOptions.maxPriorityFeePerGas, + maxFeePerGas: signerOrOptions.maxFeePerGas, + + value: signerOrOptions.value, + chainId: signerOrOptions.chainId, + + accessList: signerOrOptions.accessList, + + customData: signerOrOptions.customData, + + blockTag: signerOrOptions.blockTag, + enableCcipRead: signerOrOptions.enableCcipRead, + }; + + overrides = overridesExplicitProperties; + } + const factory = await getContractFactory(hre, name, signerOrOptions); - return factory.deploy(...args) as any; + return factory.deploy(...args, overrides); } export async function getContractAtFromArtifact( diff --git a/packages/hardhat-ethers/src/types/index.ts b/packages/hardhat-ethers/src/types/index.ts index 7176df2fc4..0b2915baa6 100644 --- a/packages/hardhat-ethers/src/types/index.ts +++ b/packages/hardhat-ethers/src/types/index.ts @@ -12,6 +12,8 @@ export interface FactoryOptions { libraries?: Libraries; } +export type DeployContractOptions = FactoryOptions & ethers.Overrides; + export declare function getContractFactory< A extends any[] = any[], I = ethers.Contract @@ -30,13 +32,13 @@ export declare function getContractFactory< export declare function deployContract( name: string, - signerOrOptions?: ethers.Signer | FactoryOptions + signerOrOptions?: ethers.Signer | DeployContractOptions ): Promise; export declare function deployContract( name: string, args: any[], - signerOrOptions?: ethers.Signer | FactoryOptions + signerOrOptions?: ethers.Signer | DeployContractOptions ): Promise; export declare function getContractFactoryFromArtifact< From cbcfb875bf848266075db365f36978a7c3b695e6 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 09:48:36 +0200 Subject: [PATCH 56/95] Fix typo in sample project --- .../sample-projects/javascript-esm/scripts/deploy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js index 119a4b791c..b17ce00262 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/scripts/deploy.js @@ -15,7 +15,7 @@ const lock = await ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); -await lock.waitForDeploymet(); +await lock.waitForDeployment(); console.log( `Lock with ${ethers.formatEther( From 8acc70750bdd476cfe181ce57d53eecdad4a7903 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 10:49:53 +0200 Subject: [PATCH 57/95] Upgrade toolbox dependencies --- packages/hardhat-toolbox/package.json | 8 +-- yarn.lock | 90 +++++++++++++-------------- 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 21f02601bc..12667910bc 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -39,7 +39,7 @@ "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", "@nomicfoundation/hardhat-ethers": "^3.0.0", "@nomicfoundation/hardhat-verify": "^1.0.0", - "@typechain/ethers-v6": "^0.3.3", + "@typechain/ethers-v6": "^0.4.0", "@typechain/hardhat": "^8.0.0", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", @@ -60,7 +60,7 @@ "rimraf": "^3.0.2", "solidity-coverage": "^0.8.1", "ts-node": "^10.8.0", - "typechain": "^8.1.0", + "typechain": "^8.2.0", "typescript": "~4.7.4" }, "peerDependencies": { @@ -71,7 +71,7 @@ "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", "@types/node": ">=12.0.0", - "@typechain/ethers-v6": "^0.3.4", + "@typechain/ethers-v6": "^0.4.0", "@typechain/hardhat": "^8.0.0", "chai": "^4.2.0", "ethers": "^6.4.0", @@ -79,7 +79,7 @@ "hardhat-gas-reporter": "^1.0.8", "solidity-coverage": "^0.8.1", "ts-node": ">=8.0.0", - "typechain": "^8.1.0", + "typechain": "^8.2.0", "typescript": ">=4.5.0" }, "bugs": { diff --git a/yarn.lock b/yarn.lock index c51602c832..3e15708f03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== +"@adraffy/ens-normalize@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" + integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" @@ -542,7 +547,7 @@ "@ethereumjs/common" "^2.5.0" ethereumjs-util "^7.1.2" -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.4.7", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.7.0": +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== @@ -733,7 +738,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.4.7", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -1185,17 +1190,6 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-chai-matchers@^1.0.0": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" - integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@types/chai-as-promised" "^7.1.3" - chai-as-promised "^7.1.1" - deep-eql "^4.0.1" - ordinal "^1.0.3" - "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" @@ -1262,27 +1256,6 @@ "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" -"@nomiclabs/hardhat-ethers@^2.0.0": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.2.tgz#812d48929c3bf8fe840ec29eab4b613693467679" - integrity sha512-NLDlDFL2us07C0jB/9wzvR0kuLivChJWCXTKcj3yqjZqMoYp7g7wwS157F70VHx/+9gHIBGzak5pKDwG8gEefA== - -"@nomiclabs/hardhat-etherscan@^3.0.0": - version "3.1.7" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz#72e3d5bd5d0ceb695e097a7f6f5ff6fcbf062b9a" - integrity sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@ethersproject/address" "^5.0.2" - cbor "^8.1.0" - chalk "^2.4.2" - debug "^4.1.1" - fs-extra "^7.0.1" - lodash "^4.17.11" - semver "^6.3.0" - table "^6.8.0" - undici "^5.14.0" - "@nomiclabs/truffle-contract@^4.2.23": version "4.5.10" resolved "https://registry.yarnpkg.com/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz#52adcca1068647e1c2b44bf0e6a89fc4ad7f9213" @@ -1561,18 +1534,18 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== -"@typechain/ethers-v5@^10.1.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.2.0.tgz#68f5963efb5214cb2d881477228e4b5b315473e1" - integrity sha512-ikaq0N/w9fABM+G01OFmU3U3dNnyRwEahkdvi9mqy1a3XwKiPZaF/lu54OcNaEWnpvEYyhhS0N7buCtLQqC92w== +"@typechain/ethers-v6@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v6/-/ethers-v6-0.4.0.tgz#fb9e9b8eeadc455fd1fc9048b2340309860deaca" + integrity sha512-vD3Agzz63Gf2XlU3ed2/y+8dLWQj+wf+4Eq+0JXsyOio/plyV5F6r0yYe+s3XdGI858U3Sr263pl8mliDrUqbw== dependencies: lodash "^4.17.15" ts-essentials "^7.0.1" -"@typechain/hardhat@^6.1.2": - version "6.1.5" - resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-6.1.5.tgz#caad58a1d3e9cd88061a584eb4f4fa763d5dcad1" - integrity sha512-lg7LW4qDZpxFMknp3Xool61Fg6Lays8F8TXdFGBG+MxyYcYU5795P1U2XdStuzGq9S2Dzdgh+1jGww9wvZ6r4Q== +"@typechain/hardhat@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-8.0.0.tgz#60568b7a2d0260cc741fb0830a8caee8eb06ac64" + integrity sha512-XUVbqlMx8tJTOmzZCD/r196CidtNWAnTBZRcYxjLTKgcJMvc/kHQpWBnVMMB5QHxVKpYpCiz8g07FYCpG8rrjA== dependencies: fs-extra "^9.1.0" @@ -1773,6 +1746,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -2139,6 +2117,11 @@ aes-js@4.0.0-beta.3: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.3.tgz#da2253f0ff03a0b3a9e445c8cbdf78e7fda7d48c" integrity sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -4207,7 +4190,7 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -"ethers-v5@npm:ethers@5", ethers@^5.0.0, ethers@^5.0.13, ethers@^5.4.7, ethers@^5.7.1: +"ethers-v5@npm:ethers@5", ethers@^5.0.0, ethers@^5.0.13, ethers@^5.7.1: name ethers-v5 version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" @@ -4271,6 +4254,19 @@ ethers@^6.1.0: tslib "2.4.0" ws "8.5.0" +ethers@^6.4.0: + version "6.4.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.4.2.tgz#8304660278ef7d43959ad5c73ccf14d0e32e0a3f" + integrity sha512-c+vcTycVHp1bN6msgs9iscZKQgEqdzFh6omyvil2musktHJkPtWOKMuiGVBlBqMV100At5AAZBzG9HUBcUWKQA== + dependencies: + "@adraffy/ens-normalize" "1.9.2" + "@noble/hashes" "1.1.2" + "@noble/secp256k1" "1.7.1" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-abi@0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.1.8.tgz#cd288583ed628cdfadaf8adefa3ba1dbcbca6c18" @@ -8947,10 +8943,10 @@ type@^2.7.2: resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== -typechain@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.1.1.tgz#9c2e8012c2c4c586536fc18402dcd7034c4ff0bd" - integrity sha512-uF/sUvnXTOVF2FHKhQYnxHk4su4JjZR8vr4mA2mBaRwHTbwh0jIlqARz9XJr1tA0l7afJGvEa1dTSi4zt039LQ== +typechain@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.2.0.tgz#bd4fc8f111d4405e36858bae6f744604617b60f3" + integrity sha512-tZqhqjxJ9xAS/Lh32jccTjMkpx7sTdUVVHAy5Bf0TIer5QFNYXotiX74oCvoVYjyxUKDK3MXHtMFzMyD3kE+jg== dependencies: "@types/prettier" "^2.1.1" debug "^4.3.1" From 0902a6a3a92eecf9e64408bc9bffb2206ffbecc8 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 11:18:52 +0200 Subject: [PATCH 58/95] Update tutorial to use latest toolbox --- .../tutorial/deploying-to-a-live-network.md | 8 +--- .../src/content/tutorial/testing-contracts.md | 40 ++++++------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/docs/src/content/tutorial/deploying-to-a-live-network.md b/docs/src/content/tutorial/deploying-to-a-live-network.md index 372337934c..17bfe55bec 100644 --- a/docs/src/content/tutorial/deploying-to-a-live-network.md +++ b/docs/src/content/tutorial/deploying-to-a-live-network.md @@ -16,12 +16,9 @@ async function main() { console.log("Deploying contracts with the account:", deployer.address); - console.log("Account balance:", (await deployer.getBalance()).toString()); + const token = await ethers.deployContract("Token"); - const Token = await ethers.getContractFactory("Token"); - const token = await Token.deploy(); - - console.log("Token address:", token.address); + console.log("Token address:", await token.getAddress()); } main() @@ -43,7 +40,6 @@ With our current configuration, running it without the `--network` parameter wou ``` $ npx hardhat run scripts/deploy.js Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -Account balance: 10000000000000000000000 Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3 ``` diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index 4d87502e75..fcee301971 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -19,9 +19,7 @@ describe("Token contract", function () { it("Deployment should assign the total supply of tokens to the owner", async function () { const [owner] = await ethers.getSigners(); - const Token = await ethers.getContractFactory("Token"); - - const hardhatToken = await Token.deploy(); + const hardhatToken = await ethers.deployContract("Token"); const ownerBalance = await hardhatToken.balanceOf(owner.address); expect(await hardhatToken.totalSupply()).to.equal(ownerBalance); @@ -62,16 +60,10 @@ To learn more about `Signer`, you can look at the [Signers documentation](https: ::: ```js -const Token = await ethers.getContractFactory("Token"); +const hardhatToken = await ethers.deployContract("Token"); ``` -A `ContractFactory` in ethers.js is an abstraction used to deploy new smart contracts, so `Token` here is a factory for instances of our token contract. - -```js -const hardhatToken = await Token.deploy(); -``` - -Calling `deploy()` on a `ContractFactory` will start the deployment, and return a `Promise` that resolves to a `Contract`. This is the object that has a method for each of your smart contract functions. +Calling `ethers.deployContract("Token")` will start the deployment of our token contract, and return a `Promise` that resolves to a `Contract`. This is the object that has a method for each of your smart contract functions. ```js const ownerBalance = await hardhatToken.balanceOf(owner.address); @@ -93,7 +85,7 @@ To do this we're using [Chai](https://www.chaijs.com/) which is a popular JavaSc If you need to test your code by sending a transaction from an account (or `Signer` in ethers.js terminology) other than the default one, you can use the `connect()` method on your ethers.js `Contract` object to connect it to a different account, like this: -```js{18} +```js{16} const { expect } = require("chai"); describe("Token contract", function () { @@ -102,9 +94,7 @@ describe("Token contract", function () { it("Should transfer tokens between accounts", async function() { const [owner, addr1, addr2] = await ethers.getSigners(); - const Token = await ethers.getContractFactory("Token"); - - const hardhatToken = await Token.deploy(); + const hardhatToken = await ethers.deployContract("Token"); // Transfer 50 tokens from owner to addr1 await hardhatToken.transfer(addr1.address, 50); @@ -129,15 +119,12 @@ const { expect } = require("chai"); describe("Token contract", function () { async function deployTokenFixture() { - const Token = await ethers.getContractFactory("Token"); const [owner, addr1, addr2] = await ethers.getSigners(); - const hardhatToken = await Token.deploy(); - - await hardhatToken.deployed(); + const hardhatToken = await ethers.deployContract("Token"); // Fixtures can return anything you consider useful for your tests - return { Token, hardhatToken, owner, addr1, addr2 }; + return { hardhatToken, owner, addr1, addr2 }; } it("Should assign the total supply of tokens to the owner", async function () { @@ -198,19 +185,18 @@ describe("Token contract", function () { // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployTokenFixture() { - // Get the ContractFactory and Signers here. - const Token = await ethers.getContractFactory("Token"); + // Get the Signers here. const [owner, addr1, addr2] = await ethers.getSigners(); - // To deploy our contract, we just have to call Token.deploy() and await - // its deployed() method, which happens once its transaction has been + // To deploy our contract, we just have to call ethers.deployContract and await + // its waitForDeployment() method, which happens once its transaction has been // mined. - const hardhatToken = await Token.deploy(); + const hardhatToken = await ethers.deployContract("Token"); - await hardhatToken.deployed(); + await hardhatToken.waitForDeployment(); // Fixtures can return anything you consider useful for your tests - return { Token, hardhatToken, owner, addr1, addr2 }; + return { hardhatToken, owner, addr1, addr2 }; } // You can nest describe calls to create subsections. From ec6acb46a7d91a71bce2734470fc30b763a2cb07 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 11:49:21 +0200 Subject: [PATCH 59/95] Update docs to use ethers v6 and ethers.deployContract --- .../docs/guides/test-contracts.md | 59 +++++++++++++++---- .../tutorial/deploying-to-a-live-network.md | 2 +- .../src/content/tutorial/testing-contracts.md | 2 +- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md index d7e4e93552..0aaa8959ce 100644 --- a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md +++ b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md @@ -37,8 +37,9 @@ describe("Lock", function () { // deploy a lock contract where funds can be withdrawn // one year in the future - const Lock = await hre.ethers.getContractFactory("Lock"); - const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); @@ -63,8 +64,9 @@ describe("Lock", function () { // deploy a lock contract where funds can be withdrawn // one year in the future - const Lock = await hre.ethers.getContractFactory("Lock"); - const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); @@ -78,7 +80,7 @@ describe("Lock", function () { First we import the things we are going to use: the [`expect`](https://www.chaijs.com/api/bdd/) function from `chai` to write our assertions, the [Hardhat Runtime Environment](../advanced/hardhat-runtime-environment.md) (`hre`), and the [network helpers](/hardhat-network-helpers) to interact with the Hardhat Network. After that we use the `describe` and `it` functions, which are global Mocha functions used to describe and group your tests. (You can read more about Mocha [here](https://mochajs.org/#getting-started).) -The test itself is what’s inside the callback argument to the `it` function. First we set the values for the amount we want to lock (in [wei](https://ethereum.org/en/glossary/#wei)) and the unlock time. For the latter we use [`time.latest`](), a network helper that returns the timestamp of the last mined block. Then we deploy the contract itself: first we get a [`ContractFactory`](https://docs.ethers.io/v5/single-page/#/v5/api/contract/contract-factory/) for the `Lock` contract and then we deploy it, passing the unlock time as its constructor argument. We also pass an object with the transaction parameters. This is optional, but we'll use it to send some ETH by setting its `value` field. +The test itself is what’s inside the callback argument to the `it` function. First we set the values for the amount we want to lock (in [wei](https://ethereum.org/en/glossary/#wei)) and the unlock time. For the latter we use [`time.latest`](), a network helper that returns the timestamp of the last mined block. Then we deploy the contract itself: we call `ethers.deployContract` with the name of the contract we want to deploy and an array of constructor arguments that has the unlock time. We also pass an object with the transaction parameters. This is optional, but we'll use it to send some ETH by setting its `value` field. Finally, we check that the value returned by the `unlockTime()` [getter](https://docs.soliditylang.org/en/v0.8.13/contracts.html#getter-functions) in the contract matches the value that we used when we deployed it. Since all the functions on a contract are async, we have to use the `await` keyword to get its value; otherwise, we would be comparing a promise with a number and this would always fail. @@ -171,8 +173,9 @@ describe("Lock", function () { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; unlockTime = (await helpers.time.latest()) + ONE_YEAR_IN_SECS; - const Lock = await ethers.getContractFactory("Lock"); - lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); }); it("some test", async function () { @@ -195,8 +198,9 @@ describe("Lock", function () { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; unlockTime = (await helpers.time.latest()) + ONE_YEAR_IN_SECS; - const Lock = await ethers.getContractFactory("Lock"); - lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); }); it("some test", async function () { @@ -216,17 +220,25 @@ However, there are two problems with this approach: The `loadFixture` helper in the Hardhat Network Helpers fixes both of these problems. This helper receives a _fixture_, a function that sets up the chain to some desired state. The first time `loadFixture` is called, the fixture is executed. But the second time, instead of executing the fixture again, `loadFixture` will reset the state of the network to the point where it was right after the fixture was executed. This is faster, and it undoes any state changes done by the previous test. -This is how our two first tests look like when a fixture is used: +This is how our tests look like when a fixture is used: ```tsx +const { expect } = require("chai"); +const hre = require("hardhat"); +const { + loadFixture, + time, +} = require("@nomicfoundation/hardhat-network-helpers"); + describe("Lock", function () { async function deployOneYearLockFixture() { const lockedAmount = 1_000_000_000; const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; - const Lock = await ethers.getContractFactory("Lock"); - const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); return { lock, unlockTime, lockedAmount }; } @@ -243,6 +255,29 @@ describe("Lock", function () { await expect(lock.withdraw()).to.be.revertedWith("You can't withdraw yet"); }); + + it("Should transfer the funds to the owner", async function () { + const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); + + await time.increaseTo(unlockTime); + + // this will throw if the transaction reverts + await lock.withdraw(); + }); + + it("Should revert with the right error if called from another account", async function () { + const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); + + const [owner, otherAccount] = await ethers.getSigners(); + + // we increase the time of the chain to pass the first check + await time.increaseTo(unlockTime); + + // We use lock.connect() to send a transaction from another account + await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( + "You aren't the owner" + ); + }); }); ``` diff --git a/docs/src/content/tutorial/deploying-to-a-live-network.md b/docs/src/content/tutorial/deploying-to-a-live-network.md index 17bfe55bec..50a350b80c 100644 --- a/docs/src/content/tutorial/deploying-to-a-live-network.md +++ b/docs/src/content/tutorial/deploying-to-a-live-network.md @@ -6,7 +6,7 @@ The "mainnet" Ethereum network deals with real money, but there are separate "te At the software level, deploying to a testnet is the same as deploying to mainnet. The only difference is which network you connect to. Let's look into what the code to deploy your contracts using ethers.js would look like. -The main concepts used are `Signer`, `ContractFactory` and `Contract` which we explained back in the [testing](testing-contracts.md) section. There's nothing new that needs to be done when compared to testing, given that when you're testing your contracts you're _actually_ making a deployment to your development network. This makes the code very similar, or even the same. +The main concepts used are `Signer` and `Contract` which we explained back in the [testing](testing-contracts.md) section. There's nothing new that needs to be done when compared to testing, given that when you're testing your contracts you're _actually_ making a deployment to your development network. This makes the code very similar, or even the same. Let's create a new directory `scripts` inside the project root's directory, and paste the following into a `deploy.js` file in that directory: diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index fcee301971..725dc2ce41 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -71,7 +71,7 @@ const ownerBalance = await hardhatToken.balanceOf(owner.address); Once the contract is deployed, we can call our contract methods on `hardhatToken`. Here we get the balance of the owner account by calling the contract's `balanceOf()` method. -Recall that the account that deploys the token gets its entire supply. By default, `ContractFactory` and `Contract` instances are connected to the first signer. This means that the account in the `owner` variable executed the deployment, and `balanceOf()` should return the entire supply amount. +Recall that the account that deploys the token gets its entire supply. By default, `Contract` instances are connected to the first signer. This means that the account in the `owner` variable executed the deployment, and `balanceOf()` should return the entire supply amount. ```js expect(await hardhatToken.totalSupply()).to.equal(ownerBalance); From c69540f1952619e1ed4980ae7468097e1b04c48f Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:13:46 +0200 Subject: [PATCH 60/95] Use proper deps versions and fix some links to ethers docs --- .../hardhat-chai-matchers/docs/migrate-from-waffle.md | 6 +++--- docs/src/content/hardhat-chai-matchers/docs/overview.md | 8 ++++---- docs/src/content/hardhat-chai-matchers/docs/reference.md | 7 +++---- .../content/hardhat-runner/docs/advanced/create-task.md | 6 +++--- .../content/hardhat-runner/docs/getting-started/index.md | 4 ++-- .../content/hardhat-runner/docs/guides/hardhat-console.md | 2 +- .../docs/guides/migrating-from-hardhat-waffle.md | 8 ++++---- .../content/hardhat-runner/docs/guides/project-setup.md | 2 +- .../content/hardhat-runner/docs/guides/test-contracts.md | 2 +- .../hardhat-runner/docs/other-guides/waffle-testing.md | 2 +- docs/src/content/hardhat-runner/plugins/_dirinfo.yaml | 2 +- docs/src/content/hardhat-runner/plugins/plugins.ts | 2 +- .../content/tutorial/creating-a-new-hardhat-project.md | 4 ++-- docs/src/content/tutorial/testing-contracts.md | 4 ++-- 14 files changed, 29 insertions(+), 30 deletions(-) diff --git a/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md b/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md index f3980f1341..485704db0d 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md +++ b/docs/src/content/hardhat-chai-matchers/docs/migrate-from-waffle.md @@ -43,7 +43,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value="npm 7+"} ``` - npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 + npm install --save-dev @nomicfoundation/hardhat-chai-matchers ``` ::: @@ -51,7 +51,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value="npm 6"} ``` - npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 + npm install --save-dev @nomicfoundation/hardhat-chai-matchers ``` ::: @@ -59,7 +59,7 @@ The `@nomicfoundation/hardhat-chai-matchers` plugin is meant to be a drop-in rep :::tab{value=yarn} ``` - yarn add --dev @nomicfoundation/hardhat-chai-matchers@1 + yarn add --dev @nomicfoundation/hardhat-chai-matchers ``` ::: diff --git a/docs/src/content/hardhat-chai-matchers/docs/overview.md b/docs/src/content/hardhat-chai-matchers/docs/overview.md index ed284fd6b7..9f52cb8220 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/overview.md +++ b/docs/src/content/hardhat-chai-matchers/docs/overview.md @@ -16,7 +16,7 @@ Among other things, you can assert that a contract fired certain events, or that :::tab{value="npm 7+"} ``` -npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 +npm install --save-dev @nomicfoundation/hardhat-chai-matchers ``` ::: @@ -24,7 +24,7 @@ npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 +npm install --save-dev @nomicfoundation/hardhat-chai-matchers ``` ::: @@ -32,7 +32,7 @@ npm install --save-dev @nomicfoundation/hardhat-chai-matchers@1 :::tab{value=yarn} ``` -yarn add --dev @nomicfoundation/hardhat-chai-matchers@1 +yarn add --dev @nomicfoundation/hardhat-chai-matchers ``` ::: @@ -175,7 +175,7 @@ This package enhances the standard numerical equality matchers (`equal`, `above` expect(await token.balanceOf(someAddress)).to.equal(1); ``` -These matchers support not just [ethers' `BigNumber`](https://docs.ethers.io/v5/single-page/#/v5/api/utils/bignumber/) and the native JavaScript `Number`, but also [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), [bn.js](https://github.com/indutny/bn.js/), and [bignumber.js](https://github.com/MikeMcl/bignumber.js/). +These matchers support not just the native JavaScript `Number`, but also [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), [bn.js](https://github.com/indutny/bn.js/), and [bignumber.js](https://github.com/MikeMcl/bignumber.js/). ### Balance Changes diff --git a/docs/src/content/hardhat-chai-matchers/docs/reference.md b/docs/src/content/hardhat-chai-matchers/docs/reference.md index 42f99a9c64..ee1dd7d2d9 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/reference.md +++ b/docs/src/content/hardhat-chai-matchers/docs/reference.md @@ -10,13 +10,12 @@ When `@nomicfoundation/hardhat-chai-matchers` is used, equality comparisons of n expect(await token.totalSupply()).to.equal(1_000_000); ``` -will work. These assertions don't normally work because the value returned by `totalSupply()` is an [ethers BigNumber](https://docs.ethers.io/v5/single-page/#/v5/api/utils/bignumber/), and an instance of a `BigNumber` will always be different than a plain number. +will work. These assertions don't normally work because the value returned by `totalSupply()` is a [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), and a bigint value will always be different than a plain number. The supported types are: - Plain javascript numbers - [BigInts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) -- [Ethers BigNumbers](https://docs.ethers.io/v5/single-page/#/v5/api/utils/bignumber/) - [`bn.js`](https://github.com/indutny/bn.js/) instances - [`bignumber.js`](https://github.com/MikeMcl/bignumber.js/) instances @@ -226,8 +225,8 @@ await expect(factory.create(9999)) Predicates are just functions that return true if the value is correct, and return false if it isn't, so you can create your own predicates: ```ts -function isEven(x: BigNumber): boolean { - return x.mod(2).isZero(); +function isEven(x: bigint): boolean { + return x % 2n === 0n; } await expect(token.transfer(100)).to.emit(token, "Transfer").withArgs(isEven); diff --git a/docs/src/content/hardhat-runner/docs/advanced/create-task.md b/docs/src/content/hardhat-runner/docs/advanced/create-task.md index 37aeaf4bdb..a1d29b3884 100644 --- a/docs/src/content/hardhat-runner/docs/advanced/create-task.md +++ b/docs/src/content/hardhat-runner/docs/advanced/create-task.md @@ -48,7 +48,7 @@ Let’s go through the process of creating one to interact with a smart contract Tasks in Hardhat are asynchronous JavaScript functions that get access to the [Hardhat Runtime Environment](../advanced/hardhat-runtime-environment.md), which exposes its configuration and parameters, as well as programmatic access to other tasks and any plugin objects that may have been injected. -For our example, we will use the [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox), which includes the [ethers.js](https://docs.ethers.io/v5/) library to interact with our contracts. +For our example, we will use the [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox), which includes the [ethers.js](https://docs.ethers.io/) library to interact with our contracts. ::::tabsgroup{options="npm 7+,npm 6,yarn"} @@ -63,7 +63,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: @@ -71,7 +71,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat :::tab{value="yarn"} ``` -yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: diff --git a/docs/src/content/hardhat-runner/docs/getting-started/index.md b/docs/src/content/hardhat-runner/docs/getting-started/index.md index b1bc062deb..6e28b34472 100644 --- a/docs/src/content/hardhat-runner/docs/getting-started/index.md +++ b/docs/src/content/hardhat-runner/docs/getting-started/index.md @@ -150,7 +150,7 @@ If you created a TypeScript project, this task will also generate TypeScript bin ### Testing your contracts -Your project comes with tests that use [Mocha](https://mochajs.org), [Chai](https://www.chaijs.com), and [Ethers.js](https://docs.ethers.io/v5). +Your project comes with tests that use [Mocha](https://mochajs.org), [Chai](https://www.chaijs.com), and [Ethers.js](https://docs.ethers.io/v6). If you take a look in the `test/` folder, you'll see a test file: @@ -178,7 +178,7 @@ You can run your tests with `npx hardhat test`: ``` $ npx hardhat test -Generating typings for: 2 artifacts in dir: typechain-types for target: ethers-v5 +Generating typings for: 2 artifacts in dir: typechain-types for target: ethers-v6 Successfully generated 6 typings! Compiled 2 Solidity files successfully diff --git a/docs/src/content/hardhat-runner/docs/guides/hardhat-console.md b/docs/src/content/hardhat-runner/docs/guides/hardhat-console.md index 7bf0def7a4..451a30a51e 100644 --- a/docs/src/content/hardhat-runner/docs/guides/hardhat-console.md +++ b/docs/src/content/hardhat-runner/docs/guides/hardhat-console.md @@ -25,7 +25,7 @@ For example, you'll have access in the global scope to the `config` object: > ``` -And if you followed the [Getting started guide](../getting-started) or installed `@nomiclabs/hardhat-ethers`, the `ethers` object: +And if you followed the [Getting started guide](../getting-started) or installed `@nomicfoundation/hardhat-ethers`, the `ethers` object: ``` > ethers diff --git a/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md b/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md index 7abec2e16c..b4edec853c 100644 --- a/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md +++ b/docs/src/content/hardhat-runner/docs/guides/migrating-from-hardhat-waffle.md @@ -55,7 +55,7 @@ Follow these steps to migrate your project to Hardhat Toolbox. :::tab{value="npm 6"} ``` - npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers + npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: @@ -63,7 +63,7 @@ Follow these steps to migrate your project to Hardhat Toolbox. :::tab{value="yarn"} ``` - yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers + yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: @@ -96,8 +96,8 @@ Follow these steps to migrate your project to Hardhat Toolbox. Adding the Toolbox will make many other imports redundant, so you can remove any of these if you want: - - `@nomiclabs/hardhat-ethers` - - `@nomiclabs/hardhat-etherscan` + - `@nomicfoundation/hardhat-ethers` + - `@nomicfoundation/hardhat-verify` - `hardhat-gas-reporter` - `solidity-coverage` - `@typechain/hardhat` diff --git a/docs/src/content/hardhat-runner/docs/guides/project-setup.md b/docs/src/content/hardhat-runner/docs/guides/project-setup.md index 0751641054..b503ad9218 100644 --- a/docs/src/content/hardhat-runner/docs/guides/project-setup.md +++ b/docs/src/content/hardhat-runner/docs/guides/project-setup.md @@ -128,7 +128,7 @@ When it comes to testing your contracts, the sample project comes with some usef - The built-in [Hardhat Network](/hardhat-network/docs) as the development network to test on, along with the [Hardhat Network Helpers](/hardhat-network-helpers) library to manipulate this network. - [Mocha](https://mochajs.org/) as the test runner, [Chai](https://chaijs.com/) as the assertion library, and the [Hardhat Chai Matchers](/hardhat-chai-matchers) to extend Chai with contracts-related functionality. -- The [`ethers.js`](https://docs.ethers.io/v5/) library to interact with the network and with contracts. +- The [`ethers.js`](https://docs.ethers.io/v6/) library to interact with the network and with contracts. As well as other useful plugins. You can learn more about this in the [Testing contracts guide](./test-contracts.md). diff --git a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md index 0aaa8959ce..d400ade784 100644 --- a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md +++ b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md @@ -2,7 +2,7 @@ After [compiling your contracts](./compile-contracts.md), the next step is to write some tests to verify that they work as intended. -This guide explains our recommended approach for testing contracts in Hardhat. It relies on [ethers](https://docs.ethers.io/v5/) to connect to [Hardhat Network](/hardhat-network) and on [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for the tests. It also uses our custom [Chai matchers](/hardhat-chai-matchers) and our [Hardhat Network Helpers](/hardhat-network-helpers) to make it easier to write clean test code. These packages are part of the Hardhat Toolbox plugin; if you followed the previous guides, you should already have them installed. +This guide explains our recommended approach for testing contracts in Hardhat. It relies on [ethers](https://docs.ethers.io/v6/) to connect to [Hardhat Network](/hardhat-network) and on [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for the tests. It also uses our custom [Chai matchers](/hardhat-chai-matchers) and our [Hardhat Network Helpers](/hardhat-network-helpers) to make it easier to write clean test code. These packages are part of the Hardhat Toolbox plugin; if you followed the previous guides, you should already have them installed. While this is our recommended test setup, Hardhat is flexible: you can customize the approach or take a completely different path with other tools. diff --git a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md index ada090eb40..b61966219f 100644 --- a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md +++ b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md @@ -229,7 +229,7 @@ A `Signer` in Ethers.js is an object that represents an Ethereum account. It's u :::tip -To learn more about `Signer`, you can look at the [Signers documentation](https://docs.ethers.io/v5/api/signer/#Wallet). +To learn more about `Signer`, you can look at the [Signers documentation](https://docs.ethers.org/v6/api/providers/#Signer). ::: diff --git a/docs/src/content/hardhat-runner/plugins/_dirinfo.yaml b/docs/src/content/hardhat-runner/plugins/_dirinfo.yaml index 1728c8daff..05dfea2621 100644 --- a/docs/src/content/hardhat-runner/plugins/_dirinfo.yaml +++ b/docs/src/content/hardhat-runner/plugins/_dirinfo.yaml @@ -3,7 +3,7 @@ section-title: Plugins order: - "@nomicfoundation/hardhat-toolbox" - "@nomicfoundation/hardhat-chai-matchers" - - "@nomiclabs/hardhat-ethers" + - "@nomicfoundation/hardhat-ethers" - "@nomicfoundation/hardhat-verify" - "@nomicfoundation/hardhat-foundry" - "@nomiclabs/hardhat-vyper" diff --git a/docs/src/content/hardhat-runner/plugins/plugins.ts b/docs/src/content/hardhat-runner/plugins/plugins.ts index 63373b11ad..370d9bc5cc 100644 --- a/docs/src/content/hardhat-runner/plugins/plugins.ts +++ b/docs/src/content/hardhat-runner/plugins/plugins.ts @@ -800,7 +800,7 @@ const officialPlugins: IPlugin[] = [ tags: ["Chai", "Testing"], }, { - name: "@nomiclabs/hardhat-ethers", + name: "@nomicfoundation/hardhat-ethers", author: "Nomic Foundation", authorUrl: "https://twitter.com/NomicFoundation", description: "Injects ethers.js into the Hardhat Runtime Environment", diff --git a/docs/src/content/tutorial/creating-a-new-hardhat-project.md b/docs/src/content/tutorial/creating-a-new-hardhat-project.md index b5323742c5..b269436fe1 100644 --- a/docs/src/content/tutorial/creating-a-new-hardhat-project.md +++ b/docs/src/content/tutorial/creating-a-new-hardhat-project.md @@ -142,7 +142,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox :::tab{value="npm 6"} ``` -npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: @@ -150,7 +150,7 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat :::tab{value=yarn} ``` -yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers +yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 ``` ::: diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index 725dc2ce41..d6bac1b957 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -4,7 +4,7 @@ Writing automated tests when building smart contracts is of crucial importance, To test our contract, we are going to use Hardhat Network, a local Ethereum network designed for development. It comes built-in with Hardhat, and it's used as the default network. You don't need to setup anything to use it. -In our tests we're going to use [ethers.js](https://docs.ethers.io/v5/) to interact with the Ethereum contract we built in the previous section, and we'll use [Mocha](https://mochajs.org/) as our test runner. +In our tests we're going to use [ethers.js](https://docs.ethers.io/v6/) to interact with the Ethereum contract we built in the previous section, and we'll use [Mocha](https://mochajs.org/) as our test runner. ## Writing tests @@ -55,7 +55,7 @@ const { ethers } = require("hardhat"); :::tip -To learn more about `Signer`, you can look at the [Signers documentation](https://docs.ethers.io/v5/api/signer/). +To learn more about `Signer`, you can look at the [Signers documentation](https://docs.ethers.org/v6/api/providers/#Signer). ::: From 236c8a2ab0f53bbbab3c0e6033c88e174040ba84 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:29:08 +0200 Subject: [PATCH 61/95] Update ethers docs URLs --- .../docs/advanced/create-task.md | 2 +- .../advanced/hardhat-runtime-environment.md | 2 +- .../docs/getting-started/index.md | 2 +- .../docs/guides/project-setup.md | 2 +- .../docs/guides/test-contracts.md | 2 +- .../docs/other-guides/waffle-testing.md | 2 +- docs/src/content/tutorial/final-thoughts.md | 2 +- .../src/content/tutorial/testing-contracts.md | 2 +- packages/hardhat-ethers/README.md | 19 ++++++------------- packages/hardhat-toolbox/README.md | 2 +- packages/hardhat-verify/README.md | 2 +- 11 files changed, 16 insertions(+), 23 deletions(-) diff --git a/docs/src/content/hardhat-runner/docs/advanced/create-task.md b/docs/src/content/hardhat-runner/docs/advanced/create-task.md index a1d29b3884..f2b571d995 100644 --- a/docs/src/content/hardhat-runner/docs/advanced/create-task.md +++ b/docs/src/content/hardhat-runner/docs/advanced/create-task.md @@ -48,7 +48,7 @@ Let’s go through the process of creating one to interact with a smart contract Tasks in Hardhat are asynchronous JavaScript functions that get access to the [Hardhat Runtime Environment](../advanced/hardhat-runtime-environment.md), which exposes its configuration and parameters, as well as programmatic access to other tasks and any plugin objects that may have been injected. -For our example, we will use the [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox), which includes the [ethers.js](https://docs.ethers.io/) library to interact with our contracts. +For our example, we will use the [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox), which includes the [ethers.js](https://docs.ethers.org/v6/) library to interact with our contracts. ::::tabsgroup{options="npm 7+,npm 6,yarn"} diff --git a/docs/src/content/hardhat-runner/docs/advanced/hardhat-runtime-environment.md b/docs/src/content/hardhat-runner/docs/advanced/hardhat-runtime-environment.md index 6f9d550920..9902915702 100644 --- a/docs/src/content/hardhat-runner/docs/advanced/hardhat-runtime-environment.md +++ b/docs/src/content/hardhat-runner/docs/advanced/hardhat-runtime-environment.md @@ -51,7 +51,7 @@ This way, tests written for Hardhat are just normal Mocha tests. This enables yo The HRE only provides the core functionality that users and plugin developers need to start building on top of Hardhat. Using it to interface directly with Ethereum in your project can be somewhat harder than expected. -Everything gets easier when you use higher-level libraries, like [Ethers.js](https://docs.ethers.io/) or [ethereum-waffle](https://www.npmjs.com/package/ethereum-waffle), but these libraries need some initialization to work, and that could get repetitive. +Everything gets easier when you use higher-level libraries, like [Ethers.js](https://docs.ethers.org/v6/) or [ethereum-waffle](https://www.npmjs.com/package/ethereum-waffle), but these libraries need some initialization to work, and that could get repetitive. Hardhat lets you hook into the HRE construction, and extend it with new functionality. This way, you only have to initialize everything once, and your new features or libraries will be available everywhere the HRE is used. diff --git a/docs/src/content/hardhat-runner/docs/getting-started/index.md b/docs/src/content/hardhat-runner/docs/getting-started/index.md index 6e28b34472..a17a00ab47 100644 --- a/docs/src/content/hardhat-runner/docs/getting-started/index.md +++ b/docs/src/content/hardhat-runner/docs/getting-started/index.md @@ -150,7 +150,7 @@ If you created a TypeScript project, this task will also generate TypeScript bin ### Testing your contracts -Your project comes with tests that use [Mocha](https://mochajs.org), [Chai](https://www.chaijs.com), and [Ethers.js](https://docs.ethers.io/v6). +Your project comes with tests that use [Mocha](https://mochajs.org), [Chai](https://www.chaijs.com), and [Ethers.js](https://docs.ethers.org/v6/). If you take a look in the `test/` folder, you'll see a test file: diff --git a/docs/src/content/hardhat-runner/docs/guides/project-setup.md b/docs/src/content/hardhat-runner/docs/guides/project-setup.md index b503ad9218..4ae4c45da1 100644 --- a/docs/src/content/hardhat-runner/docs/guides/project-setup.md +++ b/docs/src/content/hardhat-runner/docs/guides/project-setup.md @@ -128,7 +128,7 @@ When it comes to testing your contracts, the sample project comes with some usef - The built-in [Hardhat Network](/hardhat-network/docs) as the development network to test on, along with the [Hardhat Network Helpers](/hardhat-network-helpers) library to manipulate this network. - [Mocha](https://mochajs.org/) as the test runner, [Chai](https://chaijs.com/) as the assertion library, and the [Hardhat Chai Matchers](/hardhat-chai-matchers) to extend Chai with contracts-related functionality. -- The [`ethers.js`](https://docs.ethers.io/v6/) library to interact with the network and with contracts. +- The [`ethers.js`](https://docs.ethers.org/v6/) library to interact with the network and with contracts. As well as other useful plugins. You can learn more about this in the [Testing contracts guide](./test-contracts.md). diff --git a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md index d400ade784..f94565a44e 100644 --- a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md +++ b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md @@ -2,7 +2,7 @@ After [compiling your contracts](./compile-contracts.md), the next step is to write some tests to verify that they work as intended. -This guide explains our recommended approach for testing contracts in Hardhat. It relies on [ethers](https://docs.ethers.io/v6/) to connect to [Hardhat Network](/hardhat-network) and on [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for the tests. It also uses our custom [Chai matchers](/hardhat-chai-matchers) and our [Hardhat Network Helpers](/hardhat-network-helpers) to make it easier to write clean test code. These packages are part of the Hardhat Toolbox plugin; if you followed the previous guides, you should already have them installed. +This guide explains our recommended approach for testing contracts in Hardhat. It relies on [ethers](https://docs.ethers.org/v6/) to connect to [Hardhat Network](/hardhat-network) and on [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for the tests. It also uses our custom [Chai matchers](/hardhat-chai-matchers) and our [Hardhat Network Helpers](/hardhat-network-helpers) to make it easier to write clean test code. These packages are part of the Hardhat Toolbox plugin; if you followed the previous guides, you should already have them installed. While this is our recommended test setup, Hardhat is flexible: you can customize the approach or take a completely different path with other tools. diff --git a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md index b61966219f..b89a4c76c9 100644 --- a/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md +++ b/docs/src/content/hardhat-runner/docs/other-guides/waffle-testing.md @@ -8,7 +8,7 @@ Read [this guide](/hardhat-runner/docs/guides/test-contracts.md) to learn about Writing smart contract tests in Hardhat is done using JavaScript or TypeScript. -In this guide, we'll show you how to use [Ethers.js](https://docs.ethers.io/), a JavaScript library to interact with Ethereum, and [Waffle](https://getwaffle.io/) a simple smart contract testing library built on top of it. +In this guide, we'll show you how to use [Ethers.js](https://docs.ethers.org/v6/), a JavaScript library to interact with Ethereum, and [Waffle](https://getwaffle.io/) a simple smart contract testing library built on top of it. Let's see how to use it starting from an empty Hardhat project. diff --git a/docs/src/content/tutorial/final-thoughts.md b/docs/src/content/tutorial/final-thoughts.md index 419b85a365..bda100dde5 100644 --- a/docs/src/content/tutorial/final-thoughts.md +++ b/docs/src/content/tutorial/final-thoughts.md @@ -8,7 +8,7 @@ Here are some links you might find useful throughout your journey: - [Hardhat's documentation site](/docs/) - [Hardhat Toolbox's documentation](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) - [Hardhat Support Discord server](/discord) -- [Ethers.js Documentation](https://docs.ethers.io/) +- [Ethers.js Documentation](https://docs.ethers.org/v6/) - [Mocha Documentation](https://mochajs.org/) - [Chai Documentation](https://www.chaijs.com/) - [Alchemy's smart contract tutorial](https://docs.alchemy.com/docs/hello-world-smart-contract) to also learn how to use Metamask and Solidity as well as an RPC endpoint like the one that Alchemy provides. diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index d6bac1b957..30d21f75a3 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -4,7 +4,7 @@ Writing automated tests when building smart contracts is of crucial importance, To test our contract, we are going to use Hardhat Network, a local Ethereum network designed for development. It comes built-in with Hardhat, and it's used as the default network. You don't need to setup anything to use it. -In our tests we're going to use [ethers.js](https://docs.ethers.io/v6/) to interact with the Ethereum contract we built in the previous section, and we'll use [Mocha](https://mochajs.org/) as our test runner. +In our tests we're going to use [ethers.js](https://docs.ethers.org/v6/) to interact with the Ethereum contract we built in the previous section, and we'll use [Mocha](https://mochajs.org/) as our test runner. ## Writing tests diff --git a/packages/hardhat-ethers/README.md b/packages/hardhat-ethers/README.md index e86c62c4b4..47f8f973fa 100644 --- a/packages/hardhat-ethers/README.md +++ b/packages/hardhat-ethers/README.md @@ -11,7 +11,7 @@ This plugin brings to Hardhat the Ethereum library `ethers.js`, which allows you ## Installation ```bash -npm install --save-dev @nomicfoundation/hardhat-ethers 'ethers@^5.0.0' +npm install --save-dev @nomicfoundation/hardhat-ethers ethers ``` And add the following statement to your `hardhat.config.js`: @@ -34,11 +34,11 @@ This plugin creates no additional tasks. This plugins adds an `ethers` object to the Hardhat Runtime Environment. -This object has the [same API](https://docs.ethers.io/v5/single-page/) as `ethers.js`, with some extra Hardhat-specific functionality. +This object has the [same API](https://docs.ethers.org/v6/single-page/) as `ethers.js`, with some extra Hardhat-specific functionality. ### Provider object -A `provider` field is added to `ethers`, which is an [`ethers.providers.Provider`](https://docs.ethers.io/v5/single-page/#/v5/api/providers/provider/) automatically connected to the selected network. +A `provider` field is added to `ethers`, which is an [`ethers.Provider`](https://docs.ethers.org/v6/single-page/#api_providers__Provider) automatically connected to the selected network. ### Helpers @@ -79,9 +79,7 @@ function getContractFactoryFromArtifact(artifact: Artifact, factoryOptions: Fact function getContractAtFromArtifact(artifact: Artifact, address: string, signer?: ethers.Signer): Promise; ``` -The [`Contract`s](https://docs.ethers.io/v5/single-page/#/v5/api/contract/contract/) and [`ContractFactory`s](https://docs.ethers.io/v5/single-page/#/v5/api/contract/contract-factory/) returned by these helpers are connected to the first [signer](https://docs.ethers.io/v5/single-page/#/v5/api/signer/) returned by `getSigners` by default. - -If there is no signer available, `getContractAt` returns [read-only](https://docs.ethers.io/v5/single-page/#/v5/api/contract/contract/-%23-Contract--readonly) contracts. +The [`Contract`s](https://docs.ethers.org/v6/single-page/#api_contract__Contract) and [`ContractFactory`s](https://docs.ethers.org/v6/single-page/#api_contract__ContractFactory) returned by these helpers are connected to the first [signer](https://docs.ethers.org/v6/single-page/#api_providers__Signer) returned by `getSigners` by default. ## Usage @@ -97,9 +95,8 @@ task( "blockNumber", "Prints the current block number", async (_, { ethers }) => { - await ethers.provider.getBlockNumber().then((blockNumber) => { - console.log("Current block number: " + blockNumber); - }); + const blockNumber = await ethers.provider.getBlockNumber(); + console.log("Current block number: " + blockNumber); } ); @@ -133,7 +130,3 @@ To create a contract factory, all libraries must be linked. An error will be thr Ethers.js polls the network to check if some event was emitted (except when a `WebSocketProvider` is used; see below). This polling is done every 4 seconds. If you have a script or test that is not emitting an event, it's likely that the execution is finishing before the event is detected by the polling mechanism. If you are connecting to a Hardhat node using a `WebSocketProvider`, events should be emitted immediately. But keep in mind that you'll have to create this provider manually, since Hardhat only supports configuring networks via http. That is, you can't add a `localhost` network with a URL like `ws://127.0.0.1:8545`. - -### Gas transaction parameters in `hardhat.config` are not used - -When using this plugin, the `gas`, `gasPrice` and `gasMultiplier` parameters from your `hardhat.config` are not automatically applied to transactions. In order to provide such values to your transactions, specify them as [overrides](https://docs.ethers.io/v5/single-page/#/v5/api/contract/contract/-%23-contract-functionsSend) on the transaction itself. diff --git a/packages/hardhat-toolbox/README.md b/packages/hardhat-toolbox/README.md index 0ed50f6b6b..35ede2a1fb 100644 --- a/packages/hardhat-toolbox/README.md +++ b/packages/hardhat-toolbox/README.md @@ -6,7 +6,7 @@ The `@nomicfoundation/hardhat-toolbox` plugin bundles all the commonly used pack When you use this plugin, you'll be able to: -- Deploy and interact with your contracts using [ethers.js](https://docs.ethers.io/v5/) and the [`hardhat-ethers`](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers) plugin. +- Deploy and interact with your contracts using [ethers.js](https://docs.ethers.org/v6/) and the [`hardhat-ethers`](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers) plugin. - Test your contracts with [Mocha](https://mochajs.org/), [Chai](https://chaijs.com/) and our own [Hardhat Chai Matchers](https://hardhat.org/hardhat-chai-matchers) plugin. - Interact with Hardhat Network with our [Hardhat Network Helpers](https://hardhat.org/hardhat-network-helpers). - Verify the source code of your contracts with the [hardhat-etherscan](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-etherscan) plugin. diff --git a/packages/hardhat-verify/README.md b/packages/hardhat-verify/README.md index 350c3049d9..4572cd66d6 100644 --- a/packages/hardhat-verify/README.md +++ b/packages/hardhat-verify/README.md @@ -68,7 +68,7 @@ npx hardhat verify --network mainnet DEPLOYED_CONTRACT_ADDRESS "Constructor argu ### Complex arguments -When the constructor has a complex argument list, you'll need to write a javascript module that exports the argument list. The expected format is the same as a constructor list for an [ethers contract](https://docs.ethers.io/v5/api/contract/). For example, if you have a contract like this: +When the constructor has a complex argument list, you'll need to write a javascript module that exports the argument list. The expected format is the same as a constructor list for an [ethers contract](https://docs.ethers.org/v6/single-page/#api_contract__Contract). For example, if you have a contract like this: ```solidity struct Point { From f9382fe74ddf2a7189ce0c71b3e0fef5ba06d7ec Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:30:33 +0200 Subject: [PATCH 62/95] Remove unnecessary dependency in chai matchers --- packages/hardhat-chai-matchers/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index 7bc0a965b6..9fc2930747 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -68,7 +68,6 @@ "hardhat": "^2.9.4" }, "dependencies": { - "@ethersproject/abi": "^5.1.2", "@types/chai-as-promised": "^7.1.3", "chai-as-promised": "^7.1.1", "deep-eql": "^4.0.1", From 26f240ebff27a67be4c8711bd8f6b67420ce1884 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:35:34 +0200 Subject: [PATCH 63/95] Remove commented out code in vendored utils --- .../src/internal/ethers-utils.ts | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/packages/hardhat-ethers/src/internal/ethers-utils.ts b/packages/hardhat-ethers/src/internal/ethers-utils.ts index ad83009d0c..68cd19c3f9 100644 --- a/packages/hardhat-ethers/src/internal/ethers-utils.ts +++ b/packages/hardhat-ethers/src/internal/ethers-utils.ts @@ -273,41 +273,6 @@ export function formatTransactionResponse( } } - // @TODO: check chainID - /* - if (value.chainId != null) { - let chainId = value.chainId; - - if (isHexString(chainId)) { - chainId = BigNumber.from(chainId).toNumber(); - } - - result.chainId = chainId; - - } else { - let chainId = value.networkId; - - // geth-etc returns chainId - if (chainId == null && result.v == null) { - chainId = value.chainId; - } - - if (isHexString(chainId)) { - chainId = BigNumber.from(chainId).toNumber(); - } - - if (typeof(chainId) !== "number" && result.v != null) { - chainId = (result.v - 35) / 2; - if (chainId < 0) { chainId = 0; } - chainId = parseInt(chainId); - } - - if (typeof(chainId) !== "number") { chainId = 0; } - - result.chainId = chainId; - } - */ - // 0x0000... should actually be null // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (result.blockHash && getBigInt(result.blockHash) === 0n) { From 168e937d12704085404fbfcea41d08bba2d26902 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:37:18 +0200 Subject: [PATCH 64/95] Remove remaining BigNumber mentions/usages --- docs/src/content/hardhat-chai-matchers/docs/overview.md | 4 ++-- packages/hardhat-chai-matchers/test/bigNumber.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/content/hardhat-chai-matchers/docs/overview.md b/docs/src/content/hardhat-chai-matchers/docs/overview.md index 9f52cb8220..131ecd0500 100644 --- a/docs/src/content/hardhat-chai-matchers/docs/overview.md +++ b/docs/src/content/hardhat-chai-matchers/docs/overview.md @@ -90,8 +90,8 @@ This package provides the predicates `anyValue` and `anyUint`, but you can easil ```js -function isEven(x: BigNumber): boolean { - return x.mod(2).isZero(); +function isEven(x: bigint): boolean { + return x % 2n === 0n; } await expect(contract.emitUint(2)) diff --git a/packages/hardhat-chai-matchers/test/bigNumber.ts b/packages/hardhat-chai-matchers/test/bigNumber.ts index 7adb08c353..f60f967534 100644 --- a/packages/hardhat-chai-matchers/test/bigNumber.ts +++ b/packages/hardhat-chai-matchers/test/bigNumber.ts @@ -874,7 +874,7 @@ describe("BigNumber matchers", function () { // We are not checking the content of the arrays/objects because // it depends on the type of the numbers (plain numbers, native - // bigints, ethers's BigNumbers) + // bigints) // Ideally the output would be normalized and we could check the // actual content more easily. From cbbd0bdd8feda908499032295af781c03fb70dcc Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:37:59 +0200 Subject: [PATCH 65/95] Undo package.json version change --- packages/hardhat-toolbox/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 12667910bc..d135742fd1 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-toolbox", - "version": "3.0.0", + "version": "2.0.2", "description": "Nomic Foundation's recommended bundle of Hardhat plugins", "repository": "github:nomicfoundation/hardhat", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-toolbox", From 70c2ccf124a37b956723ab5ed98dedcb98d62436 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:38:46 +0200 Subject: [PATCH 66/95] Create wet-keys-press.md --- .changeset/wet-keys-press.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wet-keys-press.md diff --git a/.changeset/wet-keys-press.md b/.changeset/wet-keys-press.md new file mode 100644 index 0000000000..4143edf340 --- /dev/null +++ b/.changeset/wet-keys-press.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-chai-matchers": patch +--- + +Removed unnecessary dependency From 399347f40cac9755f478f601fc4cdeb93e719e8d Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:40:10 +0200 Subject: [PATCH 67/95] Create twelve-adults-doubt.md --- .changeset/twelve-adults-doubt.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/twelve-adults-doubt.md diff --git a/.changeset/twelve-adults-doubt.md b/.changeset/twelve-adults-doubt.md new file mode 100644 index 0000000000..2f0017d5d3 --- /dev/null +++ b/.changeset/twelve-adults-doubt.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-toolbox": major +--- + +Use new plugin versions in the Toolbox From 99995d53bac0c64b5891a1151b0ae5c80cc666f2 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:43:02 +0200 Subject: [PATCH 68/95] Create unlucky-books-love.md --- .changeset/unlucky-books-love.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/unlucky-books-love.md diff --git a/.changeset/unlucky-books-love.md b/.changeset/unlucky-books-love.md new file mode 100644 index 0000000000..0c69ca491b --- /dev/null +++ b/.changeset/unlucky-books-love.md @@ -0,0 +1,5 @@ +--- +"hardhat": minor +--- + +The sample projects now use the new version of the Toolbox From a9c159f9602089aeb388789f47d4f74d9dc066ed Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:43:53 +0200 Subject: [PATCH 69/95] Create nervous-bees-hunt.md --- .changeset/nervous-bees-hunt.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nervous-bees-hunt.md diff --git a/.changeset/nervous-bees-hunt.md b/.changeset/nervous-bees-hunt.md new file mode 100644 index 0000000000..03ddcd3284 --- /dev/null +++ b/.changeset/nervous-bees-hunt.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-ethers": patch +--- + +The `helper.deployContract` now accepts transaction overrides From aaf2c920a43c1581c4958060ba073536eef2387c Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Tue, 6 Jun 2023 12:59:02 +0200 Subject: [PATCH 70/95] Fix @typechain/ethers-v6 version in project initialization --- packages/hardhat-core/src/internal/cli/project-creation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-core/src/internal/cli/project-creation.ts b/packages/hardhat-core/src/internal/cli/project-creation.ts index 4e0bd8bdd4..760d3c0d91 100644 --- a/packages/hardhat-core/src/internal/cli/project-creation.ts +++ b/packages/hardhat-core/src/internal/cli/project-creation.ts @@ -56,7 +56,7 @@ const PEER_DEPENDENCIES: Dependencies = { "solidity-coverage": "^0.8.0", "@typechain/hardhat": "^8.0.0", typechain: "^8.1.0", - "@typechain/ethers-v6": "^0.3.4", + "@typechain/ethers-v6": "^0.4.0", }; const TYPESCRIPT_DEPENDENCIES: Dependencies = {}; From 7775b5d8bc1403b101012247c84dd0a0599154de Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 15:56:28 +0200 Subject: [PATCH 71/95] Use dual tsconfig in toolbox --- packages/hardhat-toolbox/.gitignore | 4 ++++ packages/hardhat-toolbox/package.json | 9 +++++--- packages/hardhat-toolbox/src/tsconfig.json | 27 ++++++++++++++++++++++ packages/hardhat-toolbox/test/helpers.ts | 3 +++ packages/hardhat-toolbox/tsconfig.json | 21 +++++------------ 5 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 packages/hardhat-toolbox/src/tsconfig.json diff --git a/packages/hardhat-toolbox/.gitignore b/packages/hardhat-toolbox/.gitignore index c00d7e7296..88c7f760ad 100644 --- a/packages/hardhat-toolbox/.gitignore +++ b/packages/hardhat-toolbox/.gitignore @@ -4,6 +4,10 @@ # Compilation output /build-test/ /dist +/*.js +/*.js.map +/*.d.ts +/*.d.ts.map # Code coverage artifacts /coverage diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index d135742fd1..1730b9b661 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -9,8 +9,8 @@ "Nomic Foundation" ], "license": "MIT", - "main": "dist/src/index.js", - "types": "dist/src/index.d.ts", + "main": "index.js", + "types": "index.d.ts", "keywords": [ "ethereum", "smart-contracts", @@ -28,8 +28,11 @@ "clean": "rimraf dist" }, "files": [ - "dist/src/", "src/", + "*.d.ts", + "*.d.ts.map", + "*.js", + "*.js.map", "LICENSE", "README.md" ], diff --git a/packages/hardhat-toolbox/src/tsconfig.json b/packages/hardhat-toolbox/src/tsconfig.json new file mode 100644 index 0000000000..3c04a1ea5c --- /dev/null +++ b/packages/hardhat-toolbox/src/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../../config/typescript/tsconfig.json", + "compilerOptions": { + "outDir": "../", + "rootDirs": ["."], + "composite": true + }, + "include": ["./**/*.ts"], + "exclude": [], + "references": [ + { + "path": "../../hardhat-core/src" + }, + { + "path": "../../hardhat-chai-matchers" + }, + { + "path": "../../hardhat-network-helpers" + }, + { + "path": "../../hardhat-ethers/src" + }, + { + "path": "../../hardhat-verify" + } + ] +} diff --git a/packages/hardhat-toolbox/test/helpers.ts b/packages/hardhat-toolbox/test/helpers.ts index e1b159efe3..4fc372b905 100644 --- a/packages/hardhat-toolbox/test/helpers.ts +++ b/packages/hardhat-toolbox/test/helpers.ts @@ -1,3 +1,6 @@ +// load the environment type extensions from the plugins +import type {} from "../src/index"; + import { resetHardhatContext } from "hardhat/plugins-testing"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import path from "path"; diff --git a/packages/hardhat-toolbox/tsconfig.json b/packages/hardhat-toolbox/tsconfig.json index fd844c410b..65ecfc33b9 100644 --- a/packages/hardhat-toolbox/tsconfig.json +++ b/packages/hardhat-toolbox/tsconfig.json @@ -1,24 +1,15 @@ { "extends": "../../config/typescript/tsconfig.json", "compilerOptions": { - "outDir": "./dist" + "outDir": "./build-test", + "rootDirs": ["./test"], + "composite": true }, - "exclude": ["./dist", "./node_modules", "./test/**/hardhat.config.ts"], + "include": ["./test/**/*.ts"], + "exclude": ["./node_modules", "./test/**/hardhat.config.ts"], "references": [ { - "path": "../hardhat-core/src" - }, - { - "path": "../hardhat-chai-matchers" - }, - { - "path": "../hardhat-network-helpers" - }, - { - "path": "../hardhat-ethers/src" - }, - { - "path": "../hardhat-verify" + "path": "./src" } ] } From e584f6a49f61f9d8d0a58517d33854250cda4198 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 15:56:38 +0200 Subject: [PATCH 72/95] Re-export network helpers in toolbox --- packages/hardhat-toolbox/src/network-helpers.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/hardhat-toolbox/src/network-helpers.ts diff --git a/packages/hardhat-toolbox/src/network-helpers.ts b/packages/hardhat-toolbox/src/network-helpers.ts new file mode 100644 index 0000000000..71747baddc --- /dev/null +++ b/packages/hardhat-toolbox/src/network-helpers.ts @@ -0,0 +1 @@ +export * from "@nomicfoundation/hardhat-network-helpers"; From 9d900ce0e191a9c8fa1b22903ea2a948f34b8a65 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 16:40:06 +0200 Subject: [PATCH 73/95] Use toolbox/network-helpers in docs --- .../hardhat-network/docs/guides/forking-other-networks.md | 4 ++-- .../content/hardhat-runner/docs/guides/test-contracts.md | 6 +++--- docs/src/content/tutorial/testing-contracts.md | 4 ++-- .../sample-projects/javascript-esm/test/Lock.js | 5 ++++- .../hardhat-core/sample-projects/javascript/test/Lock.js | 2 +- .../hardhat-core/sample-projects/typescript/test/Lock.ts | 5 ++++- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/src/content/hardhat-network/docs/guides/forking-other-networks.md b/docs/src/content/hardhat-network/docs/guides/forking-other-networks.md index e987e66e87..af7402898f 100644 --- a/docs/src/content/hardhat-network/docs/guides/forking-other-networks.md +++ b/docs/src/content/hardhat-network/docs/guides/forking-other-networks.md @@ -167,7 +167,7 @@ await impersonatedSigner.sendTransaction(...); Alternatively, you can use the [`impersonateAccount`]() helper and then obtain the signer for that address: ```js -const helpers = require("@nomicfoundation/hardhat-network-helpers"); +const helpers = require("@nomicfoundation/hardhat-toolbox/network-helpers"); const address = "0x1234567890123456789012345678901234567890"; await helpers.impersonateAccount(address); @@ -183,7 +183,7 @@ Once you've got a local instance of the mainnet chain state, setting that state You can reset the network with the [`reset`]() network helper: ```js -const helpers = require("@nomicfoundation/hardhat-network-helpers"); +const helpers = require("@nomicfoundation/hardhat-toolbox/network-helpers"); await helpers.reset(url, blockNumber); ``` diff --git a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md index f94565a44e..f967343d76 100644 --- a/docs/src/content/hardhat-runner/docs/guides/test-contracts.md +++ b/docs/src/content/hardhat-runner/docs/guides/test-contracts.md @@ -27,7 +27,7 @@ For our first test we’ll deploy the `Lock` contract and assert that the unlock ```tsx import { expect } from "chai"; import hre from "hardhat"; -import { time } from "@nomicfoundation/hardhat-network-helpers"; +import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; describe("Lock", function () { it("Should set the right unlockTime", async function () { @@ -54,7 +54,7 @@ describe("Lock", function () { ```js const { expect } = require("chai"); const hre = require("hardhat"); -const { time } = require("@nomicfoundation/hardhat-network-helpers"); +const { time } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Lock", function () { it("Should set the right unlockTime", async function () { @@ -228,7 +228,7 @@ const hre = require("hardhat"); const { loadFixture, time, -} = require("@nomicfoundation/hardhat-network-helpers"); +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Lock", function () { async function deployOneYearLockFixture() { diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index 30d21f75a3..bb05e7e5e8 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -114,7 +114,7 @@ The two tests that we wrote begin with their setup, which in this case means dep You can avoid code duplication and improve the performance of your test suite by using **fixtures**. A fixture is a setup function that is run only the first time it's invoked. On subsequent invocations, instead of re-running it, Hardhat will reset the state of the network to what it was at the point after the fixture was initially executed. ```js -const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers"); +const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); const { expect } = require("chai"); describe("Token contract", function () { @@ -171,7 +171,7 @@ const { expect } = require("chai"); // We use `loadFixture` to share common setups (or fixtures) between tests. // Using this simplifies your tests and makes them run faster, by taking // advantage of Hardhat Network's snapshot functionality. -const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers"); +const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); // `describe` is a Mocha function that allows you to organize your tests. // Having your tests organized makes debugging them easier. All Mocha diff --git a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js index 1d192fe850..e5ba3d8fcd 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js @@ -1,4 +1,7 @@ -import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { + time, + loadFixture, +} from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs.js"; import { expect } from "chai"; diff --git a/packages/hardhat-core/sample-projects/javascript/test/Lock.js b/packages/hardhat-core/sample-projects/javascript/test/Lock.js index ce4a74e4f1..f0e6ba1b2c 100644 --- a/packages/hardhat-core/sample-projects/javascript/test/Lock.js +++ b/packages/hardhat-core/sample-projects/javascript/test/Lock.js @@ -1,7 +1,7 @@ const { time, loadFixture, -} = require("@nomicfoundation/hardhat-network-helpers"); +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); const { expect } = require("chai"); diff --git a/packages/hardhat-core/sample-projects/typescript/test/Lock.ts b/packages/hardhat-core/sample-projects/typescript/test/Lock.ts index 6e0300bf24..a6e866b400 100644 --- a/packages/hardhat-core/sample-projects/typescript/test/Lock.ts +++ b/packages/hardhat-core/sample-projects/typescript/test/Lock.ts @@ -1,4 +1,7 @@ -import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { + time, + loadFixture, +} from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs"; import { expect } from "chai"; import { ethers } from "hardhat"; From 64b0fc5c6f7c7242081b6d0d0db5c17e4f8be733 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 18:19:12 +0200 Subject: [PATCH 74/95] Fix mentions to hh-etherscan --- .github/workflows/hardhat-toolbox-ci.yml | 4 ++-- packages/hardhat-toolbox/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/hardhat-toolbox-ci.yml b/.github/workflows/hardhat-toolbox-ci.yml index a41ddca032..d87d249cd6 100644 --- a/.github/workflows/hardhat-toolbox-ci.yml +++ b/.github/workflows/hardhat-toolbox-ci.yml @@ -9,7 +9,7 @@ on: - "packages/hardhat-chai-matchers/**" - "packages/hardhat-network-helpers/**" - "packages/hardhat-ethers/**" - - "packages/hardhat-etherscan/**" + - "packages/hardhat-verify/**" - "packages/hardhat-common/**" - "config/**" pull_request: @@ -21,7 +21,7 @@ on: - "packages/hardhat-chai-matchers/**" - "packages/hardhat-network-helpers/**" - "packages/hardhat-ethers/**" - - "packages/hardhat-etherscan/**" + - "packages/hardhat-verify/**" - "packages/hardhat-common/**" - "config/**" diff --git a/packages/hardhat-toolbox/README.md b/packages/hardhat-toolbox/README.md index 35ede2a1fb..7b243a4a47 100644 --- a/packages/hardhat-toolbox/README.md +++ b/packages/hardhat-toolbox/README.md @@ -9,7 +9,7 @@ When you use this plugin, you'll be able to: - Deploy and interact with your contracts using [ethers.js](https://docs.ethers.org/v6/) and the [`hardhat-ethers`](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers) plugin. - Test your contracts with [Mocha](https://mochajs.org/), [Chai](https://chaijs.com/) and our own [Hardhat Chai Matchers](https://hardhat.org/hardhat-chai-matchers) plugin. - Interact with Hardhat Network with our [Hardhat Network Helpers](https://hardhat.org/hardhat-network-helpers). -- Verify the source code of your contracts with the [hardhat-etherscan](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-etherscan) plugin. +- Verify the source code of your contracts with the [hardhat-verify](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify) plugin. - Get metrics on the gas used by your contracts with the [hardhat-gas-reporter](https://github.com/cgewecke/hardhat-gas-reporter) plugin. - Measure your tests coverage with [solidity-coverage](https://github.com/sc-forks/solidity-coverage). - And, if you are using TypeScript, get type bindings for your contracts with [Typechain](https://github.com/dethcrypto/TypeChain/). From 5432aa37b6683ed371906681db83ca8719c08ba2 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 18:47:13 +0200 Subject: [PATCH 75/95] Add explanation about network helpers in the toolbox --- packages/hardhat-toolbox/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/hardhat-toolbox/README.md b/packages/hardhat-toolbox/README.md index 7b243a4a47..8c0a42d0bf 100644 --- a/packages/hardhat-toolbox/README.md +++ b/packages/hardhat-toolbox/README.md @@ -19,3 +19,12 @@ When you use this plugin, you'll be able to: To create a new project that uses the Toolbox, check our [Setting up a project guide](https://hardhat.org/hardhat-runner/docs/guides/project-setup). If you want to migrate an existing Hardhat project to use the Toolbox, read [our migration guide](https://hardhat.org/hardhat-runner/docs/guides/migrating-from-hardhat-waffle). + +### Network Helpers + +When the Toolbox is installed using npm 7 or later, its peer dependencies are automatically installed. However, these dependencies won't be listed in the `package.json`. As a result, directly importing the Network Helpers can be problematic for certain tools or IDEs. +To address this issue, the Toolbox re-exports the Hardhat Network Helpers. You can use them like this: + +```ts +import helpers from "@nomicfoundation/hardhat-toolbox/network-helpers"; +``` From 9e2554e7ffa6bf47adbc46abaa96d0ef8c1867a0 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 18:52:56 +0200 Subject: [PATCH 76/95] Add basic tests for deployContract overrides --- packages/hardhat-ethers/test/index.ts | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/hardhat-ethers/test/index.ts b/packages/hardhat-ethers/test/index.ts index 102aea5055..0f417dc746 100644 --- a/packages/hardhat-ethers/test/index.ts +++ b/packages/hardhat-ethers/test/index.ts @@ -937,6 +937,40 @@ describe("Ethers plugin", function () { assert(await contract.greet(), "Hello"); }); + it("should accept overrides for the deployment transaction", async function () { + const contract = await this.env.ethers.deployContract("Greeter", { + gasLimit: 1_000_000, + }); + + await assertContract(contract, signers[0]); + + const deploymentTx = contract.deploymentTransaction(); + if (deploymentTx === null) { + assert.fail("Deployment transaction shouldn't be null"); + } + + assert.equal(deploymentTx.gasLimit, 1_000_000n); + }); + + it("should accept overrides for the deployment transaction when there are constructor args", async function () { + const contract = await this.env.ethers.deployContract( + "GreeterWithConstructorArg", + ["Hello"], + { + gasLimit: 1_000_000, + } + ); + + await assertContract(contract, signers[0]); + + const deploymentTx = contract.deploymentTransaction(); + if (deploymentTx === null) { + assert.fail("Deployment transaction shouldn't be null"); + } + + assert.equal(deploymentTx.gasLimit, 1_000_000n); + }); + async function assertContract( contract: EthersT.Contract, signer: HardhatEthersSigner From 1409b0a14f556cecf2acea45dc7be1e2b2043e42 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 19:00:41 +0200 Subject: [PATCH 77/95] Improve implementation of deployContract overrides --- .../hardhat-ethers/src/internal/helpers.ts | 35 ++++--------------- packages/hardhat-ethers/test/type-tests.ts | 13 +++++++ 2 files changed, 19 insertions(+), 29 deletions(-) create mode 100644 packages/hardhat-ethers/test/type-tests.ts diff --git a/packages/hardhat-ethers/src/internal/helpers.ts b/packages/hardhat-ethers/src/internal/helpers.ts index 4cfcde5917..bd3bc89ff2 100644 --- a/packages/hardhat-ethers/src/internal/helpers.ts +++ b/packages/hardhat-ethers/src/internal/helpers.ts @@ -371,37 +371,14 @@ export async function deployContract( let overrides: EthersT.Overrides = {}; if (signerOrOptions !== undefined && !("getAddress" in signerOrOptions)) { - // the DeployContractOptions type combines the properties of FactoryOptions - // and of EthersT.Overrides, but we only want to use the latter. - // - // This seems to be the type-safest way to extract only those. - const overridesExplicitProperties: { - [K in keyof Required]: EthersT.Overrides[K]; - } = { - type: signerOrOptions.type, + const overridesAndFactoryOptions = { ...signerOrOptions }; - from: signerOrOptions.from, + // we delete the factory options properties in case ethers + // rejects unknown properties + delete overridesAndFactoryOptions.signer; + delete overridesAndFactoryOptions.libraries; - nonce: signerOrOptions.nonce, - - gasLimit: signerOrOptions.gasLimit, - gasPrice: signerOrOptions.gasPrice, - - maxPriorityFeePerGas: signerOrOptions.maxPriorityFeePerGas, - maxFeePerGas: signerOrOptions.maxFeePerGas, - - value: signerOrOptions.value, - chainId: signerOrOptions.chainId, - - accessList: signerOrOptions.accessList, - - customData: signerOrOptions.customData, - - blockTag: signerOrOptions.blockTag, - enableCcipRead: signerOrOptions.enableCcipRead, - }; - - overrides = overridesExplicitProperties; + overrides = overridesAndFactoryOptions; } const factory = await getContractFactory(hre, name, signerOrOptions); diff --git a/packages/hardhat-ethers/test/type-tests.ts b/packages/hardhat-ethers/test/type-tests.ts new file mode 100644 index 0000000000..0fe9ce754d --- /dev/null +++ b/packages/hardhat-ethers/test/type-tests.ts @@ -0,0 +1,13 @@ +import { FactoryOptions } from "../src/types"; + +// FactoryOptions shouldn't have mandatory properties +const _factoryOptions: FactoryOptions = {}; + +// FactoryOptions only has these two properties. +// If new ones are added, then the deployContract +// implementation should be updated to also delete +// those new extra properties +const _factoryOptionsRequired: Required = { + signer: null as any, + libraries: null as any, +}; From 1b5e1cf601f4c9b686d8d501c74985bc0cd7867b Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 19:05:57 +0200 Subject: [PATCH 78/95] Fix linter in toolbox --- packages/hardhat-toolbox/.eslintrc.js | 2 +- packages/hardhat-toolbox/.prettierignore | 5 +++++ packages/hardhat-toolbox/README.md | 3 +-- packages/hardhat-toolbox/package.json | 2 +- packages/hardhat-toolbox/test/.eslintrc.js | 15 +++++++++++++++ 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 packages/hardhat-toolbox/test/.eslintrc.js diff --git a/packages/hardhat-toolbox/.eslintrc.js b/packages/hardhat-toolbox/.eslintrc.js index 889740f226..44ed8ed6d5 100644 --- a/packages/hardhat-toolbox/.eslintrc.js +++ b/packages/hardhat-toolbox/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { extends: [`${__dirname}/../../config/eslint/eslintrc.js`], parserOptions: { - project: `${__dirname}/tsconfig.json`, + project: `${__dirname}/src/tsconfig.json`, sourceType: "module", }, }; diff --git a/packages/hardhat-toolbox/.prettierignore b/packages/hardhat-toolbox/.prettierignore index 12cbe6bee7..d9f2c83183 100644 --- a/packages/hardhat-toolbox/.prettierignore +++ b/packages/hardhat-toolbox/.prettierignore @@ -3,4 +3,9 @@ /test/fixture-projects/**/artifacts /test/fixture-projects/**/artifacts-dir /test/fixture-projects/**/cache +/*.d.ts +/*.d.ts.map +/*.js +/*.js.map +/build-test CHANGELOG.md diff --git a/packages/hardhat-toolbox/README.md b/packages/hardhat-toolbox/README.md index 8c0a42d0bf..eb8bd4d0fe 100644 --- a/packages/hardhat-toolbox/README.md +++ b/packages/hardhat-toolbox/README.md @@ -22,8 +22,7 @@ If you want to migrate an existing Hardhat project to use the Toolbox, read [our ### Network Helpers -When the Toolbox is installed using npm 7 or later, its peer dependencies are automatically installed. However, these dependencies won't be listed in the `package.json`. As a result, directly importing the Network Helpers can be problematic for certain tools or IDEs. -To address this issue, the Toolbox re-exports the Hardhat Network Helpers. You can use them like this: +When the Toolbox is installed using npm 7 or later, its peer dependencies are automatically installed. However, these dependencies won't be listed in the `package.json`. As a result, directly importing the Network Helpers can be problematic for certain tools or IDEs. To address this issue, the Toolbox re-exports the Hardhat Network Helpers. You can use them like this: ```ts import helpers from "@nomicfoundation/hardhat-toolbox/network-helpers"; diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 1730b9b661..7742e6ca1f 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -25,7 +25,7 @@ "test": "mocha --recursive \"test/**/*.ts\" --exit", "build": "tsc --build .", "prepublishOnly": "yarn build", - "clean": "rimraf dist" + "clean": "rimraf dist *.{d.ts,js}{,.map} build-test tsconfig.tsbuildinfo" }, "files": [ "src/", diff --git a/packages/hardhat-toolbox/test/.eslintrc.js b/packages/hardhat-toolbox/test/.eslintrc.js new file mode 100644 index 0000000000..757fe8a3ca --- /dev/null +++ b/packages/hardhat-toolbox/test/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + extends: [`${__dirname}/../.eslintrc.js`], + parserOptions: { + project: `${__dirname}/../tsconfig.json`, + sourceType: "module", + }, + rules: { + "import/no-extraneous-dependencies": [ + "error", + { + devDependencies: true, + }, + ], + }, +}; From b6b8e9895612cb7cb4c325625f65cab98b51aeba Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 19:11:12 +0200 Subject: [PATCH 79/95] Run prettier --- docs/src/content/tutorial/testing-contracts.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/src/content/tutorial/testing-contracts.md b/docs/src/content/tutorial/testing-contracts.md index bb05e7e5e8..16ecd2a999 100644 --- a/docs/src/content/tutorial/testing-contracts.md +++ b/docs/src/content/tutorial/testing-contracts.md @@ -114,7 +114,9 @@ The two tests that we wrote begin with their setup, which in this case means dep You can avoid code duplication and improve the performance of your test suite by using **fixtures**. A fixture is a setup function that is run only the first time it's invoked. On subsequent invocations, instead of re-running it, Hardhat will reset the state of the network to what it was at the point after the fixture was initially executed. ```js -const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); const { expect } = require("chai"); describe("Token contract", function () { @@ -171,7 +173,9 @@ const { expect } = require("chai"); // We use `loadFixture` to share common setups (or fixtures) between tests. // Using this simplifies your tests and makes them run faster, by taking // advantage of Hardhat Network's snapshot functionality. -const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); // `describe` is a Mocha function that allows you to organize your tests. // Having your tests organized makes debugging them easier. All Mocha From 94b2fd1640d67bcaa9592a3fd60a5c5022b142c5 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 19:14:14 +0200 Subject: [PATCH 80/95] Improve changesets descriptions --- .changeset/twelve-adults-doubt.md | 2 +- .changeset/wet-keys-press.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/twelve-adults-doubt.md b/.changeset/twelve-adults-doubt.md index 2f0017d5d3..19314d434c 100644 --- a/.changeset/twelve-adults-doubt.md +++ b/.changeset/twelve-adults-doubt.md @@ -2,4 +2,4 @@ "@nomicfoundation/hardhat-toolbox": major --- -Use new plugin versions in the Toolbox +The Toolbox and the plugins that it includes are now based on ethers v6 diff --git a/.changeset/wet-keys-press.md b/.changeset/wet-keys-press.md index 4143edf340..f6b137dcfb 100644 --- a/.changeset/wet-keys-press.md +++ b/.changeset/wet-keys-press.md @@ -2,4 +2,4 @@ "@nomicfoundation/hardhat-chai-matchers": patch --- -Removed unnecessary dependency +Removed an unnecessary dependency From 3a1846e80292bb2f4c4e61b837b11d5939742482 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 7 Jun 2023 18:16:02 +0000 Subject: [PATCH 81/95] Version Packages --- .changeset/cuddly-grapes-wink.md | 5 ----- .changeset/nervous-bees-hunt.md | 5 ----- .changeset/twelve-adults-doubt.md | 5 ----- .changeset/unlucky-books-love.md | 5 ----- .changeset/wet-keys-press.md | 5 ----- packages/hardhat-chai-matchers/CHANGELOG.md | 6 ++++++ packages/hardhat-chai-matchers/package.json | 4 ++-- packages/hardhat-core/CHANGELOG.md | 6 ++++++ packages/hardhat-core/package.json | 2 +- packages/hardhat-ethers/CHANGELOG.md | 6 ++++++ packages/hardhat-ethers/package.json | 4 ++-- packages/hardhat-toolbox/CHANGELOG.md | 6 ++++++ packages/hardhat-toolbox/package.json | 4 ++-- packages/hardhat-verify/CHANGELOG.md | 7 +++++++ packages/hardhat-verify/package.json | 4 ++-- 15 files changed, 40 insertions(+), 34 deletions(-) delete mode 100644 .changeset/cuddly-grapes-wink.md delete mode 100644 .changeset/nervous-bees-hunt.md delete mode 100644 .changeset/twelve-adults-doubt.md delete mode 100644 .changeset/unlucky-books-love.md delete mode 100644 .changeset/wet-keys-press.md create mode 100644 packages/hardhat-verify/CHANGELOG.md diff --git a/.changeset/cuddly-grapes-wink.md b/.changeset/cuddly-grapes-wink.md deleted file mode 100644 index 4040f454f9..0000000000 --- a/.changeset/cuddly-grapes-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-verify": patch ---- - -Removed the compilation step from the verify task, and removed the noCompile flag diff --git a/.changeset/nervous-bees-hunt.md b/.changeset/nervous-bees-hunt.md deleted file mode 100644 index 03ddcd3284..0000000000 --- a/.changeset/nervous-bees-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-ethers": patch ---- - -The `helper.deployContract` now accepts transaction overrides diff --git a/.changeset/twelve-adults-doubt.md b/.changeset/twelve-adults-doubt.md deleted file mode 100644 index 19314d434c..0000000000 --- a/.changeset/twelve-adults-doubt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-toolbox": major ---- - -The Toolbox and the plugins that it includes are now based on ethers v6 diff --git a/.changeset/unlucky-books-love.md b/.changeset/unlucky-books-love.md deleted file mode 100644 index 0c69ca491b..0000000000 --- a/.changeset/unlucky-books-love.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"hardhat": minor ---- - -The sample projects now use the new version of the Toolbox diff --git a/.changeset/wet-keys-press.md b/.changeset/wet-keys-press.md deleted file mode 100644 index f6b137dcfb..0000000000 --- a/.changeset/wet-keys-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-chai-matchers": patch ---- - -Removed an unnecessary dependency diff --git a/packages/hardhat-chai-matchers/CHANGELOG.md b/packages/hardhat-chai-matchers/CHANGELOG.md index 8f336aaec7..eed11a2871 100644 --- a/packages/hardhat-chai-matchers/CHANGELOG.md +++ b/packages/hardhat-chai-matchers/CHANGELOG.md @@ -1,5 +1,11 @@ # @nomicfoundation/hardhat-chai-matchers +## 2.0.1 + +### Patch Changes + +- 70c2ccf12: Removed an unnecessary dependency + ## 2.0.0 ### Major Changes diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index 9fc2930747..047566e485 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-chai-matchers", - "version": "2.0.0", + "version": "2.0.1", "description": "Hardhat utils for testing", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-chai-matchers", "repository": "github:nomicfoundation/hardhat", @@ -54,7 +54,7 @@ "eslint-plugin-prettier": "3.4.0", "ethers": "^6.1.0", "get-port": "^5.1.1", - "hardhat": "^2.9.4", + "hardhat": "^2.15.0", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-core/CHANGELOG.md b/packages/hardhat-core/CHANGELOG.md index d0979e1b87..0290b5686d 100644 --- a/packages/hardhat-core/CHANGELOG.md +++ b/packages/hardhat-core/CHANGELOG.md @@ -1,5 +1,11 @@ # hardhat +## 2.15.0 + +### Minor Changes + +- 99995d53b: The sample projects now use the new version of the Toolbox + ## 2.14.1 ### Patch Changes diff --git a/packages/hardhat-core/package.json b/packages/hardhat-core/package.json index 6aa554aaef..a951330067 100644 --- a/packages/hardhat-core/package.json +++ b/packages/hardhat-core/package.json @@ -1,6 +1,6 @@ { "name": "hardhat", - "version": "2.14.1", + "version": "2.15.0", "author": "Nomic Labs LLC", "license": "MIT", "homepage": "https://hardhat.org", diff --git a/packages/hardhat-ethers/CHANGELOG.md b/packages/hardhat-ethers/CHANGELOG.md index ac99cf9573..ae9f26b329 100644 --- a/packages/hardhat-ethers/CHANGELOG.md +++ b/packages/hardhat-ethers/CHANGELOG.md @@ -1,5 +1,11 @@ # @nomiclabs/hardhat-ethers +## 3.0.1 + +### Patch Changes + +- a9c159f96: The `helper.deployContract` now accepts transaction overrides + ## 2.2.3 ### Patch Changes diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index 6065867680..4c46d4fea9 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-ethers", - "version": "3.0.0", + "version": "3.0.1", "description": "Hardhat plugin for ethers", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-ethers", "repository": "github:nomicfoundation/hardhat", @@ -53,7 +53,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^6.1.0", - "hardhat": "^2.0.0", + "hardhat": "^2.15.0", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-toolbox/CHANGELOG.md b/packages/hardhat-toolbox/CHANGELOG.md index f0e56c3a1c..569d3f5984 100644 --- a/packages/hardhat-toolbox/CHANGELOG.md +++ b/packages/hardhat-toolbox/CHANGELOG.md @@ -1,5 +1,11 @@ # @nomicfoundation/hardhat-toolbox +## 3.0.0 + +### Major Changes + +- 399347f40: The Toolbox and the plugins that it includes are now based on ethers v6 + ## 2.0.2 ### Patch Changes diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index 7742e6ca1f..dd25f2b97f 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-toolbox", - "version": "2.0.2", + "version": "3.0.0", "description": "Nomic Foundation's recommended bundle of Hardhat plugins", "repository": "github:nomicfoundation/hardhat", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-toolbox", @@ -56,7 +56,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^6.4.0", - "hardhat": "^2.11.0", + "hardhat": "^2.15.0", "hardhat-gas-reporter": "^1.0.8", "mocha": "^10.0.0", "prettier": "2.4.1", diff --git a/packages/hardhat-verify/CHANGELOG.md b/packages/hardhat-verify/CHANGELOG.md new file mode 100644 index 0000000000..b504fcae5e --- /dev/null +++ b/packages/hardhat-verify/CHANGELOG.md @@ -0,0 +1,7 @@ +# @nomicfoundation/hardhat-verify + +## 1.0.1 + +### Patch Changes + +- 40b371bca: Removed the compilation step from the verify task, and removed the noCompile flag diff --git a/packages/hardhat-verify/package.json b/packages/hardhat-verify/package.json index 098098cffe..55c65d9dfe 100644 --- a/packages/hardhat-verify/package.json +++ b/packages/hardhat-verify/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-verify", - "version": "1.0.0", + "version": "1.0.1", "description": "Hardhat plugin for verifying contracts", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-verify", "repository": "github:nomicfoundation/hardhat", @@ -63,7 +63,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^5.0.0", - "hardhat": "^2.0.4", + "hardhat": "^2.15.0", "mocha": "^10.0.0", "nyc": "^15.1.0", "prettier": "2.4.1", From f0aa3c3e3df56bcf9267828514cf43e63da0d17d Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 21:50:36 +0200 Subject: [PATCH 82/95] Don't bump plugins dependencies on hardhat --- packages/hardhat-chai-matchers/package.json | 2 +- packages/hardhat-ethers/package.json | 2 +- packages/hardhat-toolbox/package.json | 2 +- packages/hardhat-verify/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hardhat-chai-matchers/package.json b/packages/hardhat-chai-matchers/package.json index 047566e485..e0679c0456 100644 --- a/packages/hardhat-chai-matchers/package.json +++ b/packages/hardhat-chai-matchers/package.json @@ -54,7 +54,7 @@ "eslint-plugin-prettier": "3.4.0", "ethers": "^6.1.0", "get-port": "^5.1.1", - "hardhat": "^2.15.0", + "hardhat": "^2.9.4", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index 4c46d4fea9..f4dfcca169 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -53,7 +53,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^6.1.0", - "hardhat": "^2.15.0", + "hardhat": "^2.0.0", "mocha": "^10.0.0", "prettier": "2.4.1", "rimraf": "^3.0.2", diff --git a/packages/hardhat-toolbox/package.json b/packages/hardhat-toolbox/package.json index dd25f2b97f..e10a7908c8 100644 --- a/packages/hardhat-toolbox/package.json +++ b/packages/hardhat-toolbox/package.json @@ -56,7 +56,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^6.4.0", - "hardhat": "^2.15.0", + "hardhat": "^2.11.0", "hardhat-gas-reporter": "^1.0.8", "mocha": "^10.0.0", "prettier": "2.4.1", diff --git a/packages/hardhat-verify/package.json b/packages/hardhat-verify/package.json index 55c65d9dfe..9b4dff4f75 100644 --- a/packages/hardhat-verify/package.json +++ b/packages/hardhat-verify/package.json @@ -63,7 +63,7 @@ "eslint-plugin-no-only-tests": "3.0.0", "eslint-plugin-prettier": "3.4.0", "ethers": "^5.0.0", - "hardhat": "^2.15.0", + "hardhat": "^2.0.4", "mocha": "^10.0.0", "nyc": "^15.1.0", "prettier": "2.4.1", From 83f23a16f6f27554f042f11f63dca6e4f2774fc5 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Wed, 7 Jun 2023 22:22:08 +0200 Subject: [PATCH 83/95] Fix import in esm sample project --- .../hardhat-core/sample-projects/javascript-esm/test/Lock.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js index e5ba3d8fcd..ef8d8745e2 100644 --- a/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js +++ b/packages/hardhat-core/sample-projects/javascript-esm/test/Lock.js @@ -1,7 +1,7 @@ import { time, loadFixture, -} from "@nomicfoundation/hardhat-toolbox/network-helpers"; +} from "@nomicfoundation/hardhat-toolbox/network-helpers.js"; import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs.js"; import { expect } from "chai"; From 0039b3b6f355bf29d0c04da164583f77e750a77d Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Thu, 8 Jun 2023 10:41:24 +0200 Subject: [PATCH 84/95] Pin `web3` version in installation guide of `hardhat-truffle5` --- packages/hardhat-truffle5/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-truffle5/README.md b/packages/hardhat-truffle5/README.md index f0ba4df798..7797a3913e 100644 --- a/packages/hardhat-truffle5/README.md +++ b/packages/hardhat-truffle5/README.md @@ -15,7 +15,7 @@ This plugin requires [hardhat-web3](https://github.com/nomiclabs/hardhat/tree/ma ## Installation ```bash -npm install --save-dev @nomiclabs/hardhat-truffle5 @nomiclabs/hardhat-web3 web3 +npm install --save-dev @nomiclabs/hardhat-truffle5 @nomiclabs/hardhat-web3 'web3@^1.0.0-beta.36' ``` And add the following statement to your `hardhat.config.js`: From b466e49bdc9c3c0d85b47fd4632e0dfd8c422808 Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Thu, 8 Jun 2023 10:42:36 +0200 Subject: [PATCH 85/95] Pin `web3` version in installation guide of `hardhat-web3` --- packages/hardhat-web3/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hardhat-web3/README.md b/packages/hardhat-web3/README.md index 364e495058..3112587936 100644 --- a/packages/hardhat-web3/README.md +++ b/packages/hardhat-web3/README.md @@ -11,7 +11,7 @@ This plugin brings to Hardhat the Web3 module and an initialized instance of Web # Installation ```bash -npm install --save-dev @nomiclabs/hardhat-web3 web3 +npm install --save-dev @nomiclabs/hardhat-web3 'web3@^1.0.0-beta.36' ``` And add the following statement to your `hardhat.config.js`: From 34214392e82a8a350c9222e8e09e3d3a93edbf27 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 8 Jun 2023 11:36:46 +0200 Subject: [PATCH 86/95] Use pinned web3 version in installation instructions --- .../content/hardhat-runner/docs/other-guides/truffle-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/hardhat-runner/docs/other-guides/truffle-testing.md b/docs/src/content/hardhat-runner/docs/other-guides/truffle-testing.md index e291fd71f6..ec72f8ba5e 100644 --- a/docs/src/content/hardhat-runner/docs/other-guides/truffle-testing.md +++ b/docs/src/content/hardhat-runner/docs/other-guides/truffle-testing.md @@ -26,7 +26,7 @@ Now run `npx hardhat` inside your project folder and select `Create an empty har Let's now install the `Truffle` and `Web3.js` plugins, as well as `web3.js` itself. ``` -npm install --save-dev @nomiclabs/hardhat-truffle5 @nomiclabs/hardhat-web3 web3 +npm install --save-dev @nomiclabs/hardhat-truffle5 @nomiclabs/hardhat-web3 'web3@^1.0.0-beta.36' ``` Enable the Truffle 5 plugin on your Hardhat config file by requiring it: From 8726d0b6919f852bdbde7970aee6f2d45aad7ea6 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 8 Jun 2023 19:40:20 +0200 Subject: [PATCH 87/95] Fix waitForDeployment in non-automined networks --- packages/hardhat-ethers/package.json | 3 + .../src/internal/hardhat-ethers-provider.ts | 220 +++++++++++++++++- packages/hardhat-ethers/test/contracts.ts | 89 +++++++ packages/hardhat-ethers/test/helpers.ts | 3 + 4 files changed, 304 insertions(+), 11 deletions(-) create mode 100644 packages/hardhat-ethers/test/contracts.ts diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index f4dfcca169..9e8349787c 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -37,6 +37,9 @@ "LICENSE", "README.md" ], + "dependencies": { + "debug": "^4.1.1" + }, "devDependencies": { "@types/chai": "^4.2.0", "@types/chai-as-promised": "^7.1.3", diff --git a/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts index 6523fe0bd2..0e18241210 100644 --- a/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts +++ b/packages/hardhat-ethers/src/internal/hardhat-ethers-provider.ts @@ -14,6 +14,7 @@ import type { PerformActionFilter, } from "ethers"; +import debug from "debug"; import { Block, FeeData, @@ -46,7 +47,21 @@ import { NotImplementedError, } from "./errors"; +const log = debug("hardhat:hardhat-ethers:provider"); + export class HardhatEthersProvider implements ethers.Provider { + private _isHardhatNetworkCached: boolean | undefined; + + private _transactionHashListeners: Map< + string, + Array<{ + listener: Listener; + once: boolean; + }> + > = new Map(); + + private _transactionHashPollingInterval: NodeJS.Timeout | undefined; + constructor( private readonly _hardhatProvider: EthereumProvider, private readonly _networkName: string @@ -305,7 +320,7 @@ export class HardhatEthersProvider implements ethers.Provider { resolvedFilter, ]); - return logs.map((log: any) => this._wrapLog(formatLog(log))); + return logs.map((l: any) => this._wrapLog(formatLog(l))); } public async resolveName(_ensName: string): Promise { @@ -332,7 +347,11 @@ export class HardhatEthersProvider implements ethers.Provider { public async on(event: ProviderEvent, listener: Listener): Promise { if (typeof event === "string") { - this._hardhatProvider.on(event, listener); + if (isTransactionHash(event)) { + await this._onTransactionHash(event, listener, { once: false }); + } else { + this._hardhatProvider.on(event, listener); + } } else { throw new NonStringEventError("on", event); } @@ -342,7 +361,11 @@ export class HardhatEthersProvider implements ethers.Provider { public async once(event: ProviderEvent, listener: Listener): Promise { if (typeof event === "string") { - this._hardhatProvider.once(event, listener); + if (isTransactionHash(event)) { + await this._onTransactionHash(event, listener, { once: true }); + } else { + this._hardhatProvider.once(event, listener); + } } else { throw new NonStringEventError("once", event); } @@ -352,7 +375,11 @@ export class HardhatEthersProvider implements ethers.Provider { public async emit(event: ProviderEvent, ...args: any[]): Promise { if (typeof event === "string") { - return this._hardhatProvider.emit(event, ...args); + if (isTransactionHash(event)) { + return this._emitTransactionHash(event, ...args); + } else { + return this._hardhatProvider.emit(event, ...args); + } } else { throw new NonStringEventError("emit", event); } @@ -362,7 +389,11 @@ export class HardhatEthersProvider implements ethers.Provider { event?: ProviderEvent | undefined ): Promise { if (typeof event === "string") { - return this._hardhatProvider.listenerCount(event); + if (isTransactionHash(event)) { + return this._transactionHashListeners.get(event)?.length ?? 0; + } else { + return this._hardhatProvider.listenerCount(event); + } } else { throw new NonStringEventError("listenerCount", event); } @@ -372,7 +403,15 @@ export class HardhatEthersProvider implements ethers.Provider { event?: ProviderEvent | undefined ): Promise { if (typeof event === "string") { - return this._hardhatProvider.listeners(event) as any; + if (isTransactionHash(event)) { + return ( + this._transactionHashListeners + .get(event) + ?.map(({ listener }) => listener) ?? [] + ); + } else { + return this._hardhatProvider.listeners(event) as any; + } } else { throw new NonStringEventError("listeners", event); } @@ -382,8 +421,17 @@ export class HardhatEthersProvider implements ethers.Provider { event: ProviderEvent, listener?: Listener | undefined ): Promise { - if (typeof event === "string" && listener !== undefined) { - this._hardhatProvider.off(event, listener); + if (typeof event === "string") { + if (isTransactionHash(event)) { + this._offTransactionHash(event, listener); + } else if (listener !== undefined) { + this._hardhatProvider.off(event, listener); + } else { + const registeredListeners = this._hardhatProvider.listeners(event); + for (const registeredListener of registeredListeners) { + this._hardhatProvider.off(event, registeredListener as any); + } + } } else { throw new NonStringEventError("off", event); } @@ -394,8 +442,14 @@ export class HardhatEthersProvider implements ethers.Provider { public async removeAllListeners( event?: ProviderEvent | undefined ): Promise { - if (event === undefined || typeof event === "string") { + if (event === undefined) { this._hardhatProvider.removeAllListeners(event); + } else if (typeof event === "string") { + if (isTransactionHash(event)) { + this._transactionHashListeners.delete(event); + } else { + this._hardhatProvider.removeAllListeners(event); + } } else { throw new NonStringEventError("removeAllListeners", event); } @@ -408,7 +462,11 @@ export class HardhatEthersProvider implements ethers.Provider { listener: Listener ): Promise { if (typeof event === "string") { - this._hardhatProvider.addListener(event, listener); + if (isTransactionHash(event)) { + await this._onTransactionHash(event, listener, { once: false }); + } else { + this._hardhatProvider.addListener(event, listener); + } } else { throw new NonStringEventError("addListener", event); } @@ -421,7 +479,11 @@ export class HardhatEthersProvider implements ethers.Provider { listener: Listener ): Promise { if (typeof event === "string") { - this._hardhatProvider.removeListener(event, listener); + if (isTransactionHash(event)) { + this._offTransactionHash(event, listener); + } else { + this._hardhatProvider.removeListener(event, listener); + } } else { throw new NonStringEventError("removeListener", event); } @@ -670,6 +732,138 @@ export class HardhatEthersProvider implements ethers.Provider { return blockTag; } + + private async _onTransactionHash( + transactionHash: string, + listener: Listener, + { once }: { once: boolean } + ): Promise { + const listeners = this._transactionHashListeners.get(transactionHash) ?? []; + listeners.push({ listener, once }); + this._transactionHashListeners.set(transactionHash, listeners); + await this._startTransactionHashPolling(); + } + + private _offTransactionHash( + transactionHash: string, + listener?: Listener + ): void { + if (listener === undefined) { + this._transactionHashListeners.delete(transactionHash); + } else { + const listeners = this._transactionHashListeners.get(transactionHash); + if (listeners !== undefined) { + const listenerIndex = listeners.findIndex( + (item) => item.listener === listener + ); + + if (listenerIndex >= 0) { + listeners.splice(listenerIndex, 1); + } + + if (listeners.length === 0) { + this._transactionHashListeners.delete(transactionHash); + } + + if (this._transactionHashListeners.size === 0) { + this._stopTransactionHashPolling(); + } + } + } + } + + private async _startTransactionHashPolling() { + const _isHardhatNetwork = await this._isHardhatNetwork(); + + const interval = _isHardhatNetwork ? 50 : 500; + + if (_isHardhatNetwork) { + await this._pollTransactionHashes(); + } + + if (this._transactionHashPollingInterval === undefined) { + this._transactionHashPollingInterval = setInterval(async () => { + await this._pollTransactionHashes(); + }, interval); + } + } + + private _stopTransactionHashPolling() { + if (this._transactionHashPollingInterval !== undefined) { + clearInterval(this._transactionHashPollingInterval); + this._transactionHashPollingInterval = undefined; + } + } + + /** + * Traverse all the registered transaction hashes and check if they were mined. + * + * This function should NOT throw. + */ + private async _pollTransactionHashes() { + try { + const listenersToRemove: Array<[string, Listener]> = []; + + for (const [ + transactionHash, + listeners, + ] of this._transactionHashListeners.entries()) { + const receipt = await this.getTransactionReceipt(transactionHash); + + if (receipt !== null) { + for (const { listener, once } of listeners) { + listener(receipt); + if (once) { + listenersToRemove.push([transactionHash, listener]); + } + } + } + } + + for (const [transactionHash, listener] of listenersToRemove) { + this._offTransactionHash(transactionHash, listener); + } + } catch (e: any) { + log(`Error during transaction hash polling: ${e.message}`); + } + } + + private _emitTransactionHash( + transactionHash: string, + ...args: any[] + ): boolean { + const listeners = this._transactionHashListeners.get(transactionHash); + const listenersToRemove: Listener[] = []; + + if (listeners === undefined) { + return false; + } + + for (const { listener, once } of listeners) { + listener(...args); + if (once) { + listenersToRemove.push(listener); + } + } + + for (const listener of listenersToRemove) { + this._offTransactionHash(transactionHash, listener); + } + + return true; + } + + private async _isHardhatNetwork(): Promise { + if (this._isHardhatNetworkCached === undefined) { + this._isHardhatNetworkCached = false; + try { + await this._hardhatProvider.send("hardhat_metadata"); + this._isHardhatNetworkCached = true; + } catch {} + } + + return this._isHardhatNetworkCached; + } } function isPromise(value: any): value is Promise { @@ -681,3 +875,7 @@ function concisify(items: string[]): string[] { items.sort(); return items; } + +function isTransactionHash(x: string): boolean { + return x.startsWith("0x") && x.length === 66; +} diff --git a/packages/hardhat-ethers/test/contracts.ts b/packages/hardhat-ethers/test/contracts.ts new file mode 100644 index 0000000000..3662fcba93 --- /dev/null +++ b/packages/hardhat-ethers/test/contracts.ts @@ -0,0 +1,89 @@ +import { assert, use } from "chai"; +import chaiAsPromised from "chai-as-promised"; + +import { ExampleContract, EXAMPLE_CONTRACT } from "./example-contracts"; +import { useEnvironment } from "./environment"; +import { sleep } from "./helpers"; + +use(chaiAsPromised); + +describe("contracts", function () { + useEnvironment("minimal-project"); + + it("should wait for deployment when automining is enabled", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + + const contract = await factory.deploy(); + + await contract.waitForDeployment(); + }); + + it("should wait for deployment when automining is disabled", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + + await this.env.network.provider.send("evm_setAutomine", [false]); + + const contract = await factory.deploy(); + + let deployed = false; + const waitForDeploymentPromise = contract.waitForDeployment().then(() => { + deployed = true; + }); + + assert.isFalse(deployed); + await sleep(10); + assert.isFalse(deployed); + + await this.env.network.provider.send("hardhat_mine"); + await waitForDeploymentPromise; + assert.isTrue(deployed); + }); + + it("should wait for multiple deployments at the same time", async function () { + const signer = await this.env.ethers.provider.getSigner(0); + + const factory = new this.env.ethers.ContractFactory<[], ExampleContract>( + EXAMPLE_CONTRACT.abi, + EXAMPLE_CONTRACT.deploymentBytecode, + signer + ); + + await this.env.network.provider.send("evm_setAutomine", [false]); + + // we set the gas limit so that the 3 txs fit in a block + const contract1 = await factory.deploy({ gasLimit: 1_000_000 }); + const contract2 = await factory.deploy({ gasLimit: 1_000_000 }); + const contract3 = await factory.deploy({ gasLimit: 1_000_000 }); + + const allDeployedPromise = Promise.all([ + contract1.waitForDeployment(), + contract2.waitForDeployment(), + contract3.waitForDeployment(), + ]); + + let deployed = false; + const waitForDeploymentPromise = allDeployedPromise.then(() => { + deployed = true; + }); + + assert.isFalse(deployed); + await sleep(10); + assert.isFalse(deployed); + + await this.env.network.provider.send("hardhat_mine"); + await waitForDeploymentPromise; + assert.isTrue(deployed); + }); +}); diff --git a/packages/hardhat-ethers/test/helpers.ts b/packages/hardhat-ethers/test/helpers.ts index e705afc866..779244c08e 100644 --- a/packages/hardhat-ethers/test/helpers.ts +++ b/packages/hardhat-ethers/test/helpers.ts @@ -24,3 +24,6 @@ export function assertIsSigner( assert.isTrue("getAddress" in value); assert.isTrue("signTransaction" in value); } + +export const sleep = (timeout: number) => + new Promise((resolve) => setTimeout(resolve, timeout)); From eb1ae069b44d5e1c58b02616bcc45b4d75e3b18b Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 8 Jun 2023 19:42:56 +0200 Subject: [PATCH 88/95] Create fluffy-walls-sip.md --- .changeset/fluffy-walls-sip.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fluffy-walls-sip.md diff --git a/.changeset/fluffy-walls-sip.md b/.changeset/fluffy-walls-sip.md new file mode 100644 index 0000000000..f82528f7d8 --- /dev/null +++ b/.changeset/fluffy-walls-sip.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-ethers": patch +--- + +Fixed a problem when `waitForDeployment` was used in live networks. From eaab9eab04ebf0511327e6a73143047ad614c2e1 Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Thu, 8 Jun 2023 20:24:02 +0200 Subject: [PATCH 89/95] Run pre-release tests in changesets branch --- .github/workflows/pre-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index eead734896..3b6106c471 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -2,7 +2,7 @@ name: Pre-release tests on: push: - branches: [pre-release-testing-branch] + branches: [changeset-release/main] workflow_dispatch: concurrency: From 55a15bf7430ab116ff35849dc2e3491111aab81e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 Jun 2023 18:26:08 +0000 Subject: [PATCH 90/95] Version Packages --- .changeset/fluffy-walls-sip.md | 5 ----- packages/hardhat-ethers/CHANGELOG.md | 6 ++++++ packages/hardhat-ethers/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/fluffy-walls-sip.md diff --git a/.changeset/fluffy-walls-sip.md b/.changeset/fluffy-walls-sip.md deleted file mode 100644 index f82528f7d8..0000000000 --- a/.changeset/fluffy-walls-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@nomicfoundation/hardhat-ethers": patch ---- - -Fixed a problem when `waitForDeployment` was used in live networks. diff --git a/packages/hardhat-ethers/CHANGELOG.md b/packages/hardhat-ethers/CHANGELOG.md index ae9f26b329..d223e52215 100644 --- a/packages/hardhat-ethers/CHANGELOG.md +++ b/packages/hardhat-ethers/CHANGELOG.md @@ -1,5 +1,11 @@ # @nomiclabs/hardhat-ethers +## 3.0.2 + +### Patch Changes + +- eb1ae069b: Fixed a problem when `waitForDeployment` was used in live networks. + ## 3.0.1 ### Patch Changes diff --git a/packages/hardhat-ethers/package.json b/packages/hardhat-ethers/package.json index 9e8349787c..51dbc74e21 100644 --- a/packages/hardhat-ethers/package.json +++ b/packages/hardhat-ethers/package.json @@ -1,6 +1,6 @@ { "name": "@nomicfoundation/hardhat-ethers", - "version": "3.0.1", + "version": "3.0.2", "description": "Hardhat plugin for ethers", "homepage": "https://github.com/nomicfoundation/hardhat/tree/main/packages/hardhat-ethers", "repository": "github:nomicfoundation/hardhat", From 41595896aa52a231c780180ca2bb501cd5e9088a Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 9 Jun 2023 13:39:37 +0200 Subject: [PATCH 91/95] Adapt existing changeset --- .changeset/polite-mugs-cry.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/polite-mugs-cry.m b/.changeset/polite-mugs-cry.m index b03cb1f534..05b38a6eed 100644 --- a/.changeset/polite-mugs-cry.m +++ b/.changeset/polite-mugs-cry.m @@ -1,5 +1,5 @@ --- -"@nomiclabs/hardhat-etherscan": patch +"@nomiclabs/hardhat-verify": patch --- -Fix URLs for the Aurora networks (thanks @zZoMROT!) +Fix URLs for the Aurora networks (thanks @zZoMROT and @ZumZoom!) From 5071ed1b5ff657400aa1512e9b5f181a05e5866c Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Fri, 9 Jun 2023 13:57:42 +0200 Subject: [PATCH 92/95] Re-add pre-release-testing-branch to workflow --- .github/workflows/pre-release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 3b6106c471..f7850899c6 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -2,7 +2,9 @@ name: Pre-release tests on: push: - branches: [changeset-release/main] + branches: + - pre-release-testing-branch + - changeset-release/main workflow_dispatch: concurrency: From f56ecab6d11783c3dc74120057eb40aa4e80a127 Mon Sep 17 00:00:00 2001 From: Ana Julia Date: Fri, 9 Jun 2023 11:48:42 -0300 Subject: [PATCH 93/95] This removes an useless array --- .../hardhat-core/src/builtin-tasks/compile.ts | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/hardhat-core/src/builtin-tasks/compile.ts b/packages/hardhat-core/src/builtin-tasks/compile.ts index 9575321e39..140d7ec1dc 100644 --- a/packages/hardhat-core/src/builtin-tasks/compile.ts +++ b/packages/hardhat-core/src/builtin-tasks/compile.ts @@ -405,27 +405,19 @@ subtask(TASK_COMPILE_SOLIDITY_COMPILE_JOBS) log(`Compiling ${compilationJobs.length} jobs`); - const versionList: string[] = []; for (const job of compilationJobs) { const solcVersion = job.getSolcConfig().version; - if (!versionList.includes(solcVersion)) { - // versions older than 0.4.11 don't work with hardhat - // see issue https://github.com/nomiclabs/hardhat/issues/2004 - if ( - semver.lt(solcVersion, COMPILE_TASK_FIRST_SOLC_VERSION_SUPPORTED) - ) { - throw new HardhatError( - ERRORS.BUILTIN_TASKS.COMPILE_TASK_UNSUPPORTED_SOLC_VERSION, - { - version: solcVersion, - firstSupportedVersion: - COMPILE_TASK_FIRST_SOLC_VERSION_SUPPORTED, - } - ); - } - - versionList.push(solcVersion); + // versions older than 0.4.11 don't work with hardhat + // see issue https://github.com/nomiclabs/hardhat/issues/2004 + if (semver.lt(solcVersion, COMPILE_TASK_FIRST_SOLC_VERSION_SUPPORTED)) { + throw new HardhatError( + ERRORS.BUILTIN_TASKS.COMPILE_TASK_UNSUPPORTED_SOLC_VERSION, + { + version: solcVersion, + firstSupportedVersion: COMPILE_TASK_FIRST_SOLC_VERSION_SUPPORTED, + } + ); } } From 06d766e0428850c0dc8375a419767238278967d0 Mon Sep 17 00:00:00 2001 From: Marin Petrunic Date: Mon, 12 Jun 2023 12:52:00 +0200 Subject: [PATCH 94/95] update web3 version Signed-off-by: Marin Petrunic --- packages/hardhat-web3/package.json | 2 +- packages/hardhat-web3/test/index.ts | 20 +- yarn.lock | 434 ++++++++++++++++------------ 3 files changed, 264 insertions(+), 192 deletions(-) diff --git a/packages/hardhat-web3/package.json b/packages/hardhat-web3/package.json index 0793a80531..490a5ed38a 100644 --- a/packages/hardhat-web3/package.json +++ b/packages/hardhat-web3/package.json @@ -51,7 +51,7 @@ "rimraf": "^3.0.2", "ts-node": "^10.8.0", "typescript": "~4.7.4", - "web3": "^4.0.1-rc.1" + "web3": "^4.0.1" }, "peerDependencies": { "hardhat": "^2.0.0", diff --git a/packages/hardhat-web3/test/index.ts b/packages/hardhat-web3/test/index.ts index 5ba0f81e9f..6488c6ddb2 100644 --- a/packages/hardhat-web3/test/index.ts +++ b/packages/hardhat-web3/test/index.ts @@ -19,13 +19,9 @@ describe("Web3 plugin", function () { }).send({ from: (await this.env.web3.eth.getAccounts())[0], }); - await Promise.all([ - response.on("error", (...args) => console.log("error", args)), - response.on("transactionHash", (...args) => - console.log("transactionHash", args) - ), - response.on("receipt", (...args) => console.log("receipt", args)), - ]); + await new Promise((resolve) => + response.on("receipt", () => resolve()) + ); }); }); }); @@ -42,13 +38,9 @@ describe("Web3 plugin", function () { }).send({ from, }); - await Promise.all([ - response.on("error", (...args) => console.log("error", args)), - response.on("transactionHash", (...args) => - console.log("transactionHash", args) - ), - response.on("receipt", (...args) => console.log("receipt", args)), - ]); + await new Promise((resolve) => + response.on("receipt", () => resolve()) + ); }); }); }); diff --git a/yarn.lock b/yarn.lock index d47aea39fb..f8fd168bc3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1020,11 +1020,28 @@ lodash "^4.17.16" uuid "^7.0.3" +"@noble/curves@1.0.0", "@noble/curves@~1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932" + integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw== + dependencies: + "@noble/hashes" "1.3.0" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" + integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== + +"@noble/hashes@~1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -1297,6 +1314,15 @@ "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.0" +"@scure/bip32@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87" + integrity sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q== + dependencies: + "@noble/curves" "~1.0.0" + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" @@ -1305,6 +1331,14 @@ "@noble/hashes" "~1.2.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b" + integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg== + dependencies: + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" @@ -2146,7 +2180,7 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1, ajv@^8.11.0: +ajv@^8.0.1: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -2222,15 +2256,10 @@ ansi-styles@~1.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" integrity sha512-3iF4FIKdxaVYT3JqQuY3Wat/T2t7TRbbQ94Fu50ZUCbLy4TFbTzr90NOHQodQkNqmeEGCw8WbeP78WNi6SKYUA== -antlr4@^4.11.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.12.0.tgz#e2323fbb057c77068a174914b0533398aeaba56a" - integrity sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ== - -antlr4@~4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.8.0.tgz#f938ec171be7fc2855cd3a533e87647185b32b6a" - integrity sha512-en/MxQ4OkPgGJQ3wD/muzj1uDnFSzdFIhc2+c6bHZokWkuBb6RRvFjpWhPxWLbgQvaEzldJZ0GSQpfSAaE3hqg== +antlr4@4.7.1, antlr4@^4.11.0, antlr4@~4.8.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.7.1.tgz#69984014f096e9e775f53dd9744bf994d8959773" + integrity sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ== antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" @@ -4130,7 +4159,7 @@ ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereum-cryptography@^1.0.3, ethereum-cryptography@^1.1.2: +ethereum-cryptography@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== @@ -4140,6 +4169,16 @@ ethereum-cryptography@^1.0.3, ethereum-cryptography@^1.1.2: "@scure/bip32" "1.1.5" "@scure/bip39" "1.1.1" +ethereum-cryptography@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.0.0.tgz#e052b49fa81affae29402e977b8d3a31f88612b6" + integrity sha512-g25m4EtfQGjstWgVE1aIz7XYYjf3kH5kG17ULWVB5dH6uLahsoltOhACzSxyDV+fhn4gbR4xRrOXGe6r2uh4Bg== + dependencies: + "@noble/curves" "1.0.0" + "@noble/hashes" "1.3.0" + "@scure/bip32" "1.3.0" + "@scure/bip39" "1.2.0" + ethereum-ens@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/ethereum-ens/-/ethereum-ens-0.8.0.tgz#6d0f79acaa61fdbc87d2821779c4e550243d4c57" @@ -4710,6 +4749,20 @@ ganache-cli@^6.12.2: source-map-support "0.5.12" yargs "13.2.4" +generate-function@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + integrity sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ== + dependencies: + is-property "^1.0.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -5500,6 +5553,22 @@ is-lower-case@^1.1.0: dependencies: lower-case "^1.1.0" +is-my-ip-valid@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz#f7220d1146257c98672e6fba097a9f3f2d348442" + integrity sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg== + +is-my-json-valid@^2.20.6: + version "2.20.6" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz#a9d89e56a36493c77bda1440d69ae0dc46a08387" + integrity sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw== + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + is-my-ip-valid "^1.0.0" + jsonpointer "^5.0.0" + xtend "^4.0.0" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -5527,6 +5596,11 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-property@^1.0.0, is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -5850,6 +5924,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonpointer@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== + jsonschema@^1.2.4: version "1.4.1" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" @@ -9221,27 +9300,27 @@ web3-core@1.8.2: web3-core-requestmanager "1.8.2" web3-utils "1.8.2" -web3-core@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.0.1-rc.1.tgz#680bac30b8a2e819f651d181bc865de880fc37a3" - integrity sha512-Sf9lKbkOPsTVN9HwWEmirX1X3tcjThQFyNxEIOKnxTwnUg/eza1j8m+c//xRCe7EBP0EWmqrjsXLkeMdPnV9VA== - dependencies: - web3-errors "^1.0.0-rc.1" - web3-eth-iban "^4.0.1-rc.1" - web3-providers-http "^4.0.1-rc.1" - web3-providers-ws "^4.0.1-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" +web3-core@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.0.1.tgz#81bfafe3546e62560bd9ee35a62af667419f2c71" + integrity sha512-yGd9FuUhSeLXeSmj+S5YBNdBJfQgBsGGN+uqFRvQKGrKbOp7SXRVNxwTL/JKCLJW2rulcw0JrPD8Ope0A1YvZA== + dependencies: + web3-errors "^1.0.0" + web3-eth-iban "^4.0.1" + web3-providers-http "^4.0.1" + web3-providers-ws "^4.0.1" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" optionalDependencies: - web3-providers-ipc "^4.0.1-rc.1" + web3-providers-ipc "^4.0.1" -web3-errors@^1.0.0-rc.1: - version "1.0.0-rc.1" - resolved "https://registry.yarnpkg.com/web3-errors/-/web3-errors-1.0.0-rc.1.tgz#55d2ef3c6890bfbacf1d4d6f036b417e9a56fe99" - integrity sha512-0okx1ZAECh+BvtaN6UShSP8z3tt36wRQzbcEbfe8g/qFfcSPVeQk+VJ69iE+wGQya4NzWelYxkxwbwUsUkm8cA== +web3-errors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/web3-errors/-/web3-errors-1.0.0.tgz#c0464d19b8330ec2098b755f8c18330c4ec345e5" + integrity sha512-UadVmAm7FrWfIglZEbyKxEEeVp4p7SMrx1q1SNbX4Cngmsenth96oH+4GSSFLyDASGyWr/yDSDU2alEUTf0yug== dependencies: - web3-types "^1.0.0-rc.1" + web3-types "^1.0.0" web3-eth-abi@1.8.2: version "1.8.2" @@ -9251,16 +9330,16 @@ web3-eth-abi@1.8.2: "@ethersproject/abi" "^5.6.3" web3-utils "1.8.2" -web3-eth-abi@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-4.0.1-rc.1.tgz#b719d07c5b2bcdb3d9b798af7e267dba62c3a6f1" - integrity sha512-VKudlBkQb6JUauRjAJikjzXq93yyz6Y5jyVbp57nS9Oz4zklpjwWR/n5bfykjAPL7VxzSeO27rfAOsvsA0NUdg== +web3-eth-abi@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-4.0.1.tgz#75464fb092b61276f1429d464eb5da4cebdeb474" + integrity sha512-l4vS3oxec8A5bO5ognCQQY+ZonPolw77roNVnFdqkmf3MQpUHHovxCn1kFD+eeiT3DpeSt6GbVT9Zt6koA/LHw== dependencies: "@ethersproject/abi" "^5.7.0" "@ethersproject/bignumber" "^5.7.0" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" web3-eth-accounts@1.8.2: version "1.8.2" @@ -9278,18 +9357,18 @@ web3-eth-accounts@1.8.2: web3-core-method "1.8.2" web3-utils "1.8.2" -web3-eth-accounts@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-4.0.1-rc.1.tgz#7a0b9675c811c67aa115a3797365fbe2210317a9" - integrity sha512-Ipimuf5v53m/NGqkPamIrLCgBPB9jfvfpEhftjkzr3HmmU8cCZuYZWYiM/XV8ZnoEATCnGkIR21QpiIq8GTFyg== +web3-eth-accounts@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-4.0.1.tgz#4eb226a3a43768758e614b71c39661ef819dc18e" + integrity sha512-4SyowjO930H8/Rz6jspYaW2jCbEpqPYKDU/W2WFOHl7KiJ0edoO3mVsupCGAJQCbDG77ijSwMszHj8pA5KhB+A== dependencies: "@ethereumjs/rlp" "^4.0.1" crc-32 "^1.2.2" - ethereum-cryptography "^1.1.2" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + ethereum-cryptography "^2.0.0" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-eth-contract@1.8.2: version "1.8.2" @@ -9305,18 +9384,18 @@ web3-eth-contract@1.8.2: web3-eth-abi "1.8.2" web3-utils "1.8.2" -web3-eth-contract@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-4.0.1-rc.1.tgz#70b525621255226073b6301901161ecd7050a5ac" - integrity sha512-v88K4dWS1xbtfBPCcHJv/Kff+oYD7ulIabvg3CUG9hxf2GxorV1wWoJ7F/kYoKXP1uZy+cQoZYe/UDwloWdQRg== +web3-eth-contract@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-4.0.1.tgz#7d753e550ecc97f42a8dcba0d24365d3b17e95e0" + integrity sha512-uVVb1ZZre/kwZIDFJBu7y2LdW5BZO3HJwQKhdqLmnyPTLWTnyKE8Mq2pX5eUZzpoSqXlJCoh0GeAQnIblXYsAw== dependencies: - web3-core "^4.0.1-rc.1" - web3-errors "^1.0.0-rc.1" - web3-eth "^4.0.1-rc.1" - web3-eth-abi "^4.0.1-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + web3-core "^4.0.1" + web3-errors "^1.0.0" + web3-eth "^4.0.1" + web3-eth-abi "^4.0.1" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-eth-ens@1.8.2: version "1.8.2" @@ -9332,20 +9411,20 @@ web3-eth-ens@1.8.2: web3-eth-contract "1.8.2" web3-utils "1.8.2" -web3-eth-ens@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-4.0.1-rc.1.tgz#5f1e61affbc6e0adeed7e7c5f96c0a9f3df74faa" - integrity sha512-Z2avvDK9fO7DDi4iCb3/L7J6AHHCeBVSUN4zr0Wza0saL3m8oC+m5UB5ZOtnsQAoey51eYo3K46KS5AQuimwKw== +web3-eth-ens@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-4.0.1.tgz#eb89736d4b17360610bc2cddc978ddd359ba2e75" + integrity sha512-AIPNKs5EyY+w9grIaDkaOxApilBT8Gi7RxJfrVGjR9UnGbHRiH3QX//Y7ZEEkFrhKnZMZ2uim81gyTHP4ujYmg== dependencies: "@adraffy/ens-normalize" "^1.8.8" - web3-core "^4.0.1-rc.1" - web3-errors "^1.0.0-rc.1" - web3-eth "^4.0.1-rc.1" - web3-eth-contract "^4.0.1-rc.1" - web3-net "^4.0.1-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + web3-core "^4.0.1" + web3-errors "^1.0.0" + web3-eth "^4.0.1" + web3-eth-contract "^4.0.1" + web3-net "^4.0.1" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-eth-iban@1.8.2: version "1.8.2" @@ -9355,15 +9434,15 @@ web3-eth-iban@1.8.2: bn.js "^5.2.1" web3-utils "1.8.2" -web3-eth-iban@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-4.0.1-rc.1.tgz#1b1f0dd3ae94b81159058de3979719277b03b837" - integrity sha512-dwiFpj7EsXGpiVvS8bAk++xptHmVpqGDoWx/jVdWoc3WaeylZudd9khEbJ1w8KLtRFofLZ5E4yLAYA68K6TWkQ== +web3-eth-iban@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-4.0.1.tgz#8271607b3ca0f4b7062456d7f13b0b2eb2de95dc" + integrity sha512-SSwbB2+8+IlF97zk6wwdDv2rPAoIfXAsjLKBCRy6abf4lLFX3M1s80ZLCXISeB3DR72MvO4iqA5/hHlUu9Jlcg== dependencies: - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-eth-personal@1.8.2: version "1.8.2" @@ -9377,17 +9456,17 @@ web3-eth-personal@1.8.2: web3-net "1.8.2" web3-utils "1.8.2" -web3-eth-personal@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-4.0.1-rc.1.tgz#1f2cb84bfa058b94264bb5eac64cc60e4128532a" - integrity sha512-AmEGgXuqBh1IP+mnIuCqv/+r7HhCKhGULxDg9QIWQHQmN/9+debkUQaYU6RU0TftlcsKk8q5jwGdEInTCbMTZA== +web3-eth-personal@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-4.0.1.tgz#44056345f90ad340048789b2274bbaa7b600c660" + integrity sha512-fv/PiUYNtQhjYanHJ+veT5xp7+l+HUGk2/vklGxwl9ntrzvgdYJ7Z87WXI+dqzYAljyuunsjEVP4N5QPED5n7g== dependencies: - web3-core "^4.0.1-rc.1" - web3-eth "^4.0.1-rc.1" - web3-rpc-methods "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + web3-core "^4.0.1" + web3-eth "^4.0.1" + web3-rpc-methods "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-eth@1.8.2: version "1.8.2" @@ -9407,22 +9486,22 @@ web3-eth@1.8.2: web3-net "1.8.2" web3-utils "1.8.2" -web3-eth@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-4.0.1-rc.1.tgz#33031523a0a7792022da9c3604c50c55eb4626a6" - integrity sha512-O6Grd8W0UEGPM1vO0o0c/N3Lb0mcgOvXumPP4nlIvEXljBGvnaW/iyj6LuOjAMoj4HZOe0pLeC4g1Xt96gOtoA== +web3-eth@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-4.0.1.tgz#ce94a7ecf0e5879fb7b8d3623960355fbc50a9e1" + integrity sha512-5Tm6uusfZlWDby1zc8unoHtph5wpLoBgnRvtkzB3ZCwnQKL4KU2kqO/y4sUTSVrTM30y/CmZagTW9PKyRAt0UA== dependencies: setimmediate "^1.0.5" - web3-core "^4.0.1-rc.1" - web3-errors "^1.0.0-rc.1" - web3-eth-abi "^4.0.1-rc.1" - web3-eth-accounts "^4.0.1-rc.1" - web3-net "^4.0.1-rc.1" - web3-providers-ws "^4.0.1-rc.1" - web3-rpc-methods "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" + web3-core "^4.0.1" + web3-errors "^1.0.0" + web3-eth-abi "^4.0.1" + web3-eth-accounts "^4.0.1" + web3-net "^4.0.1" + web3-providers-ws "^4.0.1" + web3-rpc-methods "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" web3-net@1.8.2: version "1.8.2" @@ -9433,15 +9512,15 @@ web3-net@1.8.2: web3-core-method "1.8.2" web3-utils "1.8.2" -web3-net@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-4.0.1-rc.1.tgz#d1a1ef284c3b8beb77c8ffcdce44455af071258d" - integrity sha512-NOkgw0htSF5S0RAmfgkB8BVwdFsRd4X8Z7gIOdjLPL/IBVxi1u2XEt924MEkodJslu8f3UE62m09tKkbMgRQHw== +web3-net@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-4.0.1.tgz#263014e2712e12301da3614f8bd5fbfea6d83ba7" + integrity sha512-Fa4NyGyjx/aZwNxdFg1tSkZAQKyEYxfGOFjmsPCzfOC2zaFExv06UPgDEU+aOiY28cs+kTcx5mhjBKn9PLRraw== dependencies: - web3-core "^4.0.1-rc.1" - web3-rpc-methods "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" + web3-core "^4.0.1" + web3-rpc-methods "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" web3-providers-http@1.8.2: version "1.8.2" @@ -9453,15 +9532,15 @@ web3-providers-http@1.8.2: es6-promise "^4.2.8" web3-core-helpers "1.8.2" -web3-providers-http@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-4.0.1-rc.1.tgz#5af0adf2e19a2014fd158bdd701ffab9fa9baf68" - integrity sha512-pYenobNL3fv83uKqumnvfS7vymBo4qJkmvsAPF+bVCNtS9zjd1OG1ylsQu6B04V/y8IQVvy3LKRX0kwxUiYdrA== +web3-providers-http@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-4.0.1.tgz#a5fd9743176e07326792e52064e089aa18840abe" + integrity sha512-scdCB7bmUkZon3nxtP1LRByt16wiaksZtFOwk/sFrVHMbjYjqMvY5asWF+omTgawM20Ga22ESrV2l5FFsQodqA== dependencies: cross-fetch "^3.1.5" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" web3-providers-ipc@1.8.2: version "1.8.2" @@ -9471,14 +9550,14 @@ web3-providers-ipc@1.8.2: oboe "2.1.5" web3-core-helpers "1.8.2" -web3-providers-ipc@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-4.0.1-rc.1.tgz#257750f22e4163115b54156ebe15fa3c19e646bd" - integrity sha512-R86g4CNPIYoqktPXqAfLWBVTVyt5Een0jpqFy0vSsdGdoR9g1v03o+sx5/++BCWYNRAg/fFmscYGjbjZWbhg5Q== +web3-providers-ipc@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-4.0.1.tgz#ea95af4caed2253d237cf67de28fff3fffc27fb3" + integrity sha512-F93UU9LyY5XIC3pHd2Ah3FO6lAbfkPoPUa9yYHgZhwWteZkeo8mDThDYg90QUBvP7qt22vyVpwVNXpw6Hs/QMg== dependencies: - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" web3-providers-ws@1.8.2: version "1.8.2" @@ -9489,25 +9568,25 @@ web3-providers-ws@1.8.2: web3-core-helpers "1.8.2" websocket "^1.0.32" -web3-providers-ws@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-4.0.1-rc.1.tgz#4c4e6ecef0170e91a68e3ff110ea551b9cd6882a" - integrity sha512-xGtqErSxXJPwLX2DY98HGITdX6zdABEvrBmkoha5LHdGy1SfUuiPQ9/60Qlli8LmyxhJxwB6J4082HZQwBSPZA== +web3-providers-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-4.0.1.tgz#813f3e2f65e68e0ab55cde1693ab5f8326c34f14" + integrity sha512-TkNLyCkdZ7bBURbSv4+/AP6K4WjS24vuNFbJSyBDgJfmCQxi2/3hX/l+XT/AqkHj7c8amm4yuOZ6JnIkwIlzaw== dependencies: isomorphic-ws "^5.0.0" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" ws "^8.8.1" -web3-rpc-methods@^1.0.0-rc.1: - version "1.0.0-rc.1" - resolved "https://registry.yarnpkg.com/web3-rpc-methods/-/web3-rpc-methods-1.0.0-rc.1.tgz#f1dd716d64ba753d212d9b02132a89e8c7d87bf6" - integrity sha512-5Xev86E5jCPDJAW4BEfOpMj7y/vB021xLCC0Xz5+Ggl4AyU/0yUInnO5NN/ZLFoZrPzCG8aT+M8Pgc2+hYFLrQ== +web3-rpc-methods@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/web3-rpc-methods/-/web3-rpc-methods-1.0.0.tgz#d570d10d0f65fea43f8dd3c116792f272d70a077" + integrity sha512-s3awsumvzz0pHxPi3oZxA9IK0Ei1lfZnNqkZ9AMhJjKpIXcPuUhUjYxiAsL1Q9pEcn5vGOLfq1RHNUdXrhNOrQ== dependencies: - web3-core "^4.0.1-rc.1" - web3-types "^1.0.0-rc.1" - web3-validator "^1.0.0-rc.1" + web3-core "^4.0.1" + web3-types "^1.0.0" + web3-validator "^1.0.0" web3-shh@1.8.2: version "1.8.2" @@ -9519,10 +9598,10 @@ web3-shh@1.8.2: web3-core-subscriptions "1.8.2" web3-net "1.8.2" -web3-types@^1.0.0-rc.1: - version "1.0.0-rc.1" - resolved "https://registry.yarnpkg.com/web3-types/-/web3-types-1.0.0-rc.1.tgz#307a45a9ee6f0f75a37739ec7f9f46fda4353626" - integrity sha512-yqoCkP8VTYxiCDhL0u/VQxBZXUXRcWq5tuw2fZD8VCr21w5EPDJ1wvwODlcGbrBT/Bacqeoi9kNb6FXYiUe7pA== +web3-types@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/web3-types/-/web3-types-1.0.0.tgz#086dddd9696f137620f6a5054dec7c154cccbc5e" + integrity sha512-X6MwXgaZmSCEmqwLnUYVVDn5N3G8RlKStizyy+yOK7qP2VHflM8Pk9ja3VifIXmT1cHgdfLKNBapwAict1X+IA== web3-utils@1.8.2, web3-utils@^1.0.0-beta.31, web3-utils@^1.3.6: version "1.8.2" @@ -9537,25 +9616,26 @@ web3-utils@1.8.2, web3-utils@^1.0.0-beta.31, web3-utils@^1.3.6: randombytes "^2.1.0" utf8 "3.0.0" -web3-utils@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-4.0.1-rc.1.tgz#ed12679595194ad7773b07ef5907e7c0d7a8d15a" - integrity sha512-LLu3X63paQUhtv4+UlGdmGKnwqDmdq+UzRTHecCdGKNPukiho5um5O2fS/9I+l21OXIgQPLqPSc49DuAkO57jg== +web3-utils@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-4.0.1.tgz#c743d408ce8c307191961e881b72a020360b9011" + integrity sha512-q5Pys++MarxUtN/OWrtv7l2kpNBJdDbV13/doO7A2W8I+TqigakKEJQtKiyAIbfnifrIZqyT7+/zzCfPS/sLnw== dependencies: - ethereum-cryptography "^1.1.2" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-validator "^1.0.0-rc.1" + ethereum-cryptography "^2.0.0" + web3-errors "^1.0.0" + web3-types "^1.0.0" + web3-validator "^1.0.0" -web3-validator@^1.0.0-rc.1: - version "1.0.0-rc.1" - resolved "https://registry.yarnpkg.com/web3-validator/-/web3-validator-1.0.0-rc.1.tgz#e07266b0efbfb5014c6ca015bbad05c009229dcc" - integrity sha512-a6hgW4ZXkDzy22axDPnD8eW0RwYVWHedw0Un+uLsGcvZxqIh5+EKFPmo57wK6wPq+8/OgdVzxQtzDwX5S43Kmg== +web3-validator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/web3-validator/-/web3-validator-1.0.0.tgz#65860fd735b77c20927f53c2a0a0bb5776460585" + integrity sha512-WShojVeF7hcaPGzO9vgZukqxd6NWL5A9sIv5uhZzK0mGPvPvc0wqSdKeiwby0cFDH09AW2Q1Qz6knKhXDe7CzA== dependencies: - ajv "^8.11.0" - ethereum-cryptography "^1.1.2" - web3-errors "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" + ethereum-cryptography "^2.0.0" + is-my-json-valid "^2.20.6" + util "^0.12.5" + web3-errors "^1.0.0" + web3-types "^1.0.0" web3@0.20.6: version "0.20.6" @@ -9592,27 +9672,27 @@ web3@^0.20.0: xhr2-cookies "^1.1.0" xmlhttprequest "*" -web3@^4.0.1-rc.1: - version "4.0.1-rc.1" - resolved "https://registry.yarnpkg.com/web3/-/web3-4.0.1-rc.1.tgz#838e6c0d7dfe28a613d2e6772d7e007b82272ae2" - integrity sha512-86ot77U+Dxwc3kx8WNDYFB020mf8TCy9R0CXlOGPzmMWSEonBrE1VLwJxECDICMPxXhlmxpXYbvmOojBzMzIbw== - dependencies: - web3-core "^4.0.1-rc.1" - web3-errors "^1.0.0-rc.1" - web3-eth "^4.0.1-rc.1" - web3-eth-abi "^4.0.1-rc.1" - web3-eth-accounts "^4.0.1-rc.1" - web3-eth-contract "^4.0.1-rc.1" - web3-eth-ens "^4.0.1-rc.1" - web3-eth-iban "^4.0.1-rc.1" - web3-eth-personal "^4.0.1-rc.1" - web3-net "^4.0.1-rc.1" - web3-providers-http "^4.0.1-rc.1" - web3-providers-ws "^4.0.1-rc.1" - web3-rpc-methods "^1.0.0-rc.1" - web3-types "^1.0.0-rc.1" - web3-utils "^4.0.1-rc.1" - web3-validator "^1.0.0-rc.1" +web3@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-4.0.1.tgz#3b9a7978b1ae4568b535626ebdbfefd9cb07c23f" + integrity sha512-IVxPbRy3A+RYB2+NYReNPLDXvE2iamTTvx1oNjM4UdbhNt/KQujQusOaRfSpGqfIKBCIYrim1c5LSCFcKlfQhA== + dependencies: + web3-core "^4.0.1" + web3-errors "^1.0.0" + web3-eth "^4.0.1" + web3-eth-abi "^4.0.1" + web3-eth-accounts "^4.0.1" + web3-eth-contract "^4.0.1" + web3-eth-ens "^4.0.1" + web3-eth-iban "^4.0.1" + web3-eth-personal "^4.0.1" + web3-net "^4.0.1" + web3-providers-http "^4.0.1" + web3-providers-ws "^4.0.1" + web3-rpc-methods "^1.0.0" + web3-types "^1.0.0" + web3-utils "^4.0.1" + web3-validator "^1.0.0" webidl-conversions@^3.0.0: version "3.0.1" From d469cef6d54b2e9284bb3e8a36660cd6c359a767 Mon Sep 17 00:00:00 2001 From: Marin Petrunic Date: Mon, 12 Jun 2023 12:57:41 +0200 Subject: [PATCH 95/95] add changeset Signed-off-by: Marin Petrunic --- .changeset/neat-impalas-attend.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/neat-impalas-attend.md diff --git a/.changeset/neat-impalas-attend.md b/.changeset/neat-impalas-attend.md new file mode 100644 index 0000000000..4c55079548 --- /dev/null +++ b/.changeset/neat-impalas-attend.md @@ -0,0 +1,5 @@ +--- +"@nomiclabs/hardhat-web3": major +--- + +Updates web3 to latest 4.x version.