@tokamak-private-dapps/private-state-cli 2.0.0 → 2.1.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
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.1.0 - 2026-05-14
6
+
7
+ - Required current epoch-aware wallet workspaces for wallet commands and backup imports. Local
8
+ wallet metadata must include the wallet index and epoch metadata; users with older local
9
+ workspaces should rebuild them with `wallet recover-workspace`.
10
+ - Required current epoch-aware evidence bundle note paths in the investigator and removed the
11
+ special-case legacy evidence layout branch.
12
+ - Consolidated the static evidence investigator into the CLI package under `cli/investigator/`
13
+ and removed the duplicate top-level investigator copy.
14
+ - Simplified wallet command argument validation by removing unused schema fallback wrappers.
15
+
5
16
  ## 2.0.0 - 2026-05-13
6
17
 
7
18
  - Split wallet export/import into `wallet export backup`, `wallet export viewing-key`,
@@ -22,6 +33,10 @@
22
33
  commitments and nullifiers, creation/spend transaction references, receipts, events, calldata, and
23
34
  filtering indexes, while excluding viewing keys, spending keys, wallet secrets, account private
24
35
  keys, and `.key` files.
36
+ - Made local wallet workspaces epoch-aware. `channel exit` now marks the active wallet epoch as
37
+ exited and retains its local note metadata instead of deleting the wallet workspace, while
38
+ `wallet recover-workspace` and `wallet get-notes --export-evidence` can still use retained exited
39
+ epochs for historical disclosure.
25
40
  - Added a local static evidence investigator GUI and bundled it with the NPM package. The new
26
41
  top-level `private-state-cli investigator` command prints the bundled HTML path, prints the file
27
42
  URL, and opens the GUI in the default browser.
package/README.md CHANGED
@@ -176,6 +176,16 @@ channel genesis and only runs when the recovery delta fits within the 7,200-bloc
176
176
  is missing, unusable, or too far behind, the command stops and asks the user to run the appropriate recovery command
177
177
  with `--from-genesis` explicitly when needed.
178
178
 
179
+ Local wallet workspaces are epoch-aware. Each successful channel registration creates a wallet epoch under the
180
+ canonical wallet directory. `channel exit` does not delete the local wallet workspace; it marks the active epoch as
181
+ exited with the exit transaction, block, and timestamp, then keeps that epoch read-only for historical note inspection
182
+ and evidence export. If the same account later joins the same channel again, the new registration is a separate active
183
+ epoch under the same canonical wallet name.
184
+
185
+ The current CLI only supports this epoch-aware wallet workspace layout. If a local wallet directory was created by an
186
+ older CLI and does not contain `wallet-index.metadata.json` plus `epochs/<epoch-id>/` metadata files, rebuild it with
187
+ `wallet recover-workspace` before using wallet commands.
188
+
179
189
  Channel leaders can optionally register a workspace mirror server so users can bootstrap recovery
180
190
  from a signed checkpoint and download only the local-to-checkpoint delta when a local recovery index
181
191
  already exists. The channel leader can build the static mirror files with
@@ -228,8 +238,9 @@ private-state-cli wallet get-notes --network mainnet --wallet <WALLET> --export-
228
238
  This ZIP is an input for `private-state-cli investigator`. It contains plaintext for all locally known
229
239
  notes, derived commitments and nullifiers, creation and spend transaction references, transaction calldata, receipts,
230
240
  events, and indexes for filtering by note, nullifier, transaction, block range, or available counterparty metadata. It
231
- does not include viewing keys, spending keys, wallet secret material, account private keys, or `.key` files. Do not
232
- submit the raw ZIP as an exchange or auditor package unless full wallet-history disclosure is intended.
241
+ includes all local epochs for the selected wallet, including exited epochs retained after `channel exit`. It does not
242
+ include viewing keys, spending keys, wallet secret material, account private keys, or `.key` files. Do not submit the
243
+ raw ZIP as an exchange or auditor package unless full wallet-history disclosure is intended.
233
244
 
234
245
  Open the local evidence investigator with:
235
246
 
@@ -241,6 +252,9 @@ The command prints the bundled investigator HTML path and file URL, then opens t
241
252
  evidence ZIP in that GUI, apply the requested filters, and export a narrower user-consent disclosure ZIP. The GUI runs
242
253
  locally in the browser and does not send files over the network.
243
254
 
255
+ The investigator accepts current epoch-aware evidence bundles only. If a bundle was generated by an older CLI, rebuild
256
+ the wallet workspace with `wallet recover-workspace` and export a new bundle with `wallet get-notes --export-evidence`.
257
+
244
258
  Estimate live transaction costs before sending commands with:
245
259
 
246
260
  ```bash
@@ -298,7 +312,8 @@ and stores a protected local account secret for later `--account` use. The sourc
298
312
  wallet backup metadata, viewing-key metadata, and spending-key metadata as separate files. `wallet list` reads only the local workspace and prints saved wallet names that can be reused with
299
313
  `--wallet`.
300
314
  `wallet get-meta` opens the wallet metadata and reports the stored L1/L2 identity metadata plus the current
301
- on-chain channel registration match state, including the registered note-receive public key when present.
315
+ on-chain channel registration match state, including the registered note-receive public key when present. On
316
+ epoch-aware wallet workspaces it also reports the selected wallet epoch and whether that epoch is active or exited.
302
317
  `account get-l1-address` is a simple offline helper that derives the L1 address for a local account.
303
318
 
304
319
  ### Wallet Secret Source File
@@ -22,6 +22,10 @@ The raw evidence bundle contains plaintext for all locally known notes. Do not s
22
22
  as an exchange or auditor package unless full wallet-history disclosure is intended. Use the
23
23
  investigator output package for scoped disclosure.
24
24
 
25
+ The investigator accepts current epoch-aware evidence bundles only. Supported note records live under
26
+ `wallets/<wallet>/epochs/<epoch-id>/notes/` inside the ZIP. If a bundle uses an older layout, rebuild the local wallet
27
+ workspace with `wallet recover-workspace` and export a new evidence ZIP with `wallet get-notes --export-evidence`.
28
+
25
29
  ## Supported Filtering
26
30
 
27
31
  - note commitment or nullifier
@@ -60,8 +60,11 @@ async function loadEvidenceBundle(bytes) {
60
60
  if (manifest.format !== "tokamak-private-state-raw-evidence-bundle") {
61
61
  throw new Error(`Unsupported evidence format: ${manifest.format ?? "missing"}.`);
62
62
  }
63
+ if (Number(manifest.formatVersion) !== 2) {
64
+ throw new Error("Current evidence bundle formatVersion 2 is required. Run wallet recover-workspace, then run wallet get-notes --export-evidence again.");
65
+ }
63
66
  const notes = [...files.entries()]
64
- .filter(([path]) => path.startsWith("notes/") && path.endsWith(".json"))
67
+ .filter(([path]) => isEvidenceNotePath(path))
65
68
  .map(([path, content]) => ({
66
69
  path,
67
70
  record: JSON.parse(content),
@@ -69,7 +72,7 @@ async function loadEvidenceBundle(bytes) {
69
72
  .sort((left, right) =>
70
73
  String(left.record?.derived?.commitment ?? "").localeCompare(String(right.record?.derived?.commitment ?? "")));
71
74
  if (notes.length === 0) {
72
- throw new Error("The evidence bundle does not contain note records.");
75
+ throw new Error("The evidence bundle does not contain current epoch-aware note records.");
73
76
  }
74
77
  state.files = files;
75
78
  state.manifest = manifest;
@@ -79,7 +82,20 @@ async function loadEvidenceBundle(bytes) {
79
82
  els.buildPackage.disabled = false;
80
83
  els.selectAll.disabled = false;
81
84
  els.selectNone.disabled = false;
82
- setStatus(`Loaded ${notes.length} note records from ${manifest.wallet ?? "wallet"} on ${manifest.network ?? "network"}.`);
85
+ setStatus(
86
+ `Loaded ${notes.length} note records from ${evidenceWalletLabel(manifest)} on ${manifest.network ?? "network"}.`,
87
+ );
88
+ }
89
+
90
+ function isEvidenceNotePath(entryPath) {
91
+ return /^wallets\/[^/]+\/epochs\/[^/]+\/notes\/[^/]+\.json$/u.test(entryPath);
92
+ }
93
+
94
+ function evidenceWalletLabel(manifest) {
95
+ if (manifest.wallets?.length) {
96
+ return `${manifest.wallets[0].wallet ?? manifest.wallet ?? "wallet"} (${manifest.wallets.length} epochs)`;
97
+ }
98
+ return manifest.wallet ?? "wallet";
83
99
  }
84
100
 
85
101
  function resetBundle() {
@@ -324,6 +340,7 @@ function buildDisclosureManifest({ selectedNotes, selectedPaths, packageMetadata
324
340
  channelName: state.manifest.channelName,
325
341
  channelId: state.manifest.channelId,
326
342
  wallet: state.manifest.wallet,
343
+ wallets: state.manifest.wallets ?? null,
327
344
  walletL1Address: state.manifest.walletL1Address,
328
345
  walletL2Address: state.manifest.walletL2Address,
329
346
  },
@@ -441,7 +441,10 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
441
441
  description: "Check whether a wallet matches the on-chain channel registration.",
442
442
  fields: ["wallet", "network"],
443
443
  usage: "--wallet and --network",
444
- help: ["Refreshes the local channel workspace through the saved recovery index before reading registration metadata when the scan fits the 10 second pre-command budget"],
444
+ help: [
445
+ "Refreshes the local channel workspace through the saved recovery index before reading registration metadata when the scan fits the 10 second pre-command budget",
446
+ "Reports the selected local wallet epoch and lifecycle status when the workspace uses the epoch-aware wallet format",
447
+ ],
445
448
  },
446
449
  {
447
450
  id: "wallet-list",
@@ -548,7 +551,10 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
548
551
  description: "Exit a channel. Both the CLI and bridge contract require a zero channel balance.",
549
552
  fields: ["wallet", "network"],
550
553
  usage: "--wallet and --network",
551
- help: ["Refreshes the local channel workspace through the saved recovery index before checking the channel balance when the scan fits the 10 second pre-command budget"],
554
+ help: [
555
+ "Refreshes the local channel workspace through the saved recovery index before checking the channel balance when the scan fits the 10 second pre-command budget",
556
+ "Marks the current local wallet epoch as exited and keeps its note metadata available for historical evidence export",
557
+ ],
552
558
  },
553
559
  {
554
560
  id: "wallet-mint-notes",
@@ -615,6 +621,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
615
621
  "Refreshes received-note logs through the saved wallet note recovery index when the scan fits the 10 second pre-command budget",
616
622
  "Fails instead of replaying from genesis; run wallet recover-workspace --from-genesis when a genesis rebuild is required",
617
623
  "Use --export-evidence <PATH> with --acknowledge-full-note-plaintext-export to write a local full-note evidence ZIP for private-state-cli investigator",
624
+ "Evidence export includes all local epochs for the selected wallet, including exited epochs retained for dispute evidence",
618
625
  ],
619
626
  },
620
627
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamak-private-dapps/private-state-cli",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Command-line client for the Tokamak private-state DApp.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Tokamak Network",