@tokamak-private-dapps/private-state-cli 1.1.0 → 1.1.1

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,7 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.1 - 2026-05-08
4
+
5
+ - Added bridge deployment verification support for Etherscan-compatible explorers, including
6
+ proxy and implementation verification for the main bridge contracts after deploy or upgrade
7
+ flows.
8
+ - Added an incremental ChannelManager verification script that scans channel creation events from
9
+ the last indexed block, skips already verified channel contracts, and persists scan progress for
10
+ later runs.
11
+ - Required `channel join` to refresh through the recovery index before joining an existing channel,
12
+ while preserving the explicit `--from-genesis` path for recovery commands that intentionally
13
+ rebuild workspace state from channel genesis.
14
+ - Verified the private-state CLI end-to-end flow with isolated local workspace state after the
15
+ indexed join recovery change.
16
+
3
17
  ## 1.1.0 - 2026-05-06
4
18
 
19
+ - Required `channel join` to use an existing recovered channel workspace and refresh through the
20
+ recovery index before submitting the join transaction, so old channels are not silently replayed
21
+ from genesis during join. `wallet recover-workspace --from-genesis` now also replays encrypted
22
+ note delivery logs from channel genesis for existing wallets.
5
23
  - Refreshed channel workspaces through the existing recovery-indexed replay path after successful
6
24
  wallet transactions instead of manually patching local snapshots, and bounded post-transaction
7
25
  replay by the transaction receipt block so provider latest-block lag cannot skip the confirmed
package/README.md CHANGED
@@ -110,6 +110,11 @@ private-state-cli wallet recover-workspace --channel-name <CHANNEL> --network ma
110
110
  `channel create` is the exception: after the channel is created on-chain, the CLI initializes that new local workspace
111
111
  by replaying from the channel's genesis block because no prior recovery index can exist for a new channel.
112
112
 
113
+ `channel join` requires the channel workspace to have a usable recovery index and refreshes that workspace through the
114
+ indexed path before submitting the registration transaction. For a channel that was created elsewhere, run
115
+ `channel recover-workspace --from-genesis` once before joining; later joins and wallet commands resume from the saved
116
+ index instead of silently replaying from genesis.
117
+
113
118
  Wallet getter commands that need channel state, including `wallet get-meta`, `wallet get-channel-fund`, and
114
119
  `wallet get-notes`, follow the same indexed recovery rule before reading local or on-chain state. `wallet get-notes` also uses
115
120
  the wallet's saved note-receive scan index for encrypted note delivery logs. If either index is unusable, the command
@@ -332,6 +332,8 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
332
332
  fields: ["channelName", "network", "account", "walletSecretPath", "rpcUrl"],
333
333
  usage: "--channel-name, --network, --account, --wallet-secret-path, and optional --rpc-url",
334
334
  help: [
335
+ "Requires a recovered channel workspace and refreshes it through the workspace recovery index before joining",
336
+ "Run channel recover-workspace --from-genesis once if no usable local recovery index exists",
335
337
  "--wallet-secret-path imports an existing source secret file into the protected wallet-local secret file",
336
338
  "Prints the immutable policy snapshot before first registration",
337
339
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamak-private-dapps/private-state-cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
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",
@@ -846,11 +846,6 @@ async function syncChannelWorkspace({
846
846
  ethers.toBigInt(derivedAPubBlockHash) === ethers.toBigInt(normalizeBytes32Hex(channelInfo.aPubBlockHash)),
847
847
  `Derived channel block-info hash ${derivedAPubBlockHash} does not match onchain ${channelInfo.aPubBlockHash}.`,
848
848
  );
849
- const localSnapshotReusable = !fromGenesis && canReuseLocalWorkspaceSnapshot({
850
- existingArtifacts,
851
- currentRootVectorHash,
852
- managedStorageAddresses,
853
- });
854
849
  const recoveryIndex = useWorkspaceRecoveryIndex && !fromGenesis
855
850
  ? getUsableWorkspaceRecoveryIndex({
856
851
  existingArtifacts,
@@ -859,6 +854,12 @@ async function syncChannelWorkspace({
859
854
  managedStorageAddresses,
860
855
  })
861
856
  : null;
857
+ const localSnapshotReusable = !fromGenesis && (!useWorkspaceRecoveryIndex || recoveryIndex)
858
+ && canReuseLocalWorkspaceSnapshot({
859
+ existingArtifacts,
860
+ currentRootVectorHash,
861
+ managedStorageAddresses,
862
+ });
862
863
  if (useWorkspaceRecoveryIndex && !fromGenesis && !localSnapshotReusable && !recoveryIndex) {
863
864
  throw new Error([
864
865
  `Workspace recovery index is missing or unusable for channel ${channelName} on ${networkNameFromChainId(network.chainId)}.`,
@@ -1155,6 +1156,7 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
1155
1156
  signer,
1156
1157
  noteReceiveKeyMaterial,
1157
1158
  progressAction: "wallet recover-workspace",
1159
+ fromGenesis: args.fromGenesis === true,
1158
1160
  });
1159
1161
  printJson({
1160
1162
  action: "wallet recover-workspace",
@@ -1202,6 +1204,7 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
1202
1204
  signer,
1203
1205
  noteReceiveKeyMaterial,
1204
1206
  progressAction: "wallet recover-workspace",
1207
+ fromGenesis: args.fromGenesis === true,
1205
1208
  });
1206
1209
 
1207
1210
  printJson({
@@ -2861,6 +2864,13 @@ async function handleJoinChannel({ args, network, provider, rpcUrl }) {
2861
2864
  );
2862
2865
  status = "joined";
2863
2866
 
2867
+ await refreshPersistedWorkspaceAfterLocalTransaction({
2868
+ context,
2869
+ provider,
2870
+ receipt,
2871
+ progressAction: "channel join",
2872
+ });
2873
+
2864
2874
  const walletContext = ensureWallet({
2865
2875
  channelContext: context,
2866
2876
  signerAddress: signer.address,
@@ -3718,6 +3728,7 @@ async function recoverWalletReceivedNotes({
3718
3728
  signer,
3719
3729
  noteReceiveKeyMaterial = null,
3720
3730
  progressAction = null,
3731
+ fromGenesis = false,
3721
3732
  }) {
3722
3733
  const resolvedNoteReceiveKeyMaterial = noteReceiveKeyMaterial ?? await deriveNoteReceiveKeyMaterial({
3723
3734
  signer,
@@ -3732,6 +3743,7 @@ async function recoverWalletReceivedNotes({
3732
3743
  provider,
3733
3744
  noteReceivePrivateKey: resolvedNoteReceiveKeyMaterial.privateKey,
3734
3745
  progressAction,
3746
+ fromGenesis,
3735
3747
  });
3736
3748
  return {
3737
3749
  noteReceiveKeyMaterial: resolvedNoteReceiveKeyMaterial,
@@ -3745,13 +3757,16 @@ async function recoverDeliveredNotesFromEventLogs({
3745
3757
  provider,
3746
3758
  noteReceivePrivateKey,
3747
3759
  progressAction = null,
3760
+ fromGenesis = false,
3748
3761
  }) {
3749
3762
  const latestBlock = await provider.getBlockNumber();
3750
- const scanStartBlock = requireUsableWalletNoteReceiveRecoveryIndex({
3751
- walletContext,
3752
- context,
3753
- latestBlock,
3754
- });
3763
+ const scanStartBlock = fromGenesis
3764
+ ? Number(context.workspace.genesisBlockNumber)
3765
+ : requireUsableWalletNoteReceiveRecoveryIndex({
3766
+ walletContext,
3767
+ context,
3768
+ latestBlock,
3769
+ });
3755
3770
  const scanRange = {
3756
3771
  fromBlock: scanStartBlock,
3757
3772
  toBlock: latestBlock,
@@ -4695,13 +4710,16 @@ async function loadJoinChannelContext({ args, network, provider }) {
4695
4710
  network: { chainId, name: resolvedNetworkName },
4696
4711
  provider,
4697
4712
  bridgeResources,
4698
- persist: false,
4713
+ persist: true,
4714
+ allowExistingWorkspaceSync: true,
4715
+ useWorkspaceRecoveryIndex: true,
4716
+ progressAction: "channel join",
4699
4717
  });
4700
4718
 
4701
4719
  return {
4702
4720
  workspaceName: channelName,
4703
- workspaceDir: null,
4704
- persistChannelWorkspace: false,
4721
+ workspaceDir: initialized.workspaceDir,
4722
+ persistChannelWorkspace: true,
4705
4723
  workspace: initialized.workspace,
4706
4724
  bridgeAbiManifest: bridgeResources.bridgeAbiManifest,
4707
4725
  currentSnapshot: initialized.currentSnapshot,