@cofhe/hardhat-3-plugin 0.0.0-alpha-20260409113701

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/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # @cofhe/hardhat-3-plugin
2
+
3
+ ## 0.0.0-alpha-20260409113701
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [788a6e2]
8
+ - Updated dependencies [9a06012]
9
+ - Updated dependencies [503536a]
10
+ - @cofhe/sdk@0.0.0-alpha-20260409113701
11
+ - @cofhe/mock-contracts@0.0.0-alpha-20260409113701
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # @cofhe/hardhat-3-plugin
2
+
3
+ A [Hardhat 3](https://hardhat.org) plugin for [CoFHE](https://docs.fhenix.io) development. It deploys the CoFHE mock contracts to an in-process Hardhat network on every `network.connect()` call and exposes a `cofhe` namespace on the connection object — ready to use immediately, no boilerplate required.
4
+
5
+ ## Features
6
+
7
+ - Automatically deploys all CoFHE mock contracts (`MockTaskManager`, `MockACL`, `MockZkVerifier`, `MockThresholdNetwork`, `TestBed`) on every `network.connect()`
8
+ - Exposes `conn.cofhe` on the Hardhat 3 connection object (compatible with `@nomicfoundation/hardhat-viem`'s `conn.viem`)
9
+ - Provides a batteries-included `cofhe.createClientWithBatteries()` for quick SDK client setup
10
+ - Mock-specific helpers: plaintext inspection, logging control, and Viem contract descriptors for every mock
11
+
12
+ ---
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @cofhe/hardhat-3-plugin
18
+ # or
19
+ pnpm add @cofhe/hardhat-3-plugin
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Configuration
25
+
26
+ Register the plugin in `hardhat.config.ts`:
27
+
28
+ ```typescript
29
+ import { defineConfig } from 'hardhat/config';
30
+ import cofhePlugin from '@cofhe/hardhat-3-plugin';
31
+ import hardhatViem from '@nomicfoundation/hardhat-viem';
32
+ import hardhatNodeTestRunner from '@nomicfoundation/hardhat-node-test-runner';
33
+
34
+ export default defineConfig({
35
+ plugins: [cofhePlugin, hardhatViem, hardhatNodeTestRunner],
36
+
37
+ // Optional cofhe config (all values shown are their defaults)
38
+ cofhe: {
39
+ gasWarning: true, // warn when mock ops report higher gas than real FHE
40
+ logMocks: true, // enable mock contract event logging
41
+ },
42
+ });
43
+ ```
44
+
45
+ ### Config options
46
+
47
+ | Option | Type | Default | Description |
48
+ | ------------ | --------- | ------- | ---------------------------------------------------------------------------------------- |
49
+ | `gasWarning` | `boolean` | `true` | Print a warning after mock deployment reminding that mock gas costs differ from live FHE |
50
+ | `logMocks` | `boolean` | `true` | Enable event-based logging inside mock contracts |
51
+
52
+ ---
53
+
54
+ ## Usage
55
+
56
+ ### The `cofhe` connection object
57
+
58
+ Every call to `network.connect()` automatically:
59
+
60
+ 1. Deploys all CoFHE mock contracts to the fresh in-process EVM
61
+ 2. Attaches a `cofhe` namespace to the returned connection object
62
+
63
+ Because `network.connect()` is awaitable at the top level of an `async describe`, you can set everything up without lifecycle hooks:
64
+
65
+ ```typescript
66
+ import { describe, it } from 'node:test';
67
+ import assert from 'node:assert/strict';
68
+ import { network } from 'hardhat';
69
+
70
+ describe('My FHE contract', async () => {
71
+ const { viem, cofhe } = await network.connect();
72
+ const publicClient = await viem.getPublicClient();
73
+ const [walletClient] = await viem.getWalletClients();
74
+
75
+ it('encrypts and decrypts a value', async () => {
76
+ const client = await cofhe.createClientWithBatteries(walletClient);
77
+ // ... test logic
78
+ });
79
+ });
80
+ ```
81
+
82
+ > **Why `async describe`?**
83
+ > Hardhat 3's node:test runner supports top-level `await` inside the describe callback. This lets you resolve the connection (and deploy mocks) exactly once per test file without needing a `before()` hook.
84
+
85
+ ---
86
+
87
+ ## API reference
88
+
89
+ ### `cofhe.createConfig(overrides?)`
90
+
91
+ Creates a CoFHE SDK configuration pre-wired for the Hardhat mock environment.
92
+
93
+ ```typescript
94
+ const config = await cofhe.createConfig();
95
+ // With overrides:
96
+ const config = await cofhe.createConfig({ mocks: { encryptDelay: 0 } });
97
+ ```
98
+
99
+ Returns a `CofheConfig` object suitable for `cofhe.createClient()`.
100
+
101
+ ---
102
+
103
+ ### `cofhe.createClient(config)`
104
+
105
+ Creates a `CofheClient` from a config. The client is **not connected** — call `client.connect(publicClient, walletClient)` before using it.
106
+
107
+ ```typescript
108
+ const config = await cofhe.createConfig();
109
+ const client = cofhe.createClient(config);
110
+ await client.connect(publicClient, walletClient);
111
+ ```
112
+
113
+ ---
114
+
115
+ ### `cofhe.createClientWithBatteries(walletClient?)`
116
+
117
+ Creates a fully initialized `CofheClient` in one call — configures it for Hardhat, connects it, and creates a self-permit so it can decrypt encrypted FHE variables out of the box.
118
+
119
+ ```typescript
120
+ // Uses the first account in the connection automatically:
121
+ const client = await cofhe.createClientWithBatteries();
122
+
123
+ // Or pass a specific account-bound wallet client:
124
+ const [walletClient] = await viem.getWalletClients();
125
+ const client = await cofhe.createClientWithBatteries(walletClient);
126
+ ```
127
+
128
+ ---
129
+
130
+ ### `cofhe.mocks`
131
+
132
+ #### Contract descriptors
133
+
134
+ Each mock contract is exposed as an `{ address, abi }` object that can be spread directly into Viem's `readContract` / `writeContract`:
135
+
136
+ ```typescript
137
+ // Fixed-address contracts (synchronous):
138
+ cofhe.mocks.MockTaskManager; // { address: `0x...`, abi: [...] }
139
+ cofhe.mocks.MockZkVerifier; // { address: `0x...`, abi: [...] }
140
+ cofhe.mocks.MockThresholdNetwork; // { address: `0x...`, abi: [...] }
141
+ cofhe.mocks.TestBed; // { address: `0x...`, abi: [...] }
142
+
143
+ // Dynamic-address contract (async — resolves from TaskManager on-chain):
144
+ const mockACL = await cofhe.mocks.MockACL(); // { address: `0x...`, abi: [...] }
145
+ ```
146
+
147
+ Example — calling a mock directly with Viem:
148
+
149
+ ```typescript
150
+ const value = await publicClient.readContract({
151
+ ...cofhe.mocks.TestBed,
152
+ functionName: 'numberHash',
153
+ });
154
+
155
+ await walletClient.writeContract({
156
+ ...cofhe.mocks.MockTaskManager,
157
+ functionName: 'setSecurityZones',
158
+ args: [0, 1],
159
+ });
160
+ ```
161
+
162
+ #### Plaintext inspection
163
+
164
+ In the mock environment, every FHE ciphertext has a corresponding plaintext stored on-chain. These helpers let you inspect or assert on plaintext values without decryption:
165
+
166
+ ```typescript
167
+ // Returns the plaintext bigint for a ciphertext hash
168
+ const plaintext = await cofhe.mocks.getPlaintext(ctHash);
169
+
170
+ // Throws if the plaintext doesn't match the expected value
171
+ await cofhe.mocks.expectPlaintext(ctHash, 42n);
172
+ ```
173
+
174
+ Both methods accept a `ctHash` as either a `bigint` or a hex `string`.
175
+
176
+ #### Logging control
177
+
178
+ Mock contracts can emit structured logs for every FHE operation, which is useful for debugging. Logging is disabled by default.
179
+
180
+ ```typescript
181
+ // Enable logging
182
+ await cofhe.mocks.enableLogs();
183
+
184
+ // Disable logging
185
+ await cofhe.mocks.disableLogs();
186
+
187
+ // Enable only for a specific block of code, then restore previous state
188
+ await cofhe.mocks.withLogs('my test', async () => {
189
+ // ... FHE operations are logged here
190
+ });
191
+ ```
192
+
193
+ #### `cofhe.mocks.deployMocks(options?)`
194
+
195
+ Re-deploys all mock contracts. Normally you don't need to call this directly — mocks are deployed automatically on every `network.connect()`. This is available for advanced scenarios where you need to reset mock state mid-test.
196
+
197
+ ```typescript
198
+ await cofhe.mocks.deployMocks({ deployTestBed: true, silent: true });
199
+ ```
200
+
201
+ | Option | Type | Default | Description |
202
+ | --------------- | --------- | --------------- | ------------------------------------------------ |
203
+ | `deployTestBed` | `boolean` | `true` | Whether to deploy the `TestBed` utility contract |
204
+ | `gasWarning` | `boolean` | inherits config | Print gas warning after deployment |
205
+ | `silent` | `boolean` | `false` | Suppress all deployment output |
206
+
207
+ ---
208
+
209
+ ## Mock contracts
210
+
211
+ The plugin deploys these contracts automatically on every `network.connect()`:
212
+
213
+ | Contract | Address | Description |
214
+ | ---------------------- | -------------------------------------------- | --------------------------------------------------------------------- |
215
+ | `MockTaskManager` | `0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9` | Coordinates FHE operations and ACL |
216
+ | `MockACL` | dynamic | Access Control List — address resolved from TaskManager |
217
+ | `MockZkVerifier` | `0x0000000000000000000000000000000000005001` | Verifies ZK proofs for encrypted inputs |
218
+ | `MockThresholdNetwork` | `0x0000000000000000000000000000000000005002` | Simulates the threshold decryption network |
219
+ | `TestBed` | `0x0000000000000000000000000000000000005003` | Utility contract for storing and retrieving encrypted values in tests |
220
+
221
+ Fixed-address contracts are deployed via `hardhat_setCode`, ensuring they are always at the same address regardless of deployment order. `MockACL` is deployed as a normal contract (so its EIP-712 domain constructor runs correctly) and its address is registered in `MockTaskManager`.
222
+
223
+ ---
224
+
225
+ ## Complete test example
226
+
227
+ ```typescript
228
+ import { describe, it, beforeEach } from 'node:test';
229
+ import assert from 'node:assert/strict';
230
+ import { network } from 'hardhat';
231
+ import { Encryptable, FheTypes } from '@cofhe/sdk';
232
+
233
+ describe('Encrypted counter', async () => {
234
+ const { viem, cofhe } = await network.connect();
235
+ const publicClient = await viem.getPublicClient();
236
+ const [walletClient] = await viem.getWalletClients();
237
+
238
+ it('encrypts, stores, and decrypts a uint32', async () => {
239
+ const client = await cofhe.createClientWithBatteries(walletClient);
240
+
241
+ // Encrypt
242
+ const [enc] = await client.encryptInputs([Encryptable.uint32(42n)]).execute();
243
+
244
+ // Store on-chain via TestBed
245
+ await walletClient.writeContract({
246
+ ...cofhe.mocks.TestBed,
247
+ functionName: 'setNumber',
248
+ args: [{ ctHash: enc.ctHash, securityZone: enc.securityZone, utype: enc.utype, signature: enc.signature }],
249
+ });
250
+
251
+ const ctHash = (await publicClient.readContract({
252
+ ...cofhe.mocks.TestBed,
253
+ functionName: 'numberHash',
254
+ })) as `0x${string}`;
255
+
256
+ // Decrypt via view (off-chain, instant)
257
+ const decryptedView = await client.decryptForView(ctHash, FheTypes.Uint32).execute();
258
+ assert.equal(decryptedView, 42n);
259
+
260
+ // Alternatively, verify plaintext without decryption
261
+ await cofhe.mocks.expectPlaintext(ctHash, 42n);
262
+ });
263
+ });
264
+ ```
265
+
266
+ ---
267
+
268
+ ## License
269
+
270
+ MIT
@@ -0,0 +1,223 @@
1
+ // src/deploy.ts
2
+ import { createTestClient, custom } from "viem";
3
+ import chalk from "chalk";
4
+ import { privateKeyToAccount } from "viem/accounts";
5
+ import {
6
+ MockTaskManagerArtifact,
7
+ MockACLArtifact,
8
+ MockZkVerifierArtifact,
9
+ MockThresholdNetworkArtifact,
10
+ TestBedArtifact
11
+ } from "@cofhe/mock-contracts";
12
+ import {
13
+ TASK_MANAGER_ADDRESS,
14
+ MOCKS_ZK_VERIFIER_ADDRESS,
15
+ MOCKS_ZK_VERIFIER_SIGNER_ADDRESS,
16
+ MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
17
+ MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY
18
+ } from "@cofhe/sdk";
19
+ var verbosity = "v";
20
+ async function isLocalHardhatNetwork(publicClient) {
21
+ try {
22
+ await publicClient.request({ method: "hardhat_metadata", params: [] });
23
+ return true;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ async function deployMocks(ctx, options = {}) {
29
+ const { deployTestBed = true, gasWarning = true } = options;
30
+ verbosity = options.mocksDeployVerbosity ?? "v";
31
+ if (!await isLocalHardhatNetwork(ctx.publicClient)) {
32
+ log("v", `cofhe-hardhat-3-plugin - deploy mocks - skipped on non-hardhat network`, 0);
33
+ return;
34
+ }
35
+ log("vv", chalk.bold("cofhe-hardhat-3-plugin :: deploy mocks"), 0);
36
+ await deployFixed(ctx.publicClient, MockTaskManagerArtifact);
37
+ logDeployment("MockTaskManager", TASK_MANAGER_ADDRESS);
38
+ const [account] = await ctx.walletClient.getAddresses();
39
+ await ctx.walletClient.writeContract({
40
+ address: TASK_MANAGER_ADDRESS,
41
+ abi: MockTaskManagerArtifact.abi,
42
+ functionName: "initialize",
43
+ args: [account],
44
+ account,
45
+ chain: null
46
+ });
47
+ await ctx.walletClient.writeContract({
48
+ address: TASK_MANAGER_ADDRESS,
49
+ abi: MockTaskManagerArtifact.abi,
50
+ functionName: "setSecurityZones",
51
+ args: [0, 1],
52
+ account,
53
+ chain: null
54
+ });
55
+ const aclAddress = await deployVariable(ctx, MockACLArtifact, []);
56
+ logDeployment("MockACL", aclAddress);
57
+ await ctx.walletClient.writeContract({
58
+ address: TASK_MANAGER_ADDRESS,
59
+ abi: MockTaskManagerArtifact.abi,
60
+ functionName: "setACLContract",
61
+ args: [aclAddress],
62
+ account,
63
+ chain: null
64
+ });
65
+ log("vv", "ACL address set in TaskManager", 2);
66
+ const verifierSigner = privateKeyToAccount(MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY);
67
+ await ctx.walletClient.writeContract({
68
+ address: TASK_MANAGER_ADDRESS,
69
+ abi: MockTaskManagerArtifact.abi,
70
+ functionName: "setVerifierSigner",
71
+ args: [verifierSigner.address],
72
+ account,
73
+ chain: null
74
+ });
75
+ log("vv", "Verifier signer set", 2);
76
+ const decryptSigner = privateKeyToAccount(MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY);
77
+ await ctx.walletClient.writeContract({
78
+ address: TASK_MANAGER_ADDRESS,
79
+ abi: MockTaskManagerArtifact.abi,
80
+ functionName: "setDecryptResultSigner",
81
+ args: [decryptSigner.address],
82
+ account,
83
+ chain: null
84
+ });
85
+ log("vv", "Decrypt result signer set", 2);
86
+ const testClient = createTestClient({
87
+ mode: "hardhat",
88
+ transport: custom(ctx.publicClient.transport)
89
+ });
90
+ await testClient.setBalance({
91
+ address: MOCKS_ZK_VERIFIER_SIGNER_ADDRESS,
92
+ value: BigInt("10000000000000000000")
93
+ // 10 ETH
94
+ });
95
+ log("vv", `ZkVerifier signer (${MOCKS_ZK_VERIFIER_SIGNER_ADDRESS}) funded`, 1);
96
+ const zkVerifierBalance = await ctx.publicClient.getBalance({ address: MOCKS_ZK_VERIFIER_SIGNER_ADDRESS });
97
+ log("vv", `ETH balance: ${zkVerifierBalance.toString()}`, 2);
98
+ await deployFixed(ctx.publicClient, MockZkVerifierArtifact);
99
+ logDeployment("MockZkVerifier", MOCKS_ZK_VERIFIER_ADDRESS);
100
+ await deployFixed(ctx.publicClient, MockThresholdNetworkArtifact);
101
+ logDeployment("MockThresholdNetwork", MockThresholdNetworkArtifact.fixedAddress);
102
+ await ctx.walletClient.writeContract({
103
+ address: MockThresholdNetworkArtifact.fixedAddress,
104
+ abi: MockThresholdNetworkArtifact.abi,
105
+ functionName: "initialize",
106
+ args: [TASK_MANAGER_ADDRESS, aclAddress],
107
+ account,
108
+ chain: null
109
+ });
110
+ if (deployTestBed) {
111
+ await deployFixed(ctx.publicClient, TestBedArtifact);
112
+ logDeployment("TestBed", TestBedArtifact.fixedAddress);
113
+ }
114
+ log("v", chalk.bold("cofhe-hardhat-3-plugin :: mocks deployed"), 0);
115
+ if (gasWarning) {
116
+ logEmpty("v");
117
+ logWarning(
118
+ "When using mocks, FHE operations report a higher gas price due to on-chain mocking logic. Deploy your contracts on a testnet to check true gas costs.\n(Disable this warning by setting 'cofhe.gasWarning: false' in your Hardhat config)",
119
+ 0
120
+ );
121
+ }
122
+ logEmpty("v");
123
+ }
124
+ async function deployFixed(publicClient, artifact) {
125
+ await publicClient.request({
126
+ method: "hardhat_setCode",
127
+ params: [artifact.fixedAddress, artifact.deployedBytecode]
128
+ });
129
+ }
130
+ async function deployVariable(ctx, artifact, constructorArgs) {
131
+ const [account] = await ctx.walletClient.getAddresses();
132
+ const hash = await ctx.walletClient.deployContract({
133
+ abi: artifact.abi,
134
+ bytecode: artifact.bytecode,
135
+ args: constructorArgs,
136
+ account,
137
+ chain: null
138
+ });
139
+ const receipt = await ctx.publicClient.waitForTransactionReceipt({ hash });
140
+ if (!receipt.contractAddress) {
141
+ throw new Error("deployVariable: no contractAddress in receipt");
142
+ }
143
+ return receipt.contractAddress;
144
+ }
145
+ var log = (minVerbosity, message, indent = 1) => {
146
+ if (verbosity === "") return;
147
+ if (minVerbosity === "vv" && verbosity !== "vv") return;
148
+ console.log(chalk.green(`${" ".repeat(indent)}\u2713 ${message}`));
149
+ };
150
+ var logEmpty = (minVerbosity = "v") => {
151
+ if (verbosity === "") return;
152
+ if (minVerbosity === "vv" && verbosity !== "vv") return;
153
+ console.log("");
154
+ };
155
+ var logWarning = (message, indent = 1) => {
156
+ if (verbosity === "") return;
157
+ console.log(chalk.bold(chalk.yellow(`${" ".repeat(indent)}\u26A0 NOTE:`)), message);
158
+ };
159
+ var logDeployment = (contractName, address) => {
160
+ if (verbosity !== "vv") return;
161
+ const paddedName = `${contractName} deployed`.padEnd(36);
162
+ console.log(chalk.green(` \u2713 ${paddedName} ${chalk.bold(address)}`));
163
+ };
164
+
165
+ // src/utils.ts
166
+ import { TASK_MANAGER_ADDRESS as TASK_MANAGER_ADDRESS2, MOCKS_ZK_VERIFIER_ADDRESS as MOCKS_ZK_VERIFIER_ADDRESS2 } from "@cofhe/sdk";
167
+ async function isMockEnvironment(publicClient) {
168
+ const bytecode = await publicClient.getCode({
169
+ address: MOCKS_ZK_VERIFIER_ADDRESS2
170
+ });
171
+ return !!bytecode && bytecode.length > 2;
172
+ }
173
+ async function mock_getPlaintext(publicClient, ctHash) {
174
+ if (!await isMockEnvironment(publicClient)) {
175
+ console.log("mock_getPlaintext \u2014 skipped on non-mock network");
176
+ return void 0;
177
+ }
178
+ return publicClient.readContract({
179
+ address: TASK_MANAGER_ADDRESS2,
180
+ abi: [
181
+ {
182
+ name: "mockStorage",
183
+ type: "function",
184
+ inputs: [{ name: "ctHash", type: "uint256" }],
185
+ outputs: [{ type: "uint256" }],
186
+ stateMutability: "view"
187
+ }
188
+ ],
189
+ functionName: "mockStorage",
190
+ args: [BigInt(ctHash)]
191
+ });
192
+ }
193
+ async function mock_expectPlaintext(publicClient, ctHash, expectedValue) {
194
+ if (!await isMockEnvironment(publicClient)) {
195
+ console.log("mock_expectPlaintext \u2014 skipped on non-mock network");
196
+ return;
197
+ }
198
+ const exists = await publicClient.readContract({
199
+ address: TASK_MANAGER_ADDRESS2,
200
+ abi: [
201
+ {
202
+ name: "inMockStorage",
203
+ type: "function",
204
+ inputs: [{ name: "ctHash", type: "uint256" }],
205
+ outputs: [{ type: "bool" }],
206
+ stateMutability: "view"
207
+ }
208
+ ],
209
+ functionName: "inMockStorage",
210
+ args: [BigInt(ctHash)]
211
+ });
212
+ if (!exists) throw new Error(`mock_expectPlaintext: ctHash ${ctHash} not found in mock storage`);
213
+ const plaintext = await mock_getPlaintext(publicClient, ctHash);
214
+ if (plaintext !== expectedValue) {
215
+ throw new Error(`mock_expectPlaintext: expected ${expectedValue}, got ${plaintext} for ctHash ${ctHash}`);
216
+ }
217
+ }
218
+
219
+ export {
220
+ deployMocks,
221
+ mock_getPlaintext,
222
+ mock_expectPlaintext
223
+ };
@@ -0,0 +1,64 @@
1
+ // src/logging.ts
2
+ import chalk from "chalk";
3
+ import { MockTaskManagerArtifact } from "@cofhe/mock-contracts";
4
+ import { TASK_MANAGER_ADDRESS } from "@cofhe/sdk";
5
+ async function getLoggingEnabled(publicClient) {
6
+ return publicClient.readContract({
7
+ address: TASK_MANAGER_ADDRESS,
8
+ abi: MockTaskManagerArtifact.abi,
9
+ functionName: "logOps",
10
+ args: []
11
+ });
12
+ }
13
+ async function setLoggingEnabled(publicClient, walletClient, enabled) {
14
+ const [account] = await walletClient.getAddresses();
15
+ const hash = await walletClient.writeContract({
16
+ address: TASK_MANAGER_ADDRESS,
17
+ abi: MockTaskManagerArtifact.abi,
18
+ functionName: "setLogOps",
19
+ args: [enabled],
20
+ account,
21
+ chain: null
22
+ });
23
+ await publicClient.waitForTransactionReceipt({ hash });
24
+ }
25
+ var printLogsEnabledMessage = (closureMessage) => {
26
+ console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
27
+ console.log(`\u2502 [COFHE-MOCKS] \u2502 ${closureMessage}`);
28
+ console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
29
+ };
30
+ var printLogsBlockEnd = () => {
31
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
32
+ };
33
+ async function mock_setLoggingEnabled(publicClient, walletClient, enabled, closureName) {
34
+ try {
35
+ const initiallyEnabled = await getLoggingEnabled(publicClient);
36
+ await setLoggingEnabled(publicClient, walletClient, enabled);
37
+ if (enabled) {
38
+ printLogsEnabledMessage(`${closureName ? `"${chalk.bold(closureName)}" logs:` : "Logs:"}`);
39
+ }
40
+ if (!enabled && initiallyEnabled) {
41
+ printLogsBlockEnd();
42
+ }
43
+ } catch (error) {
44
+ console.log(chalk.red("mock_setLoggingEnabled error"), error);
45
+ }
46
+ }
47
+ async function mock_withLogs(publicClient, walletClient, closureName, closure) {
48
+ const initiallyEnabled = await getLoggingEnabled(publicClient);
49
+ await setLoggingEnabled(publicClient, walletClient, true);
50
+ printLogsEnabledMessage(`"${chalk.bold(closureName)}" logs:`);
51
+ try {
52
+ await closure();
53
+ } finally {
54
+ printLogsBlockEnd();
55
+ if (!initiallyEnabled) {
56
+ await setLoggingEnabled(publicClient, walletClient, false);
57
+ }
58
+ }
59
+ }
60
+
61
+ export {
62
+ mock_setLoggingEnabled,
63
+ mock_withLogs
64
+ };
@@ -0,0 +1,42 @@
1
+ // src/fund.ts
2
+ import { parseEther } from "viem";
3
+ import { privateKeyToAccount } from "viem/accounts";
4
+ var FUNDER_PRIVATE_KEY = "0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659";
5
+ async function localcofheFundAccount(publicClient, walletClient, toAddress, amount = "10") {
6
+ const privateKey = process.env["FUNDER_PRIVATE_KEY"] ?? FUNDER_PRIVATE_KEY;
7
+ const funderAccount = privateKeyToAccount(privateKey);
8
+ const balance = await publicClient.getBalance({ address: funderAccount.address });
9
+ console.log(`Funder wallet address: ${funderAccount.address}`);
10
+ console.log(`Funder wallet balance: ${balance} wei`);
11
+ const amountWei = parseEther(amount);
12
+ if (balance < amountWei) {
13
+ console.error(`Funder wallet doesn't have enough funds. Balance: ${balance} wei, needed: ${amountWei} wei`);
14
+ return;
15
+ }
16
+ console.log(`Sending ${amount} ETH to ${toAddress}...`);
17
+ const hash = await walletClient.sendTransaction({
18
+ account: funderAccount,
19
+ to: toAddress,
20
+ value: amountWei,
21
+ chain: null
22
+ });
23
+ console.log(`Transaction sent! Hash: ${hash}`);
24
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
25
+ console.log(`Transaction confirmed in block ${receipt.blockNumber}`);
26
+ console.log(`Successfully sent ${amount} ETH to ${toAddress}`);
27
+ }
28
+ async function localcofheFundWalletIfNeeded(publicClient, walletClient, walletAddress) {
29
+ const balance = await publicClient.getBalance({ address: walletAddress });
30
+ console.log(`Wallet balance: ${balance} wei`);
31
+ if (balance < parseEther("1")) {
32
+ console.log(`Balance below 1 ETH. Funding ${walletAddress}...`);
33
+ await localcofheFundAccount(publicClient, walletClient, walletAddress);
34
+ const newBalance = await publicClient.getBalance({ address: walletAddress });
35
+ console.log(`New wallet balance: ${newBalance} wei`);
36
+ }
37
+ }
38
+
39
+ export {
40
+ localcofheFundAccount,
41
+ localcofheFundWalletIfNeeded
42
+ };
@@ -0,0 +1,64 @@
1
+ // src/config.ts
2
+ function resolvePluginConfig(userConfig, resolvedConfig) {
3
+ if (!userConfig.networks?.["localcofhe"]) {
4
+ resolvedConfig.networks["localcofhe"] = {
5
+ type: "http",
6
+ url: "http://127.0.0.1:42069",
7
+ gas: "auto",
8
+ gasMultiplier: 1.2,
9
+ gasPrice: "auto",
10
+ timeout: 1e4,
11
+ httpHeaders: {},
12
+ accounts: [
13
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
14
+ "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
15
+ "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a",
16
+ "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6"
17
+ ]
18
+ };
19
+ }
20
+ if (!userConfig.networks?.["eth-sepolia"]) {
21
+ resolvedConfig.networks["eth-sepolia"] = {
22
+ type: "http",
23
+ url: process.env["SEPOLIA_RPC_URL"] ?? "https://ethereum-sepolia.publicnode.com",
24
+ accounts: process.env["PRIVATE_KEY"] ? [process.env["PRIVATE_KEY"]] : [],
25
+ chainId: 11155111,
26
+ gas: "auto",
27
+ gasMultiplier: 1.2,
28
+ gasPrice: "auto",
29
+ timeout: 6e4,
30
+ httpHeaders: {}
31
+ };
32
+ }
33
+ if (!userConfig.networks?.["arb-sepolia"]) {
34
+ resolvedConfig.networks["arb-sepolia"] = {
35
+ type: "http",
36
+ url: process.env["ARBITRUM_SEPOLIA_RPC_URL"] ?? "https://sepolia-rollup.arbitrum.io/rpc",
37
+ accounts: process.env["PRIVATE_KEY"] ? [process.env["PRIVATE_KEY"]] : [],
38
+ chainId: 421614,
39
+ gas: "auto",
40
+ gasMultiplier: 1.2,
41
+ gasPrice: "auto",
42
+ timeout: 6e4,
43
+ httpHeaders: {}
44
+ };
45
+ }
46
+ resolvedConfig.cofhe = {
47
+ logMocks: userConfig.cofhe?.logMocks ?? false,
48
+ gasWarning: userConfig.cofhe?.gasWarning ?? false,
49
+ mocksDeployVerbosity: userConfig.cofhe?.mocksDeployVerbosity ?? "v"
50
+ };
51
+ }
52
+
53
+ // src/hooks/config.ts
54
+ var configHooks = {
55
+ async resolveUserConfig(userConfig, resolveConfigurationVariable, next) {
56
+ const resolvedConfig = await next(userConfig, resolveConfigurationVariable);
57
+ resolvePluginConfig(userConfig, resolvedConfig);
58
+ return resolvedConfig;
59
+ }
60
+ };
61
+ var config_default = async () => configHooks;
62
+ export {
63
+ config_default as default
64
+ };