@cofhe/hardhat-3-plugin 0.7.1 → 1.0.0-alpha.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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @cofhe/hardhat-3-plugin
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6f7a4c5: Resolve the Task Manager through the `CoFHEAddressBook` (`@fhenixprotocol/cofhe-contracts@1.0.0`). **Breaking:** `TASK_MANAGER_ADDRESS` is removed from `@cofhe/sdk`. Use `getTaskManagerAddress(publicClient)`, which reads `getTm(TASK_MANAGER_ID)` from the book at `COFHE_ADDRESS_BOOK_ADDRESS` (both exported) and caches the result per chain. If the chain has no book, or the id is unset, it throws `TASK_MANAGER_UNRESOLVED`. `verifyDecryptResult`, the ACL/ACP lookups and `useCofheEnabled` / `useCofheReadDecryptionResults` now resolve the Task Manager this way. `@cofhe/react` adds `useCofheTaskManagerAddress()`.
8
+
9
+ Mocks: a new `MockCoFHEAddressBook` is deployed at FHE.sol's `COFHE_ADDRESS_BOOK`, and `MockTaskManager` moves to `MOCKS_TASK_MANAGER_ADDRESS` (`0x…5000`) and is registered in the book. `MockACL` now stores its Task Manager (`setTaskManager` / `getTaskManagerAddress`) instead of reading a constant, so its `TASK_MANAGER_ADDRESS_()` getter is gone. All three plugins deploy and wire the book. Hardhat 2 exposes `hre.cofhe.mocks.getMockCoFHEAddressBook()`, Hardhat 3 exposes `conn.cofhe.mocks.MockCoFHEAddressBook`, and Foundry exposes `CofheTest.mockAddressBook`. Contracts must be built against `@fhenixprotocol/cofhe-contracts@1.0.0` or later (the hardhat plugin's peer range is now `>=1.0.0`). Each FHE op now makes one extra `getTm` call on the book, as it does on real networks, so expect slightly higher gas numbers.
10
+
11
+ ### Patch Changes
12
+
13
+ - ccb7b68: Realistic gas reporting for mocks. Under Foundry, mock-only work is now excluded from gas metering by default (opt out with `mockTaskManager.setMockGasExcluded(false)`), so expect `forge snapshot` numbers to drop. Under Hardhat, mock transactions emit `MockGasConsumed` events (extra receipt logs), and the plugins add `getAdjustedGasUsed(receipt)` / `getAdjustedGasBreakdown(receipt)` plus an opt-in `cofhe.gasSummary` report.
14
+ - Updated dependencies [17ff23e]
15
+ - Updated dependencies [0fe40c3]
16
+ - Updated dependencies [6f7a4c5]
17
+ - Updated dependencies [552d118]
18
+ - Updated dependencies [22eebcc]
19
+ - Updated dependencies [ccb7b68]
20
+ - Updated dependencies [42fccae]
21
+ - @cofhe/sdk@0.8.0
22
+ - @cofhe/mock-contracts@0.8.0
23
+
3
24
  ## 0.7.1
4
25
 
5
26
  ### Patch Changes
package/README.md CHANGED
@@ -36,18 +36,20 @@ export default defineConfig({
36
36
 
37
37
  // Optional cofhe config (all values shown are their defaults)
38
38
  cofhe: {
39
- gasWarning: true, // warn when mock ops report higher gas than real FHE
40
- logMocks: true, // enable mock contract event logging
39
+ gasWarning: false, // warn when mock ops report higher gas than real FHE
40
+ gasSummary: false, // print a per-method adjusted-gas summary after `hardhat test`
41
+ logMocks: false, // enable mock contract event logging
41
42
  },
42
43
  });
43
44
  ```
44
45
 
45
46
  ### Config options
46
47
 
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 |
48
+ | Option | Type | Default | Description |
49
+ | ------------ | --------- | ------- | ------------------------------------------------------------------------------------------------- |
50
+ | `gasWarning` | `boolean` | `false` | Print a warning after mock deployment reminding that mock gas costs differ from live FHE |
51
+ | `gasSummary` | `boolean` | `false` | Print a per-method gas summary after `hardhat test`, with mock-only overhead excluded (see below) |
52
+ | `logMocks` | `boolean` | `false` | Enable event-based logging inside mock contracts |
51
53
 
52
54
  ---
53
55
 
@@ -127,6 +129,40 @@ const client = await cofhe.createClientWithBatteries(walletClient);
127
129
 
128
130
  ---
129
131
 
132
+ ### `cofhe.getAdjustedGasUsed(receipt)` / `cofhe.getAdjustedGasBreakdown(receipt)`
133
+
134
+ Mock transactions consume more gas than they would on a real CoFHE network, because the off-chain FHE work is replicated on-chain. The mock task manager measures that overhead and emits a `MockGasConsumed(uint256)` event per block of mock-only work, letting the plugin report corrected numbers:
135
+
136
+ ```typescript
137
+ const hash = await myContract.write.doFheThings();
138
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
139
+
140
+ // Gas usage excluding mock overhead — an estimate of real-network cost.
141
+ const adjusted = cofhe.getAdjustedGasUsed(receipt);
142
+
143
+ // Or the full breakdown:
144
+ const { gasUsed, mockGas, adjustedGasUsed, mockGasEvents } = cofhe.getAdjustedGasBreakdown(receipt);
145
+ ```
146
+
147
+ Both are pure functions of the receipt (no RPC calls). On a real network the receipt carries no mock events, so `adjustedGasUsed` equals `gasUsed` — the same code works everywhere.
148
+
149
+ With `cofhe: { gasSummary: true }` in the config, a per-method table (raw vs adjusted gas) is printed after `hardhat test`:
150
+
151
+ ```
152
+ [COFHE-MOCKS] Gas summary — adjusted ≈ cost excluding mock-only overhead
153
+ ┌──────────────────┬──────────────────────────┬───────┬─────────────────┬────────────────────┬───────────────┐
154
+ │ Contract │ Method │ Calls │ Avg gas (mocks) │ Avg gas (adjusted) │ Mock overhead │
155
+ ├──────────────────┼──────────────────────────┼───────┼─────────────────┼────────────────────┼───────────────┤
156
+ │ MyFHEContract │ doFheThings() │ 9 │ 146,199 │ 109,595 │ 25% │
157
+ └──────────────────┴──────────────────────────┴───────┴─────────────────┴────────────────────┴───────────────┘
158
+ ```
159
+
160
+ Note: `eth_estimateGas` is not adjusted — the mock work really does execute, so transactions still need the raw gas limit. Use a testnet for estimate-sensitive flows.
161
+
162
+ The summary table is collected per test worker at process exit and reconstructed from chain history: transactions rolled back by snapshots won't appear, and it is best-effort after forced exits (`process.exit`, Ctrl+C) — use `getAdjustedGasUsed(receipt)` inside tests for exact per-transaction numbers.
163
+
164
+ ---
165
+
130
166
  ### `cofhe.mocks`
131
167
 
132
168
  #### Contract descriptors
@@ -205,7 +241,8 @@ The plugin deploys these core contracts automatically on every `network.connect(
205
241
 
206
242
  | Contract | Address | Description |
207
243
  | ---------------------- | -------------------------------------------- | ------------------------------------------------------- |
208
- | `MockTaskManager` | `0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9` | Coordinates FHE operations and ACL |
244
+ | `MockCoFHEAddressBook` | `0xC0F4e00E531a2B086492Ae3DCC1515038307196b` | Resolves the TaskManager for FHE.sol (`getTm(1)`) |
245
+ | `MockTaskManager` | `0x0000000000000000000000000000000000005000` | Coordinates FHE operations and ACL |
209
246
  | `MockACL` | dynamic | Access Control List — address resolved from TaskManager |
210
247
  | `MockZkVerifier` | `0x0000000000000000000000000000000000005001` | Verifies ZK proofs for encrypted inputs |
211
248
  | `MockThresholdNetwork` | `0x0000000000000000000000000000000000005002` | Simulates the threshold decryption network |
@@ -0,0 +1,217 @@
1
+ // src/gas.ts
2
+ import chalk from "chalk";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { parseAbiItem, toEventSelector, toFunctionSelector, toFunctionSignature } from "viem";
6
+ import { MOCKS_TASK_MANAGER_ADDRESS } from "@cofhe/sdk";
7
+ var MOCK_GAS_CONSUMED_EVENT = parseAbiItem("event MockGasConsumed(uint256 gas)");
8
+ var MOCK_GAS_CONSUMED_TOPIC = toEventSelector(MOCK_GAS_CONSUMED_EVENT);
9
+ var mock_getAdjustedGasBreakdown = (receipt) => {
10
+ let mockGas = 0n;
11
+ let mockGasEvents = 0;
12
+ for (const log of receipt.logs ?? []) {
13
+ if (log.address.toLowerCase() === MOCKS_TASK_MANAGER_ADDRESS.toLowerCase() && log.topics[0]?.toLowerCase() === MOCK_GAS_CONSUMED_TOPIC) {
14
+ mockGas += BigInt(log.data);
15
+ mockGasEvents += 1;
16
+ }
17
+ }
18
+ const gasUsed = BigInt(receipt.gasUsed);
19
+ return { gasUsed, mockGas, adjustedGasUsed: mockGas > gasUsed ? 0n : gasUsed - mockGas, mockGasEvents };
20
+ };
21
+ var mock_getAdjustedGasUsed = (receipt) => mock_getAdjustedGasBreakdown(receipt).adjustedGasUsed;
22
+ var SUMMARY_DIR_NAME = "cofhe-gas-summary";
23
+ var registeredConnections = [];
24
+ var summaryDir;
25
+ var exitHookInstalled = false;
26
+ var exitHookRan = false;
27
+ var shortAddress = (address) => `${address.slice(0, 6)}..${address.slice(-4)}`;
28
+ var buildSelectorNameMap = async (artifacts) => {
29
+ const selectorNames = /* @__PURE__ */ new Map();
30
+ for (const fqn of await artifacts.getAllFullyQualifiedNames()) {
31
+ try {
32
+ const artifact = await artifacts.readArtifact(fqn);
33
+ for (const item of artifact.abi) {
34
+ if (item.type !== "function") continue;
35
+ const selector = toFunctionSelector(item);
36
+ if (!selectorNames.has(selector)) selectorNames.set(selector, toFunctionSignature(item));
37
+ }
38
+ } catch {
39
+ }
40
+ }
41
+ return selectorNames;
42
+ };
43
+ var buildAddressNameMap = async (publicClient, artifacts, addresses) => {
44
+ const codeToName = /* @__PURE__ */ new Map();
45
+ for (const fqn of await artifacts.getAllFullyQualifiedNames()) {
46
+ try {
47
+ const artifact = await artifacts.readArtifact(fqn);
48
+ if (artifact.deployedBytecode && artifact.deployedBytecode !== "0x") {
49
+ codeToName.set(artifact.deployedBytecode.toLowerCase(), artifact.contractName);
50
+ }
51
+ } catch {
52
+ }
53
+ }
54
+ const addressNames = /* @__PURE__ */ new Map();
55
+ for (const address of addresses) {
56
+ try {
57
+ const code = await publicClient.getCode({ address }) ?? "0x";
58
+ addressNames.set(address, codeToName.get(code.toLowerCase()) ?? shortAddress(address));
59
+ } catch {
60
+ addressNames.set(address, shortAddress(address));
61
+ }
62
+ }
63
+ return addressNames;
64
+ };
65
+ var collectMockGasRows = async (publicClient, artifacts, fromBlock = 0n) => {
66
+ let logs;
67
+ try {
68
+ logs = await publicClient.getLogs({
69
+ address: MOCKS_TASK_MANAGER_ADDRESS,
70
+ event: MOCK_GAS_CONSUMED_EVENT,
71
+ fromBlock,
72
+ toBlock: "latest"
73
+ });
74
+ } catch {
75
+ return [];
76
+ }
77
+ if (logs.length === 0) return [];
78
+ const mockGasPerTx = /* @__PURE__ */ new Map();
79
+ for (const log of logs) {
80
+ if (log.transactionHash === null) continue;
81
+ mockGasPerTx.set(log.transactionHash, (mockGasPerTx.get(log.transactionHash) ?? 0n) + (log.args.gas ?? 0n));
82
+ }
83
+ const aggregates = /* @__PURE__ */ new Map();
84
+ for (const [txHash, mockGas] of mockGasPerTx) {
85
+ try {
86
+ const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
87
+ const tx = await publicClient.getTransaction({ hash: txHash });
88
+ const target = tx.to ?? receipt.contractAddress;
89
+ if (!target) continue;
90
+ const selector = tx.to ? (tx.input ?? "0x").slice(0, 10) : "(deployment)";
91
+ const key = `${target}:${selector}`;
92
+ const aggregate = aggregates.get(key) ?? { to: target, selector, calls: 0, totalGasUsed: 0n, totalMockGas: 0n };
93
+ aggregate.calls += 1;
94
+ aggregate.totalGasUsed += receipt.gasUsed;
95
+ aggregate.totalMockGas += mockGas;
96
+ aggregates.set(key, aggregate);
97
+ } catch {
98
+ }
99
+ }
100
+ if (aggregates.size === 0) return [];
101
+ const selectorNames = await buildSelectorNameMap(artifacts);
102
+ const addressNames = await buildAddressNameMap(publicClient, artifacts, [
103
+ ...new Set([...aggregates.values()].map((a) => a.to))
104
+ ]);
105
+ return [...aggregates.values()].map((a) => ({
106
+ contract: addressNames.get(a.to) ?? shortAddress(a.to),
107
+ method: selectorNames.get(a.selector) ?? a.selector,
108
+ calls: a.calls,
109
+ totalGasUsed: a.totalGasUsed.toString(),
110
+ totalMockGas: a.totalMockGas.toString()
111
+ }));
112
+ };
113
+ var registerGasSummaryConnection = (publicClient, artifacts, cacheDir, fromBlock) => {
114
+ registeredConnections.push({ publicClient, artifacts, fromBlock });
115
+ summaryDir = path.join(cacheDir, SUMMARY_DIR_NAME);
116
+ if (exitHookInstalled) return;
117
+ exitHookInstalled = true;
118
+ process.on("beforeExit", () => {
119
+ if (exitHookRan) return;
120
+ exitHookRan = true;
121
+ void (async () => {
122
+ const rows = [];
123
+ for (const { publicClient: client, artifacts: arts, fromBlock: fromBlock2 } of registeredConnections) {
124
+ try {
125
+ rows.push(...await collectMockGasRows(client, arts, fromBlock2));
126
+ } catch {
127
+ }
128
+ }
129
+ if (rows.length === 0 || summaryDir === void 0) return;
130
+ try {
131
+ fs.mkdirSync(summaryDir, { recursive: true });
132
+ const file = path.join(summaryDir, `rows-${process.pid}-${Date.now()}.json`);
133
+ fs.writeFileSync(file, JSON.stringify(rows), "utf8");
134
+ } catch {
135
+ }
136
+ })();
137
+ });
138
+ };
139
+ var cleanGasSummaryDir = (cacheDir) => {
140
+ try {
141
+ fs.rmSync(path.join(cacheDir, SUMMARY_DIR_NAME), { recursive: true, force: true });
142
+ } catch {
143
+ }
144
+ };
145
+ var printMockGasSummaryFromDir = (cacheDir) => {
146
+ const dir = path.join(cacheDir, SUMMARY_DIR_NAME);
147
+ let files;
148
+ try {
149
+ files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
150
+ } catch {
151
+ return;
152
+ }
153
+ const merged = /* @__PURE__ */ new Map();
154
+ for (const file of files) {
155
+ try {
156
+ const rows2 = JSON.parse(fs.readFileSync(path.join(dir, file), "utf8"));
157
+ for (const r of rows2) {
158
+ const key = `${r.contract}:${r.method}`;
159
+ const row = merged.get(key) ?? { contract: r.contract, method: r.method, calls: 0, gasUsed: 0n, mockGas: 0n };
160
+ row.calls += r.calls;
161
+ row.gasUsed += BigInt(r.totalGasUsed);
162
+ row.mockGas += BigInt(r.totalMockGas);
163
+ merged.set(key, row);
164
+ }
165
+ } catch {
166
+ }
167
+ }
168
+ cleanGasSummaryDir(cacheDir);
169
+ if (merged.size === 0) return;
170
+ const rows = [...merged.values()].map((r) => {
171
+ const avgGasUsed = r.gasUsed / BigInt(r.calls);
172
+ const avgMockGas = r.mockGas / BigInt(r.calls);
173
+ return {
174
+ contract: r.contract,
175
+ method: r.method,
176
+ calls: r.calls,
177
+ avgGasUsed,
178
+ avgAdjusted: avgMockGas > avgGasUsed ? 0n : avgGasUsed - avgMockGas,
179
+ overheadPct: avgGasUsed === 0n ? 0 : Math.min(100, Number(avgMockGas * 100n / avgGasUsed))
180
+ };
181
+ }).sort((a, b) => a.contract.localeCompare(b.contract) || a.method.localeCompare(b.method));
182
+ const headers = ["Contract", "Method", "Calls", "Avg gas (mocks)", "Avg gas (adjusted)", "Mock overhead"];
183
+ const cells = rows.map((r) => [
184
+ r.contract,
185
+ r.method,
186
+ String(r.calls),
187
+ r.avgGasUsed.toLocaleString(),
188
+ r.avgAdjusted.toLocaleString(),
189
+ `${r.overheadPct}%`
190
+ ]);
191
+ const widths = headers.map((h, i) => Math.max(h.length, ...cells.map((row) => row[i].length)));
192
+ const line = (row) => `\u2502 ${row.map((cell, i) => cell.padEnd(widths[i])).join(" \u2502 ")} \u2502`;
193
+ const divider = (l, m, r) => `${l}${widths.map((w) => "\u2500".repeat(w + 2)).join(m)}${r}`;
194
+ console.log("");
195
+ console.log(chalk.bold("[COFHE-MOCKS] Gas summary") + chalk.dim(" \u2014 adjusted \u2248 cost excluding mock-only overhead"));
196
+ console.log(divider("\u250C", "\u252C", "\u2510"));
197
+ console.log(line(headers));
198
+ console.log(divider("\u251C", "\u253C", "\u2524"));
199
+ for (const row of cells) console.log(line(row));
200
+ console.log(divider("\u2514", "\u2534", "\u2518"));
201
+ console.log(
202
+ chalk.dim(
203
+ "Raw numbers include on-chain replication of off-chain CoFHE work; adjusted numbers estimate real-network cost. estimateGas remains unadjusted."
204
+ )
205
+ );
206
+ };
207
+
208
+ export {
209
+ MOCK_GAS_CONSUMED_EVENT,
210
+ MOCK_GAS_CONSUMED_TOPIC,
211
+ mock_getAdjustedGasBreakdown,
212
+ mock_getAdjustedGasUsed,
213
+ collectMockGasRows,
214
+ registerGasSummaryConnection,
215
+ cleanGasSummaryDir,
216
+ printMockGasSummaryFromDir
217
+ };
@@ -1,10 +1,10 @@
1
1
  // src/logging.ts
2
2
  import chalk from "chalk";
3
3
  import { MockTaskManagerArtifact } from "@cofhe/mock-contracts";
4
- import { TASK_MANAGER_ADDRESS } from "@cofhe/sdk";
4
+ import { MOCKS_TASK_MANAGER_ADDRESS } from "@cofhe/sdk";
5
5
  async function getLoggingEnabled(publicClient) {
6
6
  return publicClient.readContract({
7
- address: TASK_MANAGER_ADDRESS,
7
+ address: MOCKS_TASK_MANAGER_ADDRESS,
8
8
  abi: MockTaskManagerArtifact.abi,
9
9
  functionName: "logOps",
10
10
  args: []
@@ -13,7 +13,7 @@ async function getLoggingEnabled(publicClient) {
13
13
  async function setLoggingEnabled(publicClient, walletClient, enabled) {
14
14
  const [account] = await walletClient.getAddresses();
15
15
  const hash = await walletClient.writeContract({
16
- address: TASK_MANAGER_ADDRESS,
16
+ address: MOCKS_TASK_MANAGER_ADDRESS,
17
17
  abi: MockTaskManagerArtifact.abi,
18
18
  functionName: "setLogOps",
19
19
  args: [enabled],
@@ -1,10 +1,18 @@
1
1
  // src/deploy.ts
2
- import { createTestClient, custom } from "viem";
2
+ import { createTestClient, custom, encodeFunctionData } from "viem";
3
3
  import chalk from "chalk";
4
4
  import { privateKeyToAccount } from "viem/accounts";
5
- import { MockACLArtifact, MockTaskManagerArtifact, MockThresholdNetworkArtifact } from "@cofhe/mock-contracts";
6
5
  import {
7
- TASK_MANAGER_ADDRESS,
6
+ ACPShareRegistryArtifact,
7
+ MockACLArtifact,
8
+ MockCoFHEAddressBookArtifact,
9
+ MockTaskManagerArtifact,
10
+ MockThresholdNetworkArtifact
11
+ } from "@cofhe/mock-contracts";
12
+ import {
13
+ COFHE_ADDRESS_BOOK_ADDRESS,
14
+ TASK_MANAGER_ID,
15
+ MOCKS_TASK_MANAGER_ADDRESS,
8
16
  MOCKS_ZK_VERIFIER_ADDRESS,
9
17
  MOCKS_ZK_VERIFIER_SIGNER_ADDRESS,
10
18
  MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY,
@@ -28,11 +36,13 @@ async function deployMocks(ctx, options = {}) {
28
36
  return {};
29
37
  }
30
38
  log("vv", chalk.bold("cofhe-hardhat-3-plugin :: deploy mocks"), 0);
31
- await deployFixed(ctx.publicClient, "MockTaskManager", TASK_MANAGER_ADDRESS, ctx.artifacts);
32
- logDeployment("MockTaskManager", TASK_MANAGER_ADDRESS);
39
+ await deployFixed(ctx.publicClient, "MockCoFHEAddressBook", COFHE_ADDRESS_BOOK_ADDRESS, ctx.artifacts);
40
+ logDeployment("MockCoFHEAddressBook", COFHE_ADDRESS_BOOK_ADDRESS);
41
+ await deployFixed(ctx.publicClient, "MockTaskManager", MOCKS_TASK_MANAGER_ADDRESS, ctx.artifacts);
42
+ logDeployment("MockTaskManager", MOCKS_TASK_MANAGER_ADDRESS);
33
43
  const [account] = await ctx.walletClient.getAddresses();
34
44
  await ctx.walletClient.writeContract({
35
- address: TASK_MANAGER_ADDRESS,
45
+ address: MOCKS_TASK_MANAGER_ADDRESS,
36
46
  abi: MockTaskManagerArtifact.abi,
37
47
  functionName: "initialize",
38
48
  args: [account],
@@ -40,7 +50,16 @@ async function deployMocks(ctx, options = {}) {
40
50
  chain: null
41
51
  });
42
52
  await ctx.walletClient.writeContract({
43
- address: TASK_MANAGER_ADDRESS,
53
+ address: COFHE_ADDRESS_BOOK_ADDRESS,
54
+ abi: MockCoFHEAddressBookArtifact.abi,
55
+ functionName: "setTm",
56
+ args: [TASK_MANAGER_ID, MOCKS_TASK_MANAGER_ADDRESS],
57
+ account,
58
+ chain: null
59
+ });
60
+ log("vv", "TaskManager registered in CoFHEAddressBook", 2);
61
+ await ctx.walletClient.writeContract({
62
+ address: MOCKS_TASK_MANAGER_ADDRESS,
44
63
  abi: MockTaskManagerArtifact.abi,
45
64
  functionName: "setSecurityZones",
46
65
  args: [0, 1],
@@ -50,7 +69,7 @@ async function deployMocks(ctx, options = {}) {
50
69
  const aclAddress = await deployVariable(ctx, "MockACL", []);
51
70
  logDeployment("MockACL", aclAddress);
52
71
  await ctx.walletClient.writeContract({
53
- address: TASK_MANAGER_ADDRESS,
72
+ address: MOCKS_TASK_MANAGER_ADDRESS,
54
73
  abi: MockTaskManagerArtifact.abi,
55
74
  functionName: "setACLContract",
56
75
  args: [aclAddress],
@@ -58,6 +77,15 @@ async function deployMocks(ctx, options = {}) {
58
77
  chain: null
59
78
  });
60
79
  log("vv", "ACL address set in TaskManager", 2);
80
+ await ctx.walletClient.writeContract({
81
+ address: aclAddress,
82
+ abi: MockACLArtifact.abi,
83
+ functionName: "setTaskManager",
84
+ args: [MOCKS_TASK_MANAGER_ADDRESS],
85
+ account,
86
+ chain: null
87
+ });
88
+ log("vv", "TaskManager address set in ACL", 2);
61
89
  const acpRevokerAddress = await deployVariable(ctx, "ACPTimestampRevoker", []);
62
90
  logDeployment("ACPTimestampRevoker", acpRevokerAddress);
63
91
  await ctx.walletClient.writeContract({
@@ -69,7 +97,11 @@ async function deployMocks(ctx, options = {}) {
69
97
  chain: null
70
98
  });
71
99
  log("vv", "Default revoker contract set in ACL", 2);
72
- const acpShareRegistryAddress = await deployVariable(ctx, "ACPShareRegistry", []);
100
+ const acpShareRegistryImpl = await deployVariable(ctx, "ACPShareRegistry", []);
101
+ const acpShareRegistryAddress = await deployVariable(ctx, "MockERC1967Proxy", [
102
+ acpShareRegistryImpl,
103
+ encodeFunctionData({ abi: ACPShareRegistryArtifact.abi, functionName: "initialize", args: [account] })
104
+ ]);
73
105
  logDeployment("ACPShareRegistry", acpShareRegistryAddress);
74
106
  await ctx.walletClient.writeContract({
75
107
  address: aclAddress,
@@ -82,7 +114,7 @@ async function deployMocks(ctx, options = {}) {
82
114
  log("vv", "Share registry set in ACL", 2);
83
115
  const verifierSigner = privateKeyToAccount(MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY);
84
116
  await ctx.walletClient.writeContract({
85
- address: TASK_MANAGER_ADDRESS,
117
+ address: MOCKS_TASK_MANAGER_ADDRESS,
86
118
  abi: MockTaskManagerArtifact.abi,
87
119
  functionName: "setVerifierSigner",
88
120
  args: [verifierSigner.address],
@@ -92,7 +124,7 @@ async function deployMocks(ctx, options = {}) {
92
124
  log("vv", "Verifier signer set", 2);
93
125
  const decryptSigner = privateKeyToAccount(MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY);
94
126
  await ctx.walletClient.writeContract({
95
- address: TASK_MANAGER_ADDRESS,
127
+ address: MOCKS_TASK_MANAGER_ADDRESS,
96
128
  abi: MockTaskManagerArtifact.abi,
97
129
  functionName: "setDecryptResultSigner",
98
130
  args: [decryptSigner.address],
@@ -120,7 +152,7 @@ async function deployMocks(ctx, options = {}) {
120
152
  address: MockThresholdNetworkArtifact.fixedAddress,
121
153
  abi: MockThresholdNetworkArtifact.abi,
122
154
  functionName: "initialize",
123
- args: [TASK_MANAGER_ADDRESS, aclAddress],
155
+ args: [MOCKS_TASK_MANAGER_ADDRESS, aclAddress],
124
156
  account,
125
157
  chain: null
126
158
  });
@@ -128,13 +160,14 @@ async function deployMocks(ctx, options = {}) {
128
160
  if (gasWarning) {
129
161
  logEmpty("v");
130
162
  logWarning(
131
- "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)",
163
+ "When using mocks, FHE operations consume extra gas replicating off-chain CoFHE work on-chain. Use conn.cofhe.getAdjustedGasUsed(receipt) or set 'cofhe.gasSummary: true' to see gas numbers with that overhead excluded.\n(Disable this warning by setting 'cofhe.gasWarning: false' in your Hardhat config)",
132
164
  0
133
165
  );
134
166
  }
135
167
  logEmpty("v");
136
168
  return {
137
- MockTaskManager: TASK_MANAGER_ADDRESS,
169
+ MockCoFHEAddressBook: COFHE_ADDRESS_BOOK_ADDRESS,
170
+ MockTaskManager: MOCKS_TASK_MANAGER_ADDRESS,
138
171
  MockACL: aclAddress,
139
172
  ACPTimestampRevoker: acpRevokerAddress,
140
173
  ACPShareRegistry: acpShareRegistryAddress,
@@ -186,7 +219,7 @@ var logDeployment = (contractName, address) => {
186
219
  };
187
220
 
188
221
  // src/utils.ts
189
- import { TASK_MANAGER_ADDRESS as TASK_MANAGER_ADDRESS2, MOCKS_ZK_VERIFIER_ADDRESS as MOCKS_ZK_VERIFIER_ADDRESS2 } from "@cofhe/sdk";
222
+ import { MOCKS_TASK_MANAGER_ADDRESS as MOCKS_TASK_MANAGER_ADDRESS2, MOCKS_ZK_VERIFIER_ADDRESS as MOCKS_ZK_VERIFIER_ADDRESS2 } from "@cofhe/sdk";
190
223
  import path from "path";
191
224
  import fs from "fs";
192
225
  import { createRequire } from "module";
@@ -216,7 +249,7 @@ async function mock_getPlaintext(publicClient, ctHash) {
216
249
  return void 0;
217
250
  }
218
251
  return publicClient.readContract({
219
- address: TASK_MANAGER_ADDRESS2,
252
+ address: MOCKS_TASK_MANAGER_ADDRESS2,
220
253
  abi: [
221
254
  {
222
255
  name: "mockStorage",
@@ -236,7 +269,7 @@ async function mock_expectPlaintext(publicClient, ctHash, expectedValue) {
236
269
  return;
237
270
  }
238
271
  const exists = await publicClient.readContract({
239
- address: TASK_MANAGER_ADDRESS2,
272
+ address: MOCKS_TASK_MANAGER_ADDRESS2,
240
273
  abi: [
241
274
  {
242
275
  name: "inMockStorage",
@@ -46,6 +46,7 @@ function resolvePluginConfig(userConfig, resolvedConfig) {
46
46
  resolvedConfig.cofhe = {
47
47
  logMocks: userConfig.cofhe?.logMocks ?? false,
48
48
  gasWarning: userConfig.cofhe?.gasWarning ?? false,
49
+ gasSummary: userConfig.cofhe?.gasSummary ?? false,
49
50
  mocksDeployVerbosity: userConfig.cofhe?.mocksDeployVerbosity ?? "v"
50
51
  };
51
52
  }
@@ -3,17 +3,23 @@ import {
3
3
  getMockContractsNpmPaths,
4
4
  mock_expectPlaintext,
5
5
  mock_getPlaintext
6
- } from "./chunk-E7DR6EGV.js";
6
+ } from "./chunk-W4H6WKGI.js";
7
7
  import {
8
8
  mock_setLoggingEnabled,
9
9
  mock_withLogs
10
- } from "./chunk-IVRNGFNF.js";
10
+ } from "./chunk-NYXXHYHW.js";
11
+ import {
12
+ mock_getAdjustedGasBreakdown,
13
+ mock_getAdjustedGasUsed,
14
+ registerGasSummaryConnection
15
+ } from "./chunk-6G2MCXNM.js";
11
16
 
12
17
  // src/hooks/hre.ts
13
18
  import { FileBuildResultType } from "hardhat/types/solidity";
14
19
  import { createPublicClient, createWalletClient, custom } from "viem";
15
20
  import { privateKeyToAccount } from "viem/accounts";
16
21
  import {
22
+ MockCoFHEAddressBookArtifact,
17
23
  MockTaskManagerArtifact,
18
24
  MockACLArtifact,
19
25
  MockZkVerifierArtifact,
@@ -44,6 +50,8 @@ function createCofheConnection(publicClient, walletClient, transport, artifacts,
44
50
  createClient(config) {
45
51
  return createCofheClient(config);
46
52
  },
53
+ getAdjustedGasUsed: mock_getAdjustedGasUsed,
54
+ getAdjustedGasBreakdown: mock_getAdjustedGasBreakdown,
47
55
  async createClientWithBatteries(signerWalletClient) {
48
56
  let signerClient;
49
57
  let address;
@@ -85,6 +93,10 @@ function createCofheConnection(publicClient, walletClient, transport, artifacts,
85
93
  async expectPlaintext(ctHash, expectedValue) {
86
94
  await mock_expectPlaintext(publicClient, ctHash, expectedValue);
87
95
  },
96
+ MockCoFHEAddressBook: {
97
+ address: deployedMockContracts.MockCoFHEAddressBook,
98
+ abi: MockCoFHEAddressBookArtifact.abi
99
+ },
88
100
  MockTaskManager: { address: deployedMockContracts.MockTaskManager, abi: MockTaskManagerArtifact.abi },
89
101
  MockACL: { address: deployedMockContracts.MockACL, abi: MockACLArtifact.abi },
90
102
  MockZkVerifier: { address: deployedMockContracts.MockZkVerifier, abi: MockZkVerifierArtifact.abi },
@@ -136,6 +148,10 @@ var hreHooks = {
136
148
  mocksDeployVerbosity: hre.config.cofhe.mocksDeployVerbosity
137
149
  }
138
150
  );
151
+ if (hre.config.cofhe.gasSummary && deployedMockContracts.MockTaskManager !== void 0) {
152
+ const fromBlock = await publicClient.getBlockNumber();
153
+ registerGasSummaryConnection(publicClient, hre.artifacts, hre.config.paths.cache, fromBlock);
154
+ }
139
155
  conn.cofhe = createCofheConnection(
140
156
  publicClient,
141
157
  walletClient,