Skip to content

Commit ec5d587

Browse files
authored
Merge pull request #5708 from TateB/viem-small-tweaks
fix(hardhat-viem): type consistency + retryCount 0 on devnet
2 parents 6ec0e83 + 6010386 commit ec5d587

File tree

6 files changed

+141
-52
lines changed

6 files changed

+141
-52
lines changed

.changeset/kind-radios-begin.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nomicfoundation/hardhat-viem": patch
3+
---
4+
5+
Moved types to `HardhatViemHelpers` and initialized `ContractTypesMap` as empty for better extensibility. Improved performance by disabling retries in dev nets (thanks @TateB!)

packages/hardhat-viem/src/internal/clients.ts

+38-18
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@ import type {
1313
WalletClient,
1414
} from "../types";
1515

16+
async function getParameters<TConfig extends {} | undefined>(
17+
chain: Chain,
18+
config: TConfig
19+
) {
20+
const { isDevelopmentNetwork } = await import("./chains");
21+
22+
const defaultParameters = isDevelopmentNetwork(chain.id)
23+
? { pollingInterval: 50, cacheTime: 0 }
24+
: {};
25+
26+
const transportParameters = isDevelopmentNetwork(chain.id)
27+
? { retryCount: 0 }
28+
: {};
29+
30+
return {
31+
clientParameters: { ...defaultParameters, ...config },
32+
transportParameters,
33+
};
34+
}
35+
1636
/**
1737
* Get a PublicClient instance. This is a read-only client that can be used to
1838
* query the blockchain.
@@ -36,16 +56,15 @@ export async function innerGetPublicClient(
3656
publicClientConfig?: Partial<PublicClientConfig>
3757
): Promise<PublicClient> {
3858
const viem = await import("viem");
39-
const { isDevelopmentNetwork } = await import("./chains");
40-
const defaultParameters = isDevelopmentNetwork(chain.id)
41-
? { pollingInterval: 50, cacheTime: 0 }
42-
: {};
43-
const parameters = { ...defaultParameters, ...publicClientConfig };
59+
const { clientParameters, transportParameters } = await getParameters(
60+
chain,
61+
publicClientConfig
62+
);
4463

4564
const publicClient = viem.createPublicClient({
4665
chain,
47-
transport: viem.custom(provider),
48-
...parameters,
66+
transport: viem.custom(provider, transportParameters),
67+
...clientParameters,
4968
});
5069

5170
return publicClient;
@@ -78,18 +97,17 @@ export async function innerGetWalletClients(
7897
walletClientConfig?: Partial<WalletClientConfig>
7998
): Promise<WalletClient[]> {
8099
const viem = await import("viem");
81-
const { isDevelopmentNetwork } = await import("./chains");
82-
const defaultParameters = isDevelopmentNetwork(chain.id)
83-
? { pollingInterval: 50, cacheTime: 0 }
84-
: {};
85-
const parameters = { ...defaultParameters, ...walletClientConfig };
100+
const { clientParameters, transportParameters } = await getParameters(
101+
chain,
102+
walletClientConfig
103+
);
86104

87105
const walletClients = accounts.map((account) =>
88106
viem.createWalletClient({
89107
chain,
90108
account,
91-
transport: viem.custom(provider),
92-
...parameters,
109+
transport: viem.custom(provider, transportParameters),
110+
...clientParameters,
93111
})
94112
);
95113

@@ -142,14 +160,16 @@ export async function innerGetTestClient(
142160
testClientConfig?: Partial<TestClientConfig>
143161
): Promise<TestClient> {
144162
const viem = await import("viem");
145-
const defaultParameters = { pollingInterval: 50, cacheTime: 0 };
146-
const parameters = { ...defaultParameters, ...testClientConfig };
163+
const { clientParameters, transportParameters } = await getParameters(
164+
chain,
165+
testClientConfig
166+
);
147167

148168
const testClient = viem.createTestClient({
149169
mode,
150170
chain,
151-
transport: viem.custom(provider),
152-
...parameters,
171+
transport: viem.custom(provider, transportParameters),
172+
...clientParameters,
153173
});
154174

155175
return testClient;

packages/hardhat-viem/src/internal/type-extensions.ts

+5-32
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,20 @@
1-
import type {
2-
Address,
3-
PublicClientConfig,
4-
WalletClientConfig,
5-
TestClientConfig,
6-
} from "viem";
7-
import type {
8-
PublicClient,
9-
TestClient,
10-
WalletClient,
11-
deployContract,
12-
sendDeploymentTransaction,
13-
getContractAt,
14-
} from "../types";
1+
import type { HardhatViemHelpers } from "../types";
152
import "hardhat/types/runtime";
163
import "hardhat/types/artifacts";
174

185
declare module "hardhat/types/runtime" {
196
interface HardhatRuntimeEnvironment {
20-
viem: {
21-
getPublicClient(
22-
publicClientConfig?: Partial<PublicClientConfig>
23-
): Promise<PublicClient>;
24-
getWalletClients(
25-
walletClientConfig?: Partial<WalletClientConfig>
26-
): Promise<WalletClient[]>;
27-
getWalletClient(
28-
address: Address,
29-
walletClientConfig?: Partial<WalletClientConfig>
30-
): Promise<WalletClient>;
31-
getTestClient(
32-
testClientConfig?: Partial<TestClientConfig>
33-
): Promise<TestClient>;
34-
deployContract: typeof deployContract;
35-
sendDeploymentTransaction: typeof sendDeploymentTransaction;
36-
getContractAt: typeof getContractAt;
37-
};
7+
viem: HardhatViemHelpers;
388
}
399
}
4010

4111
declare module "hardhat/types/artifacts" {
4212
// eslint-disable-next-line @typescript-eslint/no-empty-interface
4313
interface ArtifactsMap {}
4414

15+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
16+
interface ContractTypesMap {}
17+
4518
interface Artifacts {
4619
readArtifact<ArgT extends keyof ArtifactsMap>(
4720
contractNameOrFullyQualifiedName: ArgT

packages/hardhat-viem/src/types.ts

+19
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,23 @@ export declare function getContractAt<CN extends string>(
8383
config?: GetContractAtConfig
8484
): Promise<GetContractReturnType>;
8585

86+
export interface HardhatViemHelpers {
87+
getPublicClient(
88+
publicClientConfig?: Partial<viemT.PublicClientConfig>
89+
): Promise<PublicClient>;
90+
getWalletClients(
91+
walletClientConfig?: Partial<viemT.WalletClientConfig>
92+
): Promise<WalletClient[]>;
93+
getWalletClient(
94+
address: viemT.Address,
95+
walletClientConfig?: Partial<viemT.WalletClientConfig>
96+
): Promise<WalletClient>;
97+
getTestClient(
98+
testClientConfig?: Partial<viemT.TestClientConfig>
99+
): Promise<TestClient>;
100+
deployContract: typeof deployContract;
101+
sendDeploymentTransaction: typeof sendDeploymentTransaction;
102+
getContractAt: typeof getContractAt;
103+
}
104+
86105
export type { AbiParameterToPrimitiveType } from "abitype";

packages/hardhat-viem/test/clients.ts

+68-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { EthereumProvider } from "hardhat/types";
22

3-
import { assert } from "chai";
3+
import { assert, expect } from "chai";
44
import * as chains from "viem/chains";
55

66
import {
@@ -32,6 +32,7 @@ describe("clients", () => {
3232

3333
assert.equal(client.pollingInterval, 1000);
3434
assert.equal(client.cacheTime, 2000);
35+
assert.equal(client.transport.retryCount, 3);
3536
});
3637

3738
it("should return a public client with default parameters for development networks", async () => {
@@ -41,6 +42,29 @@ describe("clients", () => {
4142

4243
assert.equal(client.pollingInterval, 50);
4344
assert.equal(client.cacheTime, 0);
45+
assert.equal(client.transport.retryCount, 0);
46+
});
47+
48+
it("should retry failed calls on public client", async () => {
49+
const provider = new EthereumMockedProvider();
50+
51+
const client = await innerGetPublicClient(provider, chains.mainnet);
52+
53+
await expect(client.getBlockNumber()).to.eventually.be.rejectedWith(
54+
/unknown RPC error/
55+
);
56+
assert.equal(provider.calledCount, 4);
57+
});
58+
59+
it("should not retry failed calls on public client when using a development network", async () => {
60+
const provider = new EthereumMockedProvider();
61+
62+
const client = await innerGetPublicClient(provider, chains.hardhat);
63+
64+
await expect(client.getBlockNumber()).to.eventually.be.rejectedWith(
65+
/unknown RPC error/
66+
);
67+
assert.equal(provider.calledCount, 1);
4468
});
4569
});
4670

@@ -97,9 +121,36 @@ describe("clients", () => {
97121
clients.forEach((client) => {
98122
assert.equal(client.pollingInterval, 50);
99123
assert.equal(client.cacheTime, 0);
124+
assert.equal(client.transport.retryCount, 0);
100125
});
101126
});
102127

128+
it("should retry failed calls on wallet client", async () => {
129+
const provider = new EthereumMockedProvider();
130+
131+
const [client] = await innerGetWalletClients(provider, chains.mainnet, [
132+
"0x1",
133+
]);
134+
135+
await expect(client.getChainId()).to.eventually.be.rejectedWith(
136+
/unknown RPC error/
137+
);
138+
assert.equal(provider.calledCount, 4);
139+
});
140+
141+
it("should not retry failed calls on wallet client when using a development network", async () => {
142+
const provider = new EthereumMockedProvider();
143+
144+
const [client] = await innerGetWalletClients(provider, chains.hardhat, [
145+
"0x1",
146+
]);
147+
148+
await expect(client.getChainId()).to.eventually.be.rejectedWith(
149+
/unknown RPC error/
150+
);
151+
assert.equal(provider.calledCount, 1);
152+
});
153+
103154
it("should return an empty array if there are no accounts owned by the user", async () => {
104155
const provider: EthereumProvider = new EthereumMockedProvider();
105156

@@ -169,6 +220,22 @@ describe("clients", () => {
169220

170221
assert.equal(client.pollingInterval, 50);
171222
assert.equal(client.cacheTime, 0);
223+
assert.equal(client.transport.retryCount, 0);
224+
});
225+
226+
it("should not retry failed calls on test client", async () => {
227+
const provider = new EthereumMockedProvider();
228+
229+
const client = await innerGetTestClient(
230+
provider,
231+
chains.hardhat,
232+
"hardhat"
233+
);
234+
235+
await expect(client.getAutomine()).to.eventually.be.rejectedWith(
236+
/unknown RPC error/
237+
);
238+
assert.equal(provider.calledCount, 1);
172239
});
173240
});
174241
});

packages/hardhat-viem/test/mocks/provider.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ export class EthereumMockedProvider
1111
extends EventEmitter
1212
implements EthereumProvider
1313
{
14-
public async request(_args: RequestArguments): Promise<any> {}
14+
public calledCount = 0;
15+
16+
public async request(_args: RequestArguments): Promise<any> {
17+
this.calledCount++;
18+
throw new Error();
19+
}
1520

1621
public async send(_method: string, _params: any[] = []) {}
1722

0 commit comments

Comments
 (0)