@nomicfoundation/hardhat-viem 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +24 -0
- package/LICENSE +21 -0
- package/README.md +237 -0
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -0
- package/index.js +20 -0
- package/index.js.map +1 -0
- package/internal/accounts.d.ts +5 -0
- package/internal/accounts.d.ts.map +1 -0
- package/internal/accounts.js +9 -0
- package/internal/accounts.js.map +1 -0
- package/internal/chains.d.ts +7 -0
- package/internal/chains.d.ts.map +1 -0
- package/internal/chains.js +74 -0
- package/internal/chains.js.map +1 -0
- package/internal/clients.d.ts +45 -0
- package/internal/clients.d.ts.map +1 -0
- package/internal/clients.js +127 -0
- package/internal/clients.js.map +1 -0
- package/internal/contracts.d.ts +11 -0
- package/internal/contracts.d.ts.map +1 -0
- package/internal/contracts.js +155 -0
- package/internal/contracts.js.map +1 -0
- package/internal/errors.d.ts +23 -0
- package/internal/errors.d.ts.map +1 -0
- package/internal/errors.js +70 -0
- package/internal/errors.js.map +1 -0
- package/internal/tasks.d.ts +2 -0
- package/internal/tasks.d.ts.map +1 -0
- package/internal/tasks.js +224 -0
- package/internal/tasks.js.map +1 -0
- package/internal/type-extensions.d.ts +26 -0
- package/internal/type-extensions.d.ts.map +1 -0
- package/internal/type-extensions.js +5 -0
- package/internal/type-extensions.js.map +1 -0
- package/package.json +75 -0
- package/src/index.ts +42 -0
- package/src/internal/accounts.ts +9 -0
- package/src/internal/chains.ts +91 -0
- package/src/internal/clients.ts +152 -0
- package/src/internal/contracts.ts +243 -0
- package/src/internal/errors.ts +76 -0
- package/src/internal/tasks.ts +319 -0
- package/src/internal/type-extensions.ts +54 -0
- package/src/tsconfig.json +15 -0
- package/src/types.ts +77 -0
- package/types.d.ts +32 -0
- package/types.d.ts.map +1 -0
- package/types.js +3 -0
- package/types.js.map +1 -0
package/src/index.ts
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
import { extendEnvironment } from "hardhat/config";
|
2
|
+
|
3
|
+
import {
|
4
|
+
getPublicClient,
|
5
|
+
getWalletClients,
|
6
|
+
getWalletClient,
|
7
|
+
getTestClient,
|
8
|
+
} from "./internal/clients";
|
9
|
+
import {
|
10
|
+
deployContract,
|
11
|
+
sendDeploymentTransaction,
|
12
|
+
getContractAt,
|
13
|
+
} from "./internal/contracts";
|
14
|
+
import "./internal/type-extensions";
|
15
|
+
import "./internal/tasks";
|
16
|
+
|
17
|
+
extendEnvironment((hre) => {
|
18
|
+
const { provider } = hre.network;
|
19
|
+
|
20
|
+
hre.viem = {
|
21
|
+
getPublicClient: (publicClientConfig) =>
|
22
|
+
getPublicClient(provider, publicClientConfig),
|
23
|
+
|
24
|
+
getWalletClients: (walletClientConfig) =>
|
25
|
+
getWalletClients(provider, walletClientConfig),
|
26
|
+
|
27
|
+
getWalletClient: (address, walletClientConfig) =>
|
28
|
+
getWalletClient(provider, address, walletClientConfig),
|
29
|
+
|
30
|
+
getTestClient: (testClientConfig) =>
|
31
|
+
getTestClient(provider, testClientConfig),
|
32
|
+
|
33
|
+
deployContract: (contractName, constructorArgs, config) =>
|
34
|
+
deployContract(hre, contractName, constructorArgs, config),
|
35
|
+
|
36
|
+
sendDeploymentTransaction: (contractName, constructorArgs, config) =>
|
37
|
+
sendDeploymentTransaction(hre, contractName, constructorArgs, config),
|
38
|
+
|
39
|
+
getContractAt: (contractName, address, config) =>
|
40
|
+
getContractAt(hre, contractName, address, config),
|
41
|
+
};
|
42
|
+
});
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { EthereumProvider } from "hardhat/types";
|
2
|
+
import type { Address } from "viem";
|
3
|
+
|
4
|
+
import memoize from "lodash.memoize";
|
5
|
+
|
6
|
+
export const getAccounts = memoize(
|
7
|
+
async (provider: EthereumProvider): Promise<Address[]> =>
|
8
|
+
provider.send("eth_accounts")
|
9
|
+
);
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import type { EthereumProvider } from "hardhat/types";
|
2
|
+
import type { Chain } from "viem";
|
3
|
+
import type { TestClientMode } from "../types";
|
4
|
+
|
5
|
+
import memoize from "lodash.memoize";
|
6
|
+
|
7
|
+
import {
|
8
|
+
UnknownDevelopmentNetworkError,
|
9
|
+
NetworkNotFoundError,
|
10
|
+
MultipleMatchingNetworksError,
|
11
|
+
} from "./errors";
|
12
|
+
|
13
|
+
export async function getChain(provider: EthereumProvider): Promise<Chain> {
|
14
|
+
const chains: Record<string, Chain> = require("viem/chains");
|
15
|
+
const chainId = await getChainId(provider);
|
16
|
+
|
17
|
+
if (isDevelopmentNetwork(chainId)) {
|
18
|
+
if (await isHardhatNetwork(provider)) {
|
19
|
+
return chains.hardhat;
|
20
|
+
} else if (await isFoundryNetwork(provider)) {
|
21
|
+
return chains.foundry;
|
22
|
+
} else {
|
23
|
+
throw new UnknownDevelopmentNetworkError();
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
const matchingChains = Object.values(chains).filter(
|
28
|
+
({ id }) => id === chainId
|
29
|
+
);
|
30
|
+
|
31
|
+
if (matchingChains.length === 0) {
|
32
|
+
if (await isHardhatNetwork(provider)) {
|
33
|
+
return chains.hardhat;
|
34
|
+
} else if (await isFoundryNetwork(provider)) {
|
35
|
+
return chains.foundry;
|
36
|
+
} else {
|
37
|
+
throw new NetworkNotFoundError(chainId);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
if (matchingChains.length > 1) {
|
42
|
+
throw new MultipleMatchingNetworksError(chainId);
|
43
|
+
}
|
44
|
+
|
45
|
+
return matchingChains[0];
|
46
|
+
}
|
47
|
+
|
48
|
+
export function isDevelopmentNetwork(chainId: number) {
|
49
|
+
return chainId === 31337;
|
50
|
+
}
|
51
|
+
|
52
|
+
export async function getMode(
|
53
|
+
provider: EthereumProvider
|
54
|
+
): Promise<TestClientMode> {
|
55
|
+
if (await isHardhatNetwork(provider)) {
|
56
|
+
return "hardhat";
|
57
|
+
} else if (await isFoundryNetwork(provider)) {
|
58
|
+
return "anvil";
|
59
|
+
} else {
|
60
|
+
throw new UnknownDevelopmentNetworkError();
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
const getChainId = memoize(async (provider: EthereumProvider) =>
|
65
|
+
Number(await provider.send("eth_chainId"))
|
66
|
+
);
|
67
|
+
|
68
|
+
const isHardhatNetwork = memoize(async (provider: EthereumProvider) =>
|
69
|
+
detectNetworkByMethodName(provider, NetworkMethod.HARDHAT_METADATA)
|
70
|
+
);
|
71
|
+
|
72
|
+
const isFoundryNetwork = memoize(async (provider: EthereumProvider) =>
|
73
|
+
detectNetworkByMethodName(provider, NetworkMethod.ANVIL_NODE_INFO)
|
74
|
+
);
|
75
|
+
|
76
|
+
enum NetworkMethod {
|
77
|
+
HARDHAT_METADATA = "hardhat_metadata",
|
78
|
+
ANVIL_NODE_INFO = "anvil_nodeInfo",
|
79
|
+
}
|
80
|
+
|
81
|
+
async function detectNetworkByMethodName(
|
82
|
+
provider: EthereumProvider,
|
83
|
+
methodName: string
|
84
|
+
) {
|
85
|
+
try {
|
86
|
+
await provider.send(methodName);
|
87
|
+
return true;
|
88
|
+
} catch {
|
89
|
+
return false;
|
90
|
+
}
|
91
|
+
}
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import type { EthereumProvider } from "hardhat/types";
|
2
|
+
import type {
|
3
|
+
Address,
|
4
|
+
Chain,
|
5
|
+
PublicClientConfig,
|
6
|
+
WalletClientConfig,
|
7
|
+
TestClientConfig,
|
8
|
+
} from "viem";
|
9
|
+
import type {
|
10
|
+
PublicClient,
|
11
|
+
TestClient,
|
12
|
+
TestClientMode,
|
13
|
+
WalletClient,
|
14
|
+
} from "../types";
|
15
|
+
|
16
|
+
import { getChain, getMode, isDevelopmentNetwork } from "./chains";
|
17
|
+
import { getAccounts } from "./accounts";
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Get a PublicClient instance. This is a read-only client that can be used to
|
21
|
+
* query the blockchain.
|
22
|
+
*
|
23
|
+
* @param provider The Ethereum provider used to connect to the blockchain.
|
24
|
+
* @param publicClientConfig Optional configuration for the PublicClient instance. See the viem documentation for more information.
|
25
|
+
* @returns A PublicClient instance.
|
26
|
+
*/
|
27
|
+
export async function getPublicClient(
|
28
|
+
provider: EthereumProvider,
|
29
|
+
publicClientConfig?: Partial<PublicClientConfig>
|
30
|
+
): Promise<PublicClient> {
|
31
|
+
const chain = publicClientConfig?.chain ?? (await getChain(provider));
|
32
|
+
return innerGetPublicClient(provider, chain, publicClientConfig);
|
33
|
+
}
|
34
|
+
|
35
|
+
export async function innerGetPublicClient(
|
36
|
+
provider: EthereumProvider,
|
37
|
+
chain: Chain,
|
38
|
+
publicClientConfig?: Partial<PublicClientConfig>
|
39
|
+
): Promise<PublicClient> {
|
40
|
+
const viem = await import("viem");
|
41
|
+
const defaultParameters = isDevelopmentNetwork(chain.id)
|
42
|
+
? { pollingInterval: 50, cacheTime: 0 }
|
43
|
+
: {};
|
44
|
+
const parameters = { ...defaultParameters, ...publicClientConfig };
|
45
|
+
|
46
|
+
const publicClient = viem.createPublicClient({
|
47
|
+
chain,
|
48
|
+
transport: viem.custom(provider),
|
49
|
+
...parameters,
|
50
|
+
});
|
51
|
+
|
52
|
+
return publicClient;
|
53
|
+
}
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Get a list of WalletClient instances. These are read-write clients that can
|
57
|
+
* be used to send transactions to the blockchain. Each client is associated
|
58
|
+
* with a an account obtained from the provider using `eth_accounts`.
|
59
|
+
*
|
60
|
+
* @param provider The Ethereum provider used to connect to the blockchain.
|
61
|
+
* @param walletClientConfig Optional configuration for the WalletClient instances. See the viem documentation for more information.
|
62
|
+
* @returns A list of WalletClient instances.
|
63
|
+
*/
|
64
|
+
export async function getWalletClients(
|
65
|
+
provider: EthereumProvider,
|
66
|
+
walletClientConfig?: Partial<WalletClientConfig>
|
67
|
+
): Promise<WalletClient[]> {
|
68
|
+
const chain = walletClientConfig?.chain ?? (await getChain(provider));
|
69
|
+
const accounts = await getAccounts(provider);
|
70
|
+
return innerGetWalletClients(provider, chain, accounts, walletClientConfig);
|
71
|
+
}
|
72
|
+
|
73
|
+
export async function innerGetWalletClients(
|
74
|
+
provider: EthereumProvider,
|
75
|
+
chain: Chain,
|
76
|
+
accounts: Address[],
|
77
|
+
walletClientConfig?: Partial<WalletClientConfig>
|
78
|
+
): Promise<WalletClient[]> {
|
79
|
+
const viem = await import("viem");
|
80
|
+
const defaultParameters = isDevelopmentNetwork(chain.id)
|
81
|
+
? { pollingInterval: 50, cacheTime: 0 }
|
82
|
+
: {};
|
83
|
+
const parameters = { ...defaultParameters, ...walletClientConfig };
|
84
|
+
|
85
|
+
const walletClients = accounts.map((account) =>
|
86
|
+
viem.createWalletClient({
|
87
|
+
chain,
|
88
|
+
account,
|
89
|
+
transport: viem.custom(provider),
|
90
|
+
...parameters,
|
91
|
+
})
|
92
|
+
);
|
93
|
+
|
94
|
+
return walletClients;
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Get a WalletClient instance for a specific address. This is a read-write
|
99
|
+
* client that can be used to send transactions to the blockchain.
|
100
|
+
*
|
101
|
+
* @param provider The Ethereum provider used to connect to the blockchain.
|
102
|
+
* @param address The public address of the account to use.
|
103
|
+
* @param walletClientConfig Optional configuration for the WalletClient instance. See the viem documentation for more information.
|
104
|
+
* @returns A WalletClient instance.
|
105
|
+
*/
|
106
|
+
export async function getWalletClient(
|
107
|
+
provider: EthereumProvider,
|
108
|
+
address: Address,
|
109
|
+
walletClientConfig?: Partial<WalletClientConfig>
|
110
|
+
): Promise<WalletClient> {
|
111
|
+
const chain = walletClientConfig?.chain ?? (await getChain(provider));
|
112
|
+
return (
|
113
|
+
await innerGetWalletClients(provider, chain, [address], walletClientConfig)
|
114
|
+
)[0];
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Get a TestClient instance. This is a read-write client that can be used to
|
119
|
+
* perform actions only available on test nodes such as hardhat or anvil.
|
120
|
+
*
|
121
|
+
* @param provider The Ethereum provider used to connect to the blockchain.
|
122
|
+
* @param testClientConfig Optional configuration for the TestClient instance. See the viem documentation for more information.
|
123
|
+
* @returns A TestClient instance.
|
124
|
+
*/
|
125
|
+
export async function getTestClient(
|
126
|
+
provider: EthereumProvider,
|
127
|
+
testClientConfig?: Partial<TestClientConfig>
|
128
|
+
): Promise<TestClient> {
|
129
|
+
const chain = testClientConfig?.chain ?? (await getChain(provider));
|
130
|
+
const mode = await getMode(provider);
|
131
|
+
return innerGetTestClient(provider, chain, mode, testClientConfig);
|
132
|
+
}
|
133
|
+
|
134
|
+
export async function innerGetTestClient(
|
135
|
+
provider: EthereumProvider,
|
136
|
+
chain: Chain,
|
137
|
+
mode: TestClientMode,
|
138
|
+
testClientConfig?: Partial<TestClientConfig>
|
139
|
+
): Promise<TestClient> {
|
140
|
+
const viem = await import("viem");
|
141
|
+
const defaultParameters = { pollingInterval: 50, cacheTime: 0 };
|
142
|
+
const parameters = { ...defaultParameters, ...testClientConfig };
|
143
|
+
|
144
|
+
const testClient = viem.createTestClient({
|
145
|
+
mode,
|
146
|
+
chain,
|
147
|
+
transport: viem.custom(provider),
|
148
|
+
...parameters,
|
149
|
+
});
|
150
|
+
|
151
|
+
return testClient;
|
152
|
+
}
|
@@ -0,0 +1,243 @@
|
|
1
|
+
import type {
|
2
|
+
EthereumProvider,
|
3
|
+
HardhatRuntimeEnvironment,
|
4
|
+
} from "hardhat/types";
|
5
|
+
import type { Abi, Address, Hex } from "viem";
|
6
|
+
import type {
|
7
|
+
DeployContractConfig,
|
8
|
+
GetContractAtConfig,
|
9
|
+
GetContractReturnType,
|
10
|
+
GetTransactionReturnType,
|
11
|
+
PublicClient,
|
12
|
+
SendDeploymentTransactionConfig,
|
13
|
+
WalletClient,
|
14
|
+
} from "../types";
|
15
|
+
|
16
|
+
import { getPublicClient, getWalletClients } from "./clients";
|
17
|
+
import {
|
18
|
+
DefaultWalletClientNotFoundError,
|
19
|
+
DeployContractError,
|
20
|
+
HardhatViemError,
|
21
|
+
InvalidConfirmationsError,
|
22
|
+
} from "./errors";
|
23
|
+
|
24
|
+
export async function deployContract(
|
25
|
+
{ artifacts, network }: HardhatRuntimeEnvironment,
|
26
|
+
contractName: string,
|
27
|
+
constructorArgs: any[] = [],
|
28
|
+
config: DeployContractConfig = {}
|
29
|
+
): Promise<GetContractReturnType> {
|
30
|
+
const {
|
31
|
+
walletClient: configWalletClient,
|
32
|
+
confirmations,
|
33
|
+
...deployContractParameters
|
34
|
+
} = config;
|
35
|
+
const [publicClient, walletClient, contractArtifact] = await Promise.all([
|
36
|
+
getPublicClient(network.provider),
|
37
|
+
configWalletClient ??
|
38
|
+
getDefaultWalletClient(network.provider, network.name),
|
39
|
+
artifacts.readArtifact(contractName),
|
40
|
+
]);
|
41
|
+
|
42
|
+
return innerDeployContract(
|
43
|
+
publicClient,
|
44
|
+
walletClient,
|
45
|
+
contractArtifact.abi,
|
46
|
+
contractArtifact.bytecode as Hex,
|
47
|
+
constructorArgs,
|
48
|
+
deployContractParameters,
|
49
|
+
confirmations
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
export async function innerDeployContract(
|
54
|
+
publicClient: PublicClient,
|
55
|
+
walletClient: WalletClient,
|
56
|
+
contractAbi: Abi,
|
57
|
+
contractBytecode: Hex,
|
58
|
+
constructorArgs: any[],
|
59
|
+
deployContractParameters: DeployContractConfig = {},
|
60
|
+
confirmations: number = 1
|
61
|
+
): Promise<GetContractReturnType> {
|
62
|
+
let deploymentTxHash: Hex;
|
63
|
+
// If gasPrice is defined, then maxFeePerGas and maxPriorityFeePerGas
|
64
|
+
// must be undefined because it's a legaxy tx.
|
65
|
+
if (deployContractParameters.gasPrice !== undefined) {
|
66
|
+
deploymentTxHash = await walletClient.deployContract({
|
67
|
+
abi: contractAbi,
|
68
|
+
bytecode: contractBytecode,
|
69
|
+
args: constructorArgs,
|
70
|
+
...deployContractParameters,
|
71
|
+
maxFeePerGas: undefined,
|
72
|
+
maxPriorityFeePerGas: undefined,
|
73
|
+
});
|
74
|
+
} else {
|
75
|
+
deploymentTxHash = await walletClient.deployContract({
|
76
|
+
abi: contractAbi,
|
77
|
+
bytecode: contractBytecode,
|
78
|
+
args: constructorArgs,
|
79
|
+
...deployContractParameters,
|
80
|
+
gasPrice: undefined,
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
if (confirmations < 0) {
|
85
|
+
throw new HardhatViemError("Confirmations must be greater than 0.");
|
86
|
+
}
|
87
|
+
if (confirmations === 0) {
|
88
|
+
throw new InvalidConfirmationsError();
|
89
|
+
}
|
90
|
+
|
91
|
+
const { contractAddress } = await publicClient.waitForTransactionReceipt({
|
92
|
+
hash: deploymentTxHash,
|
93
|
+
confirmations,
|
94
|
+
});
|
95
|
+
|
96
|
+
if (contractAddress === null) {
|
97
|
+
const transaction = await publicClient.getTransaction({
|
98
|
+
hash: deploymentTxHash,
|
99
|
+
});
|
100
|
+
throw new DeployContractError(deploymentTxHash, transaction.blockNumber);
|
101
|
+
}
|
102
|
+
|
103
|
+
const contract = await innerGetContractAt(
|
104
|
+
publicClient,
|
105
|
+
walletClient,
|
106
|
+
contractAbi,
|
107
|
+
contractAddress
|
108
|
+
);
|
109
|
+
|
110
|
+
return contract;
|
111
|
+
}
|
112
|
+
|
113
|
+
export async function sendDeploymentTransaction(
|
114
|
+
{ artifacts, network }: HardhatRuntimeEnvironment,
|
115
|
+
contractName: string,
|
116
|
+
constructorArgs: any[] = [],
|
117
|
+
config: SendDeploymentTransactionConfig = {}
|
118
|
+
): Promise<{
|
119
|
+
contract: GetContractReturnType;
|
120
|
+
deploymentTransaction: GetTransactionReturnType;
|
121
|
+
}> {
|
122
|
+
const { walletClient: configWalletClient, ...deployContractParameters } =
|
123
|
+
config;
|
124
|
+
const [publicClient, walletClient, contractArtifact] = await Promise.all([
|
125
|
+
getPublicClient(network.provider),
|
126
|
+
configWalletClient ??
|
127
|
+
getDefaultWalletClient(network.provider, network.name),
|
128
|
+
artifacts.readArtifact(contractName),
|
129
|
+
]);
|
130
|
+
|
131
|
+
return innerSendDeploymentTransaction(
|
132
|
+
publicClient,
|
133
|
+
walletClient,
|
134
|
+
contractArtifact.abi,
|
135
|
+
contractArtifact.bytecode as Hex,
|
136
|
+
constructorArgs,
|
137
|
+
deployContractParameters
|
138
|
+
);
|
139
|
+
}
|
140
|
+
|
141
|
+
async function innerSendDeploymentTransaction(
|
142
|
+
publicClient: PublicClient,
|
143
|
+
walletClient: WalletClient,
|
144
|
+
contractAbi: Abi,
|
145
|
+
contractBytecode: Hex,
|
146
|
+
constructorArgs: any[],
|
147
|
+
deployContractParameters: SendDeploymentTransactionConfig = {}
|
148
|
+
): Promise<{
|
149
|
+
contract: GetContractReturnType;
|
150
|
+
deploymentTransaction: GetTransactionReturnType;
|
151
|
+
}> {
|
152
|
+
let deploymentTxHash: Hex;
|
153
|
+
// If gasPrice is defined, then maxFeePerGas and maxPriorityFeePerGas
|
154
|
+
// must be undefined because it's a legaxy tx.
|
155
|
+
if (deployContractParameters.gasPrice !== undefined) {
|
156
|
+
deploymentTxHash = await walletClient.deployContract({
|
157
|
+
abi: contractAbi,
|
158
|
+
bytecode: contractBytecode,
|
159
|
+
args: constructorArgs,
|
160
|
+
...deployContractParameters,
|
161
|
+
maxFeePerGas: undefined,
|
162
|
+
maxPriorityFeePerGas: undefined,
|
163
|
+
});
|
164
|
+
} else {
|
165
|
+
deploymentTxHash = await walletClient.deployContract({
|
166
|
+
abi: contractAbi,
|
167
|
+
bytecode: contractBytecode,
|
168
|
+
args: constructorArgs,
|
169
|
+
...deployContractParameters,
|
170
|
+
gasPrice: undefined,
|
171
|
+
});
|
172
|
+
}
|
173
|
+
|
174
|
+
const deploymentTx = await publicClient.getTransaction({
|
175
|
+
hash: deploymentTxHash,
|
176
|
+
});
|
177
|
+
|
178
|
+
const { getContractAddress } = await import("viem");
|
179
|
+
const contractAddress = getContractAddress({
|
180
|
+
from: walletClient.account.address,
|
181
|
+
nonce: BigInt(deploymentTx.nonce),
|
182
|
+
});
|
183
|
+
|
184
|
+
const contract = await innerGetContractAt(
|
185
|
+
publicClient,
|
186
|
+
walletClient,
|
187
|
+
contractAbi,
|
188
|
+
contractAddress
|
189
|
+
);
|
190
|
+
|
191
|
+
return { contract, deploymentTransaction: deploymentTx };
|
192
|
+
}
|
193
|
+
|
194
|
+
export async function getContractAt(
|
195
|
+
{ artifacts, network }: HardhatRuntimeEnvironment,
|
196
|
+
contractName: string,
|
197
|
+
address: Address,
|
198
|
+
config: GetContractAtConfig = {}
|
199
|
+
): Promise<GetContractReturnType> {
|
200
|
+
const [publicClient, walletClient, contractArtifact] = await Promise.all([
|
201
|
+
getPublicClient(network.provider),
|
202
|
+
config.walletClient ??
|
203
|
+
getDefaultWalletClient(network.provider, network.name),
|
204
|
+
artifacts.readArtifact(contractName),
|
205
|
+
]);
|
206
|
+
|
207
|
+
return innerGetContractAt(
|
208
|
+
publicClient,
|
209
|
+
walletClient,
|
210
|
+
contractArtifact.abi,
|
211
|
+
address
|
212
|
+
);
|
213
|
+
}
|
214
|
+
|
215
|
+
async function innerGetContractAt(
|
216
|
+
publicClient: PublicClient,
|
217
|
+
walletClient: WalletClient,
|
218
|
+
contractAbi: Abi,
|
219
|
+
address: Address
|
220
|
+
): Promise<GetContractReturnType> {
|
221
|
+
const viem = await import("viem");
|
222
|
+
const contract = viem.getContract({
|
223
|
+
address,
|
224
|
+
publicClient,
|
225
|
+
walletClient,
|
226
|
+
abi: contractAbi,
|
227
|
+
});
|
228
|
+
|
229
|
+
return contract;
|
230
|
+
}
|
231
|
+
|
232
|
+
async function getDefaultWalletClient(
|
233
|
+
provider: EthereumProvider,
|
234
|
+
networkName: string
|
235
|
+
): Promise<WalletClient> {
|
236
|
+
const [defaultWalletClient] = await getWalletClients(provider);
|
237
|
+
|
238
|
+
if (defaultWalletClient === undefined) {
|
239
|
+
throw new DefaultWalletClientNotFoundError(networkName);
|
240
|
+
}
|
241
|
+
|
242
|
+
return defaultWalletClient;
|
243
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { NomicLabsHardhatPluginError } from "hardhat/plugins";
|
2
|
+
|
3
|
+
export class HardhatViemError extends NomicLabsHardhatPluginError {
|
4
|
+
constructor(message: string, parent?: Error) {
|
5
|
+
super("@nomicfoundation/hardhat-viem", message, parent);
|
6
|
+
}
|
7
|
+
}
|
8
|
+
|
9
|
+
export class UnknownDevelopmentNetworkError extends HardhatViemError {
|
10
|
+
constructor() {
|
11
|
+
super(`The chain id corresponds to a development network but we couldn't detect which one.
|
12
|
+
Please report this issue if you're using Hardhat or Foundry.`);
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
export class NetworkNotFoundError extends HardhatViemError {
|
17
|
+
constructor(chainId: number) {
|
18
|
+
super(
|
19
|
+
`No network with chain id ${chainId} found. You can override the chain by passing it as a parameter to the client getter:
|
20
|
+
|
21
|
+
import { someChain } from "viem/chains";
|
22
|
+
const client = await hre.viem.getPublicClient({
|
23
|
+
chain: someChain,
|
24
|
+
...
|
25
|
+
});
|
26
|
+
|
27
|
+
You can find a list of supported networks here: https://viem.sh/docs/clients/chains.html`
|
28
|
+
);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
export class MultipleMatchingNetworksError extends HardhatViemError {
|
33
|
+
constructor(chainId: number) {
|
34
|
+
super(
|
35
|
+
`Multiple networks with chain id ${chainId} found. You can override the chain by passing it as a parameter to the client getter:
|
36
|
+
|
37
|
+
import { someChain } from "viem/chains";
|
38
|
+
const client = await hre.viem.getPublicClient({
|
39
|
+
chain: someChain,
|
40
|
+
...
|
41
|
+
});
|
42
|
+
|
43
|
+
You can find a list of supported networks here: https://viem.sh/docs/clients/chains.html`
|
44
|
+
);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
export class DefaultWalletClientNotFoundError extends HardhatViemError {
|
49
|
+
constructor(networkName: string) {
|
50
|
+
super(
|
51
|
+
`Default wallet client not found. This can happen if no accounts were configured for this network (network: '${networkName}').
|
52
|
+
|
53
|
+
Alternatively, you can set a custom wallet client by passing it as a parameter in the deployContract function:
|
54
|
+
|
55
|
+
const walletClient = await hre.viem.getWalletClient(address);
|
56
|
+
const contractA = await hre.viem.deployContract("A", [], { walletClient });
|
57
|
+
const contractB = await hre.viem.getContractAt("B", address, { walletClient });`
|
58
|
+
);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
export class InvalidConfirmationsError extends HardhatViemError {
|
63
|
+
constructor() {
|
64
|
+
super(
|
65
|
+
"deployContract does not support 0 confirmations. Use sendDeploymentTransaction if you want to handle the deployment transaction yourself."
|
66
|
+
);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
export class DeployContractError extends HardhatViemError {
|
71
|
+
constructor(txHash: string, blockNumber: bigint) {
|
72
|
+
super(
|
73
|
+
`The deployment transaction '${txHash}' was mined in block '${blockNumber}' but its receipt doesn't contain a contract address`
|
74
|
+
);
|
75
|
+
}
|
76
|
+
}
|