From 1bffc5f9dbd037cecd5f638b41acacb945a2bd7f Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:33:58 +0100 Subject: [PATCH 1/4] add logic to support attach method --- .../src/internal/generate-types.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/v-next/hardhat-typechain/src/internal/generate-types.ts b/v-next/hardhat-typechain/src/internal/generate-types.ts index 59b66d6ff6..a1481fdf38 100644 --- a/v-next/hardhat-typechain/src/internal/generate-types.ts +++ b/v-next/hardhat-typechain/src/internal/generate-types.ts @@ -110,6 +110,8 @@ function addCompiledFilesTransformerIfAbsent( 'declare module "@nomicfoundation/hardhat-ethers/types"', ); + modifiedContent = addSupportForAttachMethod(modifiedContent); + return modifiedContent; }; @@ -140,3 +142,37 @@ export function addJsExtensionsIfNeeded(content: string): string { `import ${imports} from ${quote}${path}/index.js${quote};`, ); } + +function addSupportForAttachMethod(modifiedContent: string): string { + const pattern = /class\s+(\w+)__factory/; // Pattern to find the contract name in factory files + const match = modifiedContent.match(pattern); + + if (match === null) { + // File is not a factory file, so there is no need to modify it + return modifiedContent; + } + + const contractName = match[1]; + + // Insert the "attach" snippet right before the "connect" method + const insertPoint = modifiedContent.lastIndexOf("static connect("); + + const attachMethod = ` + override attach(address: string | Addressable): ${contractName} { + return super.attach(address) as ${contractName}; + } + `; + + modifiedContent = + modifiedContent.slice(0, insertPoint) + + attachMethod + + modifiedContent.slice(insertPoint); + + // Import the "Addressable" type as it is required by the "attach" method + modifiedContent = modifiedContent.replace( + "/* eslint-disable */", + '/* eslint-disable */\nimport type { Addressable } from "ethers";', + ); + + return modifiedContent; +} From 89f95f9df37017eb1d51d6414e41907ed9e3b583 Mon Sep 17 00:00:00 2001 From: Christopher Dedominici <18092467+ChristopherDedominici@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:37:09 +0100 Subject: [PATCH 2/4] Create small-buckets-ring.md --- .changeset/small-buckets-ring.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/small-buckets-ring.md diff --git a/.changeset/small-buckets-ring.md b/.changeset/small-buckets-ring.md new file mode 100644 index 0000000000..8d9bc37139 --- /dev/null +++ b/.changeset/small-buckets-ring.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/hardhat-typechain": patch +--- + +Added support for the `attach` method in `hardhat-typechain`. From b105a2682a35b8d86a5b5d8e176a913b64d04d5d Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Tue, 4 Mar 2025 14:05:37 +0100 Subject: [PATCH 3/4] update tests --- v-next/hardhat-typechain/test/index.ts | 34 +++++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/v-next/hardhat-typechain/test/index.ts b/v-next/hardhat-typechain/test/index.ts index 25cfed3e7d..6fe4800f91 100644 --- a/v-next/hardhat-typechain/test/index.ts +++ b/v-next/hardhat-typechain/test/index.ts @@ -18,11 +18,6 @@ describe("hardhat-typechain", () => { before(async () => { await remove(`${process.cwd()}/types`); - }); - - it("should generate the types", async () => { - // Check that the types are generated with the expected addition of the "/index.js" extensions - // and the v3 modules const hardhatConfig = await import( // eslint-disable-next-line import/no-relative-packages -- allow for fixture projects @@ -36,6 +31,11 @@ describe("hardhat-typechain", () => { await hre.tasks.getTask("clean").run(); await hre.tasks.getTask("compile").run(); + }); + + it("should generate the types for the `hardhat.d.ts` file", async () => { + // Check that the types are generated with the expected addition of the "/index.js" extensions + // and the v3 modules const content = await readUtf8File( path.join(process.cwd(), "types", "ethers-contracts", "hardhat.d.ts"), @@ -63,12 +63,28 @@ describe("hardhat-typechain", () => { // The import from a npm package should have ".js" extensions assert.equal(content.includes(`import { ethers } from 'ethers'`), true); + }); - // Check that the types for the contract are generated - assert.equal( - await exists( - `${process.cwd()}/types/ethers-contracts/factories/A__factory.ts`, + it("should generated types for the contracts and add the support for the `attach` method", async () => { + const content = await readUtf8File( + path.join( + process.cwd(), + "types", + "ethers-contracts", + "factories", + "A__factory.ts", ), + ); + + // The "Addressable" type should be imported + assert.equal( + content.includes(`import type { Addressable } from "ethers";`), + true, + ); + + // The "attach" method should be added to the factory + assert.equal( + content.includes(`override attach(address: string | Addressable): A {`), true, ); }); From 287102a4ea8f3579edcb89e88f48aecb8a52d621 Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:25:17 +0100 Subject: [PATCH 4/4] add comment with example of factory file structure --- v-next/hardhat-typechain/src/internal/generate-types.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/v-next/hardhat-typechain/src/internal/generate-types.ts b/v-next/hardhat-typechain/src/internal/generate-types.ts index a1481fdf38..1ffb2e8510 100644 --- a/v-next/hardhat-typechain/src/internal/generate-types.ts +++ b/v-next/hardhat-typechain/src/internal/generate-types.ts @@ -143,6 +143,14 @@ export function addJsExtensionsIfNeeded(content: string): string { ); } +// We expect the structure of the factory files to be: +// /* eslint-disable */ +// ... +// export class [contractName]__factory extends ContractFactory { +// ... +// static connect( +// ... +// } function addSupportForAttachMethod(modifiedContent: string): string { const pattern = /class\s+(\w+)__factory/; // Pattern to find the contract name in factory files const match = modifiedContent.match(pattern);