@tokamak-private-dapps/private-state-cli 2.1.2 → 2.2.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 +10 -0
- package/README.md +46 -16
- package/commands/account.mjs +3 -7
- package/commands/channel.mjs +7 -15
- package/commands/notes.mjs +4 -9
- package/commands/wallet.mjs +5 -11
- package/lib/private-state-cli-command-registry.mjs +40 -7
- package/lib/private-state-runtime-management.mjs +294 -25
- package/lib/runtime.mjs +104 -63
- package/package.json +1 -1
package/lib/runtime.mjs
CHANGED
|
@@ -82,9 +82,12 @@ import {
|
|
|
82
82
|
installPrivateStateCliArtifacts,
|
|
83
83
|
installTokamakCliRuntimeForPrivateState,
|
|
84
84
|
inspectGroth16Runtime,
|
|
85
|
+
normalizeInstallMode,
|
|
85
86
|
parseJsonReport,
|
|
86
87
|
printDoctorHumanReport,
|
|
88
|
+
privateStateCliArtifactRequiredFiles,
|
|
87
89
|
privateStateCliArtifactPaths,
|
|
90
|
+
PRIVATE_STATE_INSTALL_MODES,
|
|
88
91
|
readTokamakCliPackageReport,
|
|
89
92
|
requireActiveTokamakCliRuntimeRoot,
|
|
90
93
|
resolveActiveGroth16ProverRuntime,
|
|
@@ -99,6 +102,7 @@ import {
|
|
|
99
102
|
PRIVATE_STATE_CLI_COMMANDS,
|
|
100
103
|
PRIVATE_STATE_CLI_FIELD_CATALOG,
|
|
101
104
|
privateStateCliCommandDisplay,
|
|
105
|
+
privateStateCliCommandInstallMode,
|
|
102
106
|
privateStateCliCommandOptionKeys,
|
|
103
107
|
privateStateCliCommandRequiredOptionKeys,
|
|
104
108
|
privateStateCliCommandSynopsis,
|
|
@@ -299,7 +303,7 @@ const ACTION_IMPACT_SUMMARIES = Object.freeze({
|
|
|
299
303
|
"No private note owner, value, salt, counterparty, or note provenance is created by this action.",
|
|
300
304
|
],
|
|
301
305
|
noteProvenance: "Not applicable for this bridge-edge action.",
|
|
302
|
-
|
|
306
|
+
exchangeControlledAddressWarning: "Do not use an exchange-controlled address as a self-custody bridge source.",
|
|
303
307
|
policy: "No channel policy is accepted by this action.",
|
|
304
308
|
},
|
|
305
309
|
"account-withdraw-bridge": {
|
|
@@ -316,7 +320,7 @@ const ACTION_IMPACT_SUMMARIES = Object.freeze({
|
|
|
316
320
|
"The private note path that produced any prior channel balance is not reconstructed from this event alone.",
|
|
317
321
|
],
|
|
318
322
|
noteProvenance: "Public observers cannot reconstruct prior internal note provenance from this withdrawal alone.",
|
|
319
|
-
|
|
323
|
+
exchangeControlledAddressWarning: "Do not use an exchange deposit address as the direct bridge withdrawal target unless the user has explicitly accepted the compliance implications. Prefer a self-custody L1 wallet.",
|
|
320
324
|
policy: "No channel policy is accepted by this action.",
|
|
321
325
|
},
|
|
322
326
|
"channel-join": {
|
|
@@ -472,8 +476,8 @@ function printActionImpactSummary(summary, details) {
|
|
|
472
476
|
`- Secret recovery: Losing wallet secrets, viewing keys, or spending keys can prevent note discovery or note use. The CLI cannot recover lost secrets.`,
|
|
473
477
|
`- Channel policy: ${summary.policy}`,
|
|
474
478
|
];
|
|
475
|
-
if (summary.
|
|
476
|
-
lines.push(`-
|
|
479
|
+
if (summary.exchangeControlledAddressWarning) {
|
|
480
|
+
lines.push(`- Exchange-controlled address warning: ${summary.exchangeControlledAddressWarning}`);
|
|
477
481
|
}
|
|
478
482
|
lines.push(`- Confirmation: pass --acknowledge-action-impact or type the exact confirmation phrase when prompted.`);
|
|
479
483
|
console.error(lines.join("\n"));
|
|
@@ -509,22 +513,36 @@ function normalizeDAppPolicySnapshot({
|
|
|
509
513
|
};
|
|
510
514
|
}
|
|
511
515
|
|
|
512
|
-
|
|
516
|
+
function prepareDeploymentArtifacts(chainId, { mode = PRIVATE_STATE_INSTALL_MODES.FULL } = {}) {
|
|
513
517
|
const normalizedChainId = Number(chainId);
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
518
|
+
const normalizedMode = normalizeInstallMode(mode);
|
|
519
|
+
const existingEntry = flatDeploymentArtifactPathsByChainId.get(normalizedChainId);
|
|
520
|
+
if (existingEntry?.preparedModes.has(normalizedMode)) {
|
|
521
|
+
return existingEntry.paths.rootDir;
|
|
517
522
|
}
|
|
518
523
|
|
|
519
524
|
const cacheBaseRoot = resolveArtifactCacheBaseRoot();
|
|
520
|
-
const artifactPaths = privateStateCliArtifactPaths(cacheBaseRoot, normalizedChainId);
|
|
521
|
-
requireInstalledDeploymentArtifacts(artifactPaths, normalizedChainId);
|
|
522
|
-
|
|
525
|
+
const artifactPaths = existingEntry?.paths ?? privateStateCliArtifactPaths(cacheBaseRoot, normalizedChainId);
|
|
526
|
+
requireInstalledDeploymentArtifacts(artifactPaths, normalizedChainId, normalizedMode);
|
|
527
|
+
const preparedModes = existingEntry?.preparedModes ?? new Set();
|
|
528
|
+
preparedModes.add(normalizedMode);
|
|
529
|
+
flatDeploymentArtifactPathsByChainId.set(normalizedChainId, {
|
|
530
|
+
paths: artifactPaths,
|
|
531
|
+
preparedModes,
|
|
532
|
+
});
|
|
523
533
|
return artifactPaths.rootDir;
|
|
524
534
|
}
|
|
525
535
|
|
|
536
|
+
function prepareDeploymentArtifactsForCommand(commandId, chainId) {
|
|
537
|
+
const command = PRIVATE_STATE_CLI_COMMANDS.find((entry) => entry.id === commandId);
|
|
538
|
+
expect(command, `Missing CLI command metadata for ${commandId}.`);
|
|
539
|
+
const mode = privateStateCliCommandInstallMode(command);
|
|
540
|
+
expect(mode !== "none", `${privateStateCliCommandDisplay(command)} does not require installed deployment artifacts.`);
|
|
541
|
+
return prepareDeploymentArtifacts(chainId, { mode });
|
|
542
|
+
}
|
|
543
|
+
|
|
526
544
|
function flatDeploymentArtifactPathsForChainId(chainId) {
|
|
527
|
-
return flatDeploymentArtifactPathsByChainId.get(Number(chainId)) ?? null;
|
|
545
|
+
return flatDeploymentArtifactPathsByChainId.get(Number(chainId))?.paths ?? null;
|
|
528
546
|
}
|
|
529
547
|
|
|
530
548
|
function requireFlatDeploymentArtifactPathsForChainId(chainId) {
|
|
@@ -535,29 +553,22 @@ function requireFlatDeploymentArtifactPathsForChainId(chainId) {
|
|
|
535
553
|
return paths;
|
|
536
554
|
}
|
|
537
555
|
|
|
538
|
-
function requireInstalledDeploymentArtifacts(artifactPaths, chainId) {
|
|
539
|
-
const requiredFiles =
|
|
540
|
-
artifactPaths.bridgeDeploymentPath,
|
|
541
|
-
artifactPaths.bridgeAbiManifestPath,
|
|
542
|
-
artifactPaths.grothManifestPath,
|
|
543
|
-
artifactPaths.grothZkeyPath,
|
|
544
|
-
artifactPaths.dappDeploymentPath,
|
|
545
|
-
artifactPaths.dappStorageLayoutPath,
|
|
546
|
-
artifactPaths.privateStateControllerAbiPath,
|
|
547
|
-
artifactPaths.dappRegistrationPath,
|
|
548
|
-
];
|
|
556
|
+
function requireInstalledDeploymentArtifacts(artifactPaths, chainId, mode) {
|
|
557
|
+
const requiredFiles = privateStateCliArtifactRequiredFiles(artifactPaths, mode);
|
|
549
558
|
try {
|
|
550
|
-
for (const
|
|
551
|
-
if (!fs.existsSync(
|
|
552
|
-
throw new Error(`Missing ${
|
|
559
|
+
for (const entry of requiredFiles) {
|
|
560
|
+
if (!fs.existsSync(entry.path)) {
|
|
561
|
+
throw new Error(`Missing ${entry.label}: ${entry.path}.`);
|
|
553
562
|
}
|
|
554
563
|
}
|
|
555
564
|
} catch (error) {
|
|
556
565
|
throw cliError(
|
|
557
566
|
CLI_ERROR_CODES.MISSING_DEPLOYMENT_ARTIFACTS,
|
|
558
567
|
[
|
|
559
|
-
`Missing installed deployment artifacts for chain ${chainId} under ${artifactPaths.rootDir}.`,
|
|
560
|
-
|
|
568
|
+
`Missing ${mode} installed deployment artifacts for chain ${chainId} under ${artifactPaths.rootDir}.`,
|
|
569
|
+
mode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
570
|
+
? "Run install before running private-state CLI commands that write channel state."
|
|
571
|
+
: "Run install --read-only before running private-state CLI commands that read channel state.",
|
|
561
572
|
`Original error: ${error.message}`,
|
|
562
573
|
].join(" "),
|
|
563
574
|
);
|
|
@@ -2450,22 +2461,33 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
|
|
|
2450
2461
|
}
|
|
2451
2462
|
|
|
2452
2463
|
async function handleInstallZkEvm({ args }) {
|
|
2453
|
-
const
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2464
|
+
const installMode = args.readOnly === true
|
|
2465
|
+
? PRIVATE_STATE_INSTALL_MODES.READ_ONLY
|
|
2466
|
+
: PRIVATE_STATE_INSTALL_MODES.FULL;
|
|
2467
|
+
const selectedVersions = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2468
|
+
? await resolvePrivateStateInstallRuntimeVersions(args)
|
|
2469
|
+
: null;
|
|
2470
|
+
const tokamakCliRuntime = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2471
|
+
? await installTokamakCliRuntimeForPrivateState({
|
|
2472
|
+
version: selectedVersions.tokamak,
|
|
2473
|
+
docker: Boolean(args.docker),
|
|
2474
|
+
})
|
|
2475
|
+
: null;
|
|
2476
|
+
const groth16Runtime = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2477
|
+
? await installGroth16RuntimeForPrivateState({
|
|
2478
|
+
version: selectedVersions.groth16,
|
|
2479
|
+
docker: Boolean(args.docker),
|
|
2480
|
+
})
|
|
2481
|
+
: null;
|
|
2462
2482
|
const localDeploymentBaseRoot = args.includeLocalArtifacts ? process.cwd() : null;
|
|
2463
2483
|
const deploymentArtifacts = await installPrivateStateCliArtifacts({
|
|
2464
2484
|
dappName: PRIVATE_STATE_DAPP_LABEL,
|
|
2485
|
+
installMode,
|
|
2465
2486
|
localDeploymentBaseRoot,
|
|
2466
|
-
groth16CrsVersion: groth16Runtime
|
|
2487
|
+
groth16CrsVersion: groth16Runtime?.compatibleBackendVersion ?? null,
|
|
2467
2488
|
});
|
|
2468
2489
|
const installManifest = writePrivateStateCliInstallManifest({
|
|
2490
|
+
installMode,
|
|
2469
2491
|
dockerRequested: Boolean(args.docker),
|
|
2470
2492
|
includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
|
|
2471
2493
|
localDeploymentBaseRoot,
|
|
@@ -2476,9 +2498,10 @@ async function handleInstallZkEvm({ args }) {
|
|
|
2476
2498
|
});
|
|
2477
2499
|
printJson({
|
|
2478
2500
|
action: "install",
|
|
2501
|
+
installMode,
|
|
2479
2502
|
selectedVersions,
|
|
2480
|
-
tokamakCli: tokamakCliRuntime
|
|
2481
|
-
runtimeRoot: tokamakCliRuntime
|
|
2503
|
+
tokamakCli: tokamakCliRuntime?.entryPath ?? null,
|
|
2504
|
+
runtimeRoot: tokamakCliRuntime?.runtimeRoot ?? null,
|
|
2482
2505
|
tokamakCliRuntime,
|
|
2483
2506
|
groth16Runtime,
|
|
2484
2507
|
docker: Boolean(args.docker),
|
|
@@ -3435,15 +3458,19 @@ async function handleGuide({ args }) {
|
|
|
3435
3458
|
guide.state.deploymentArtifacts = artifactState;
|
|
3436
3459
|
guide.checks.push(guideCheck(
|
|
3437
3460
|
"installed deployment artifacts",
|
|
3438
|
-
artifactState.
|
|
3461
|
+
artifactState.readOnlyInstalled ? "ok" : "missing",
|
|
3439
3462
|
{
|
|
3440
3463
|
chainId: networkRuntime.network.chainId,
|
|
3441
3464
|
rootDir: artifactState.rootDir,
|
|
3442
|
-
missingFiles: artifactState.
|
|
3465
|
+
missingFiles: artifactState.readOnlyMissingFiles,
|
|
3466
|
+
fullMissingFiles: artifactState.fullMissingFiles,
|
|
3443
3467
|
},
|
|
3444
3468
|
));
|
|
3445
|
-
if (artifactState.
|
|
3446
|
-
flatDeploymentArtifactPathsByChainId.set(Number(networkRuntime.network.chainId),
|
|
3469
|
+
if (artifactState.readOnlyInstalled) {
|
|
3470
|
+
flatDeploymentArtifactPathsByChainId.set(Number(networkRuntime.network.chainId), {
|
|
3471
|
+
paths: artifactState.paths,
|
|
3472
|
+
preparedModes: new Set([PRIVATE_STATE_INSTALL_MODES.READ_ONLY]),
|
|
3473
|
+
});
|
|
3447
3474
|
}
|
|
3448
3475
|
|
|
3449
3476
|
const provider = networkRuntime.provider;
|
|
@@ -3452,7 +3479,7 @@ async function handleGuide({ args }) {
|
|
|
3452
3479
|
channelName: String(args.channelName),
|
|
3453
3480
|
network: networkRuntime.network,
|
|
3454
3481
|
provider,
|
|
3455
|
-
artifactsInstalled: artifactState.
|
|
3482
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3456
3483
|
});
|
|
3457
3484
|
guide.checks.push(guideCheck(
|
|
3458
3485
|
"channel",
|
|
@@ -3474,7 +3501,7 @@ async function handleGuide({ args }) {
|
|
|
3474
3501
|
networkName,
|
|
3475
3502
|
network: networkRuntime.network,
|
|
3476
3503
|
provider,
|
|
3477
|
-
artifactsInstalled: artifactState.
|
|
3504
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3478
3505
|
});
|
|
3479
3506
|
guide.checks.push(guideCheck(
|
|
3480
3507
|
"local account secret",
|
|
@@ -3493,7 +3520,7 @@ async function handleGuide({ args }) {
|
|
|
3493
3520
|
walletName: String(args.wallet),
|
|
3494
3521
|
networkName,
|
|
3495
3522
|
provider,
|
|
3496
|
-
artifactsInstalled: artifactState.
|
|
3523
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3497
3524
|
});
|
|
3498
3525
|
guide.checks.push(guideCheck(
|
|
3499
3526
|
"local wallet",
|
|
@@ -3596,21 +3623,20 @@ function inspectGuideNetworkRuntime(networkName) {
|
|
|
3596
3623
|
|
|
3597
3624
|
function inspectGuideDeploymentArtifacts(chainId) {
|
|
3598
3625
|
const paths = privateStateCliArtifactPaths(resolveArtifactCacheBaseRoot(), chainId);
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
paths.dappStorageLayoutPath,
|
|
3606
|
-
paths.privateStateControllerAbiPath,
|
|
3607
|
-
paths.dappRegistrationPath,
|
|
3608
|
-
];
|
|
3609
|
-
const missingFiles = requiredFiles.filter((filePath) => !fs.existsSync(filePath));
|
|
3626
|
+
const readOnlyMissingFiles = privateStateCliArtifactRequiredFiles(paths, PRIVATE_STATE_INSTALL_MODES.READ_ONLY)
|
|
3627
|
+
.map((entry) => entry.path)
|
|
3628
|
+
.filter((filePath) => !fs.existsSync(filePath));
|
|
3629
|
+
const fullMissingFiles = privateStateCliArtifactRequiredFiles(paths, PRIVATE_STATE_INSTALL_MODES.FULL)
|
|
3630
|
+
.map((entry) => entry.path)
|
|
3631
|
+
.filter((filePath) => !fs.existsSync(filePath));
|
|
3610
3632
|
return {
|
|
3611
|
-
installed:
|
|
3633
|
+
installed: readOnlyMissingFiles.length === 0,
|
|
3634
|
+
readOnlyInstalled: readOnlyMissingFiles.length === 0,
|
|
3635
|
+
fullInstalled: fullMissingFiles.length === 0,
|
|
3612
3636
|
rootDir: paths.rootDir,
|
|
3613
|
-
missingFiles,
|
|
3637
|
+
missingFiles: readOnlyMissingFiles,
|
|
3638
|
+
readOnlyMissingFiles,
|
|
3639
|
+
fullMissingFiles,
|
|
3614
3640
|
paths,
|
|
3615
3641
|
};
|
|
3616
3642
|
}
|
|
@@ -9976,6 +10002,20 @@ function assertWalletChannelMoveArgs(args, commandName) {
|
|
|
9976
10002
|
|
|
9977
10003
|
function assertInstallZkEvmArgs(args) {
|
|
9978
10004
|
assertAllowedCommandSchema(args, "install");
|
|
10005
|
+
if (args.readOnly !== undefined && args.readOnly !== true) {
|
|
10006
|
+
throw new Error("install option --read-only does not accept a value.");
|
|
10007
|
+
}
|
|
10008
|
+
if (args.readOnly === true && args.docker !== undefined) {
|
|
10009
|
+
throw new Error("install --read-only does not accept --docker because proof runtimes are not installed.");
|
|
10010
|
+
}
|
|
10011
|
+
if (args.readOnly === true && args.groth16CliVersion !== undefined) {
|
|
10012
|
+
throw new Error("install --read-only does not accept --groth16-cli-version because Groth16 is not installed.");
|
|
10013
|
+
}
|
|
10014
|
+
if (args.readOnly === true && args.tokamakZkEvmCliVersion !== undefined) {
|
|
10015
|
+
throw new Error(
|
|
10016
|
+
"install --read-only does not accept --tokamak-zk-evm-cli-version because Tokamak zk-EVM is not installed.",
|
|
10017
|
+
);
|
|
10018
|
+
}
|
|
9979
10019
|
if (args.groth16CliVersion !== undefined) {
|
|
9980
10020
|
requireSemverVersion(args.groth16CliVersion, "--groth16-cli-version");
|
|
9981
10021
|
}
|
|
@@ -10919,7 +10959,7 @@ function ensureDir(dirPath) {
|
|
|
10919
10959
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
10920
10960
|
}
|
|
10921
10961
|
|
|
10922
|
-
function loadExplicitCommandRuntime(args, { staticNetwork = false } = {}) {
|
|
10962
|
+
function loadExplicitCommandRuntime(args, { staticNetwork = false, prepareArtifacts = false } = {}) {
|
|
10923
10963
|
const networkName = requireNetworkName(args);
|
|
10924
10964
|
const network = {
|
|
10925
10965
|
...resolveCliNetwork(networkName),
|
|
@@ -10930,6 +10970,7 @@ function loadExplicitCommandRuntime(args, { staticNetwork = false } = {}) {
|
|
|
10930
10970
|
const provider = staticNetwork
|
|
10931
10971
|
? new JsonRpcProvider(rpcConfig.rpcUrl, Number(network.chainId), { staticNetwork: true })
|
|
10932
10972
|
: new JsonRpcProvider(rpcConfig.rpcUrl);
|
|
10973
|
+
if (prepareArtifacts) prepareDeploymentArtifactsForCommand(args.command, network.chainId);
|
|
10933
10974
|
return {
|
|
10934
10975
|
network,
|
|
10935
10976
|
rpcUrl: rpcConfig.rpcUrl,
|
|
@@ -10950,7 +10991,7 @@ async function assertProviderChainIdMatchesNetwork({ provider, network, rpcUrl }
|
|
|
10950
10991
|
);
|
|
10951
10992
|
}
|
|
10952
10993
|
|
|
10953
|
-
function loadWalletCommandRuntime(args) {
|
|
10994
|
+
function loadWalletCommandRuntime(args, { prepareArtifacts = false } = {}) {
|
|
10954
10995
|
const networkName = requireNetworkName(args);
|
|
10955
10996
|
loadWalletMetadata(requireWalletName(args), networkName);
|
|
10956
10997
|
const network = {
|
|
@@ -10959,6 +11000,7 @@ function loadWalletCommandRuntime(args) {
|
|
|
10959
11000
|
};
|
|
10960
11001
|
const rpcConfig = resolveCommandRpcConfig(args);
|
|
10961
11002
|
setActiveRpcLogConfig(rpcConfig);
|
|
11003
|
+
if (prepareArtifacts) prepareDeploymentArtifactsForCommand(args.command, network.chainId);
|
|
10962
11004
|
return {
|
|
10963
11005
|
network,
|
|
10964
11006
|
rpcConfig,
|
|
@@ -11525,7 +11567,6 @@ export {
|
|
|
11525
11567
|
handleJoinChannel,
|
|
11526
11568
|
loadExplicitCommandRuntime,
|
|
11527
11569
|
loadWalletCommandRuntime,
|
|
11528
|
-
prepareDeploymentArtifacts,
|
|
11529
11570
|
assertProviderChainIdMatchesNetwork,
|
|
11530
11571
|
formatCliErrorForDisplay,
|
|
11531
11572
|
};
|
package/package.json
CHANGED