@tokamak-private-dapps/private-state-cli 2.1.2 → 2.2.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 +16 -0
- package/README.md +52 -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 +51 -10
- package/lib/private-state-runtime-management.mjs +299 -35
- package/lib/runtime.mjs +357 -121
- package/package.json +1 -1
package/lib/runtime.mjs
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
deriveChannelTokenVaultLeafIndex,
|
|
53
53
|
deriveLiquidBalanceStorageKey,
|
|
54
54
|
fetchContractCodes,
|
|
55
|
+
getBlockInfoAt,
|
|
55
56
|
normalizeBytesHex,
|
|
56
57
|
normalizeBytes32Hex,
|
|
57
58
|
serializeBigInts,
|
|
@@ -82,9 +83,12 @@ import {
|
|
|
82
83
|
installPrivateStateCliArtifacts,
|
|
83
84
|
installTokamakCliRuntimeForPrivateState,
|
|
84
85
|
inspectGroth16Runtime,
|
|
86
|
+
normalizeInstallMode,
|
|
85
87
|
parseJsonReport,
|
|
86
88
|
printDoctorHumanReport,
|
|
89
|
+
privateStateCliArtifactRequiredFiles,
|
|
87
90
|
privateStateCliArtifactPaths,
|
|
91
|
+
PRIVATE_STATE_INSTALL_MODES,
|
|
88
92
|
readTokamakCliPackageReport,
|
|
89
93
|
requireActiveTokamakCliRuntimeRoot,
|
|
90
94
|
resolveActiveGroth16ProverRuntime,
|
|
@@ -99,6 +103,7 @@ import {
|
|
|
99
103
|
PRIVATE_STATE_CLI_COMMANDS,
|
|
100
104
|
PRIVATE_STATE_CLI_FIELD_CATALOG,
|
|
101
105
|
privateStateCliCommandDisplay,
|
|
106
|
+
privateStateCliCommandInstallMode,
|
|
102
107
|
privateStateCliCommandOptionKeys,
|
|
103
108
|
privateStateCliCommandRequiredOptionKeys,
|
|
104
109
|
privateStateCliCommandSynopsis,
|
|
@@ -299,7 +304,7 @@ const ACTION_IMPACT_SUMMARIES = Object.freeze({
|
|
|
299
304
|
"No private note owner, value, salt, counterparty, or note provenance is created by this action.",
|
|
300
305
|
],
|
|
301
306
|
noteProvenance: "Not applicable for this bridge-edge action.",
|
|
302
|
-
|
|
307
|
+
exchangeControlledAddressWarning: "Do not use an exchange-controlled address as a self-custody bridge source.",
|
|
303
308
|
policy: "No channel policy is accepted by this action.",
|
|
304
309
|
},
|
|
305
310
|
"account-withdraw-bridge": {
|
|
@@ -316,7 +321,7 @@ const ACTION_IMPACT_SUMMARIES = Object.freeze({
|
|
|
316
321
|
"The private note path that produced any prior channel balance is not reconstructed from this event alone.",
|
|
317
322
|
],
|
|
318
323
|
noteProvenance: "Public observers cannot reconstruct prior internal note provenance from this withdrawal alone.",
|
|
319
|
-
|
|
324
|
+
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
325
|
policy: "No channel policy is accepted by this action.",
|
|
321
326
|
},
|
|
322
327
|
"channel-join": {
|
|
@@ -472,8 +477,8 @@ function printActionImpactSummary(summary, details) {
|
|
|
472
477
|
`- Secret recovery: Losing wallet secrets, viewing keys, or spending keys can prevent note discovery or note use. The CLI cannot recover lost secrets.`,
|
|
473
478
|
`- Channel policy: ${summary.policy}`,
|
|
474
479
|
];
|
|
475
|
-
if (summary.
|
|
476
|
-
lines.push(`-
|
|
480
|
+
if (summary.exchangeControlledAddressWarning) {
|
|
481
|
+
lines.push(`- Exchange-controlled address warning: ${summary.exchangeControlledAddressWarning}`);
|
|
477
482
|
}
|
|
478
483
|
lines.push(`- Confirmation: pass --acknowledge-action-impact or type the exact confirmation phrase when prompted.`);
|
|
479
484
|
console.error(lines.join("\n"));
|
|
@@ -509,22 +514,36 @@ function normalizeDAppPolicySnapshot({
|
|
|
509
514
|
};
|
|
510
515
|
}
|
|
511
516
|
|
|
512
|
-
|
|
517
|
+
function prepareDeploymentArtifacts(chainId, { mode = PRIVATE_STATE_INSTALL_MODES.FULL } = {}) {
|
|
513
518
|
const normalizedChainId = Number(chainId);
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
519
|
+
const normalizedMode = normalizeInstallMode(mode);
|
|
520
|
+
const existingEntry = flatDeploymentArtifactPathsByChainId.get(normalizedChainId);
|
|
521
|
+
if (existingEntry?.preparedModes.has(normalizedMode)) {
|
|
522
|
+
return existingEntry.paths.rootDir;
|
|
517
523
|
}
|
|
518
524
|
|
|
519
525
|
const cacheBaseRoot = resolveArtifactCacheBaseRoot();
|
|
520
|
-
const artifactPaths = privateStateCliArtifactPaths(cacheBaseRoot, normalizedChainId);
|
|
521
|
-
requireInstalledDeploymentArtifacts(artifactPaths, normalizedChainId);
|
|
522
|
-
|
|
526
|
+
const artifactPaths = existingEntry?.paths ?? privateStateCliArtifactPaths(cacheBaseRoot, normalizedChainId);
|
|
527
|
+
requireInstalledDeploymentArtifacts(artifactPaths, normalizedChainId, normalizedMode);
|
|
528
|
+
const preparedModes = existingEntry?.preparedModes ?? new Set();
|
|
529
|
+
preparedModes.add(normalizedMode);
|
|
530
|
+
flatDeploymentArtifactPathsByChainId.set(normalizedChainId, {
|
|
531
|
+
paths: artifactPaths,
|
|
532
|
+
preparedModes,
|
|
533
|
+
});
|
|
523
534
|
return artifactPaths.rootDir;
|
|
524
535
|
}
|
|
525
536
|
|
|
537
|
+
function prepareDeploymentArtifactsForCommand(commandId, chainId) {
|
|
538
|
+
const command = PRIVATE_STATE_CLI_COMMANDS.find((entry) => entry.id === commandId);
|
|
539
|
+
expect(command, `Missing CLI command metadata for ${commandId}.`);
|
|
540
|
+
const mode = privateStateCliCommandInstallMode(command);
|
|
541
|
+
expect(mode !== "none", `${privateStateCliCommandDisplay(command)} does not require installed deployment artifacts.`);
|
|
542
|
+
return prepareDeploymentArtifacts(chainId, { mode });
|
|
543
|
+
}
|
|
544
|
+
|
|
526
545
|
function flatDeploymentArtifactPathsForChainId(chainId) {
|
|
527
|
-
return flatDeploymentArtifactPathsByChainId.get(Number(chainId)) ?? null;
|
|
546
|
+
return flatDeploymentArtifactPathsByChainId.get(Number(chainId))?.paths ?? null;
|
|
528
547
|
}
|
|
529
548
|
|
|
530
549
|
function requireFlatDeploymentArtifactPathsForChainId(chainId) {
|
|
@@ -535,33 +554,26 @@ function requireFlatDeploymentArtifactPathsForChainId(chainId) {
|
|
|
535
554
|
return paths;
|
|
536
555
|
}
|
|
537
556
|
|
|
538
|
-
function requireInstalledDeploymentArtifacts(artifactPaths, chainId) {
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
artifactPaths.grothManifestPath,
|
|
543
|
-
artifactPaths.grothZkeyPath,
|
|
544
|
-
artifactPaths.dappDeploymentPath,
|
|
545
|
-
artifactPaths.dappStorageLayoutPath,
|
|
546
|
-
artifactPaths.privateStateControllerAbiPath,
|
|
547
|
-
artifactPaths.dappRegistrationPath,
|
|
548
|
-
];
|
|
549
|
-
try {
|
|
550
|
-
for (const filePath of requiredFiles) {
|
|
551
|
-
if (!fs.existsSync(filePath)) {
|
|
552
|
-
throw new Error(`Missing ${filePath}.`);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
} catch (error) {
|
|
556
|
-
throw cliError(
|
|
557
|
-
CLI_ERROR_CODES.MISSING_DEPLOYMENT_ARTIFACTS,
|
|
558
|
-
[
|
|
559
|
-
`Missing installed deployment artifacts for chain ${chainId} under ${artifactPaths.rootDir}.`,
|
|
560
|
-
"Run install before running private-state CLI commands for this network.",
|
|
561
|
-
`Original error: ${error.message}`,
|
|
562
|
-
].join(" "),
|
|
563
|
-
);
|
|
557
|
+
function requireInstalledDeploymentArtifacts(artifactPaths, chainId, mode) {
|
|
558
|
+
const missingFiles = missingInstalledDeploymentArtifactFiles(artifactPaths, mode);
|
|
559
|
+
if (missingFiles.length === 0) {
|
|
560
|
+
return;
|
|
564
561
|
}
|
|
562
|
+
throw cliError(
|
|
563
|
+
CLI_ERROR_CODES.MISSING_DEPLOYMENT_ARTIFACTS,
|
|
564
|
+
[
|
|
565
|
+
`Missing ${mode} installed deployment artifacts for chain ${chainId} under ${artifactPaths.rootDir}.`,
|
|
566
|
+
mode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
567
|
+
? "Run install before running private-state CLI commands that write channel state."
|
|
568
|
+
: "Run install --read-only before running private-state CLI commands that read channel state.",
|
|
569
|
+
`Original error: ${missingFiles.map((entry) => `Missing ${entry.label}: ${entry.path}.`).join(" ")}`,
|
|
570
|
+
].join(" "),
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function missingInstalledDeploymentArtifactFiles(artifactPaths, mode) {
|
|
575
|
+
return privateStateCliArtifactRequiredFiles(artifactPaths, mode)
|
|
576
|
+
.filter((entry) => !fs.existsSync(entry.path));
|
|
565
577
|
}
|
|
566
578
|
|
|
567
579
|
async function handleChannelCreate({ args, network, provider }) {
|
|
@@ -710,12 +722,14 @@ async function handleWorkspaceInit({ args, network, provider }) {
|
|
|
710
722
|
const workspaceName = channelName;
|
|
711
723
|
const bridgeResources = loadBridgeResources({ chainId: network.chainId });
|
|
712
724
|
const recoverySource = resolveWorkspaceRecoverySource(args);
|
|
725
|
+
const outputRawRpcCallHistory = args.outputRaw === true;
|
|
713
726
|
|
|
714
727
|
const {
|
|
715
728
|
workspaceDir,
|
|
716
729
|
workspace,
|
|
717
730
|
currentSnapshot,
|
|
718
731
|
cleanRebuildBackup,
|
|
732
|
+
rpcCallHistory,
|
|
719
733
|
} = await syncChannelWorkspace({
|
|
720
734
|
workspaceName,
|
|
721
735
|
channelName,
|
|
@@ -727,6 +741,7 @@ async function handleWorkspaceInit({ args, network, provider }) {
|
|
|
727
741
|
useWorkspaceRecoveryIndex: true,
|
|
728
742
|
fromGenesis: args.fromGenesis === true,
|
|
729
743
|
recoverySource,
|
|
744
|
+
outputRawRpcCallHistory,
|
|
730
745
|
progressAction: "channel recover-workspace",
|
|
731
746
|
});
|
|
732
747
|
|
|
@@ -746,6 +761,7 @@ async function handleWorkspaceInit({ args, network, provider }) {
|
|
|
746
761
|
recoveryLastScannedBlock: workspace.recoveryLastScannedBlock,
|
|
747
762
|
recoveryRootVectorHash: workspace.recoveryRootVectorHash,
|
|
748
763
|
recoveryScanRange: workspace.recoveryScanRange,
|
|
764
|
+
rpcCallHistory,
|
|
749
765
|
workspaceMirror: workspace.workspaceMirror ?? null,
|
|
750
766
|
});
|
|
751
767
|
}
|
|
@@ -1957,6 +1973,7 @@ async function syncChannelWorkspace({
|
|
|
1957
1973
|
useWorkspaceRecoveryIndex = false,
|
|
1958
1974
|
fromGenesis = false,
|
|
1959
1975
|
recoverySource = "rpc",
|
|
1976
|
+
outputRawRpcCallHistory = false,
|
|
1960
1977
|
minimumToBlock = null,
|
|
1961
1978
|
progressAction = null,
|
|
1962
1979
|
}) {
|
|
@@ -1982,8 +1999,15 @@ async function syncChannelWorkspace({
|
|
|
1982
1999
|
});
|
|
1983
2000
|
}
|
|
1984
2001
|
|
|
2002
|
+
const rpcCallHistoryRecorder = outputRawRpcCallHistory
|
|
2003
|
+
? createRpcCallHistoryRecorder({ workspaceDir })
|
|
2004
|
+
: null;
|
|
2005
|
+
const activeProvider = rpcCallHistoryRecorder
|
|
2006
|
+
? attachRpcCallHistoryRecorderToProvider(provider, rpcCallHistoryRecorder)
|
|
2007
|
+
: provider;
|
|
2008
|
+
|
|
1985
2009
|
const { bridgeDeployment, bridgeAbiManifest } = bridgeResources;
|
|
1986
|
-
const bridgeCore = new Contract(bridgeDeployment.bridgeCore, bridgeAbiManifest.contracts.bridgeCore.abi,
|
|
2010
|
+
const bridgeCore = new Contract(bridgeDeployment.bridgeCore, bridgeAbiManifest.contracts.bridgeCore.abi, activeProvider);
|
|
1987
2011
|
const channelId = deriveChannelIdFromName(channelName);
|
|
1988
2012
|
const channelInfo = await bridgeCore.getChannel(channelId);
|
|
1989
2013
|
if (!channelInfo.exists) {
|
|
@@ -1993,13 +2017,13 @@ async function syncChannelWorkspace({
|
|
|
1993
2017
|
const channelManager = new Contract(
|
|
1994
2018
|
channelInfo.manager,
|
|
1995
2019
|
bridgeAbiManifest.contracts.channelManager.abi,
|
|
1996
|
-
|
|
2020
|
+
activeProvider,
|
|
1997
2021
|
);
|
|
1998
2022
|
const canonicalAsset = getAddress(channelInfo.asset);
|
|
1999
|
-
const canonicalAssetDecimals = await fetchTokenDecimals(
|
|
2023
|
+
const canonicalAssetDecimals = await fetchTokenDecimals(activeProvider, canonicalAsset);
|
|
2000
2024
|
const currentRootVectorHash = normalizeBytes32Hex(await channelManager.currentRootVectorHash());
|
|
2001
2025
|
const genesisBlockNumber = Number(await channelManager.genesisBlockNumber());
|
|
2002
|
-
const observedLatestBlock = await
|
|
2026
|
+
const observedLatestBlock = await activeProvider.getBlockNumber();
|
|
2003
2027
|
const latestBlock = minimumToBlock === null
|
|
2004
2028
|
? observedLatestBlock
|
|
2005
2029
|
: Math.max(observedLatestBlock, Number(minimumToBlock));
|
|
@@ -2027,8 +2051,8 @@ async function syncChannelWorkspace({
|
|
|
2027
2051
|
`Managed storage vector does not include L2 accounting vault ${l2AccountingVaultAddress}.`,
|
|
2028
2052
|
);
|
|
2029
2053
|
|
|
2030
|
-
const contractCodes = await fetchContractCodes(
|
|
2031
|
-
const blockInfo = await
|
|
2054
|
+
const contractCodes = await fetchContractCodes(activeProvider, managedStorageAddresses);
|
|
2055
|
+
const blockInfo = await getBlockInfoAt(activeProvider, genesisBlockNumber);
|
|
2032
2056
|
const derivedAPubBlockHash = normalizeBytes32Hex(hashTokamakPublicInputs(encodeTokamakBlockInfo(blockInfo)));
|
|
2033
2057
|
expect(
|
|
2034
2058
|
ethers.toBigInt(derivedAPubBlockHash) === ethers.toBigInt(normalizeBytes32Hex(channelInfo.aPubBlockHash)),
|
|
@@ -2143,6 +2167,10 @@ async function syncChannelWorkspace({
|
|
|
2143
2167
|
});
|
|
2144
2168
|
}
|
|
2145
2169
|
: null;
|
|
2170
|
+
rpcCallHistoryRecorder?.setScanRange({
|
|
2171
|
+
fromBlock: selectedRecoveryIndex?.nextBlock ?? genesisBlockNumber,
|
|
2172
|
+
toBlock: latestBlock,
|
|
2173
|
+
});
|
|
2146
2174
|
const reconstruction = localSnapshotReusable
|
|
2147
2175
|
? {
|
|
2148
2176
|
currentSnapshot: existingArtifacts.stateSnapshot,
|
|
@@ -2162,7 +2190,7 @@ async function syncChannelWorkspace({
|
|
|
2162
2190
|
},
|
|
2163
2191
|
}
|
|
2164
2192
|
: await reconstructChannelSnapshot({
|
|
2165
|
-
provider,
|
|
2193
|
+
provider: activeProvider,
|
|
2166
2194
|
bridgeAbiManifest,
|
|
2167
2195
|
channelInfo,
|
|
2168
2196
|
channelManager,
|
|
@@ -2179,7 +2207,9 @@ async function syncChannelWorkspace({
|
|
|
2179
2207
|
toBlock: latestBlock,
|
|
2180
2208
|
progressAction,
|
|
2181
2209
|
onCheckpoint: persistWorkspaceCheckpoint,
|
|
2210
|
+
rpcCallHistoryRecorder,
|
|
2182
2211
|
});
|
|
2212
|
+
rpcCallHistoryRecorder?.setScanRange(reconstruction.scanRange);
|
|
2183
2213
|
const currentSnapshot = reconstruction.currentSnapshot;
|
|
2184
2214
|
const workspace = buildWorkspaceForSnapshot({
|
|
2185
2215
|
currentSnapshot,
|
|
@@ -2204,6 +2234,7 @@ async function syncChannelWorkspace({
|
|
|
2204
2234
|
blockInfo,
|
|
2205
2235
|
contractCodes,
|
|
2206
2236
|
cleanRebuildBackup,
|
|
2237
|
+
rpcCallHistory: rpcCallHistoryRecorder?.finish() ?? null,
|
|
2207
2238
|
};
|
|
2208
2239
|
}
|
|
2209
2240
|
|
|
@@ -2450,22 +2481,33 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
|
|
|
2450
2481
|
}
|
|
2451
2482
|
|
|
2452
2483
|
async function handleInstallZkEvm({ args }) {
|
|
2453
|
-
const
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2484
|
+
const installMode = args.readOnly === true
|
|
2485
|
+
? PRIVATE_STATE_INSTALL_MODES.READ_ONLY
|
|
2486
|
+
: PRIVATE_STATE_INSTALL_MODES.FULL;
|
|
2487
|
+
const selectedVersions = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2488
|
+
? await resolvePrivateStateInstallRuntimeVersions(args)
|
|
2489
|
+
: null;
|
|
2490
|
+
const tokamakCliRuntime = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2491
|
+
? await installTokamakCliRuntimeForPrivateState({
|
|
2492
|
+
version: selectedVersions.tokamak,
|
|
2493
|
+
docker: Boolean(args.docker),
|
|
2494
|
+
})
|
|
2495
|
+
: null;
|
|
2496
|
+
const groth16Runtime = installMode === PRIVATE_STATE_INSTALL_MODES.FULL
|
|
2497
|
+
? await installGroth16RuntimeForPrivateState({
|
|
2498
|
+
version: selectedVersions.groth16,
|
|
2499
|
+
docker: Boolean(args.docker),
|
|
2500
|
+
})
|
|
2501
|
+
: null;
|
|
2462
2502
|
const localDeploymentBaseRoot = args.includeLocalArtifacts ? process.cwd() : null;
|
|
2463
2503
|
const deploymentArtifacts = await installPrivateStateCliArtifacts({
|
|
2464
2504
|
dappName: PRIVATE_STATE_DAPP_LABEL,
|
|
2505
|
+
installMode,
|
|
2465
2506
|
localDeploymentBaseRoot,
|
|
2466
|
-
groth16CrsVersion: groth16Runtime
|
|
2507
|
+
groth16CrsVersion: groth16Runtime?.compatibleBackendVersion ?? null,
|
|
2467
2508
|
});
|
|
2468
2509
|
const installManifest = writePrivateStateCliInstallManifest({
|
|
2510
|
+
installMode,
|
|
2469
2511
|
dockerRequested: Boolean(args.docker),
|
|
2470
2512
|
includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
|
|
2471
2513
|
localDeploymentBaseRoot,
|
|
@@ -2476,9 +2518,10 @@ async function handleInstallZkEvm({ args }) {
|
|
|
2476
2518
|
});
|
|
2477
2519
|
printJson({
|
|
2478
2520
|
action: "install",
|
|
2521
|
+
installMode,
|
|
2479
2522
|
selectedVersions,
|
|
2480
|
-
tokamakCli: tokamakCliRuntime
|
|
2481
|
-
runtimeRoot: tokamakCliRuntime
|
|
2523
|
+
tokamakCli: tokamakCliRuntime?.entryPath ?? null,
|
|
2524
|
+
runtimeRoot: tokamakCliRuntime?.runtimeRoot ?? null,
|
|
2482
2525
|
tokamakCliRuntime,
|
|
2483
2526
|
groth16Runtime,
|
|
2484
2527
|
docker: Boolean(args.docker),
|
|
@@ -2633,6 +2676,198 @@ function persistChannelWorkspaceFiles({
|
|
|
2633
2676
|
writeJsonIfChanged(channelWorkspaceConfigPath(workspaceDir), workspace);
|
|
2634
2677
|
}
|
|
2635
2678
|
|
|
2679
|
+
function channelWorkspaceRpcCallHistoryPath(workspaceDir) {
|
|
2680
|
+
return path.join(channelDataPath(workspaceDir), "rpcCallHistory");
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
function createRpcCallHistoryRecorder({ workspaceDir }) {
|
|
2684
|
+
const historyDir = channelWorkspaceRpcCallHistoryPath(workspaceDir);
|
|
2685
|
+
const entriesByFile = new Map();
|
|
2686
|
+
let scanRange = null;
|
|
2687
|
+
let callCount = 0;
|
|
2688
|
+
ensureDir(historyDir);
|
|
2689
|
+
|
|
2690
|
+
const pushEntry = ({ method, eventName = null, entry }) => {
|
|
2691
|
+
const file = rpcCallHistoryFileName(method, eventName);
|
|
2692
|
+
const entries = entriesByFile.get(file) ?? [];
|
|
2693
|
+
entries.push({
|
|
2694
|
+
method,
|
|
2695
|
+
...(eventName ? { event: eventName } : {}),
|
|
2696
|
+
...entry,
|
|
2697
|
+
});
|
|
2698
|
+
entriesByFile.set(file, entries);
|
|
2699
|
+
};
|
|
2700
|
+
|
|
2701
|
+
return {
|
|
2702
|
+
historyDir,
|
|
2703
|
+
setScanRange(nextScanRange) {
|
|
2704
|
+
scanRange = {
|
|
2705
|
+
fromBlock: Number(nextScanRange.fromBlock),
|
|
2706
|
+
toBlock: Number(nextScanRange.toBlock),
|
|
2707
|
+
...(nextScanRange.mode ? { mode: nextScanRange.mode } : {}),
|
|
2708
|
+
};
|
|
2709
|
+
},
|
|
2710
|
+
recordRpcCall({ method, params, response, error = null }) {
|
|
2711
|
+
if (method === "eth_getLogs") {
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
callCount += 1;
|
|
2715
|
+
pushEntry({
|
|
2716
|
+
method,
|
|
2717
|
+
entry: {
|
|
2718
|
+
recordedAt: new Date().toISOString(),
|
|
2719
|
+
request: buildRawJsonRpcRequest(method, params),
|
|
2720
|
+
...(error ? { error } : { response }),
|
|
2721
|
+
},
|
|
2722
|
+
});
|
|
2723
|
+
},
|
|
2724
|
+
recordEthGetLogs({ request, logs, groupedValues, chunkFromBlock, chunkToBlock }) {
|
|
2725
|
+
callCount += 1;
|
|
2726
|
+
const eventBuckets = groupRawEthGetLogsByRecoveryEvent({ logs, groupedValues });
|
|
2727
|
+
for (const [eventName, response] of eventBuckets.entries()) {
|
|
2728
|
+
pushEntry({
|
|
2729
|
+
method: "eth_getLogs",
|
|
2730
|
+
eventName,
|
|
2731
|
+
entry: {
|
|
2732
|
+
recordedAt: new Date().toISOString(),
|
|
2733
|
+
chunkRange: { fromBlock: Number(chunkFromBlock), toBlock: Number(chunkToBlock) },
|
|
2734
|
+
request: buildRawEthGetLogsRequest(request),
|
|
2735
|
+
response,
|
|
2736
|
+
},
|
|
2737
|
+
});
|
|
2738
|
+
}
|
|
2739
|
+
},
|
|
2740
|
+
finish() {
|
|
2741
|
+
const files = [...entriesByFile.entries()].map(([file, entries]) =>
|
|
2742
|
+
appendRpcCallHistoryEntries({
|
|
2743
|
+
historyDir,
|
|
2744
|
+
file,
|
|
2745
|
+
entries: entries.map((entry) => ({ scanRange, ...entry })),
|
|
2746
|
+
}));
|
|
2747
|
+
return {
|
|
2748
|
+
historyDir,
|
|
2749
|
+
scanRange,
|
|
2750
|
+
callCount,
|
|
2751
|
+
files: files.sort((left, right) => left.file.localeCompare(right.file)),
|
|
2752
|
+
};
|
|
2753
|
+
},
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
function attachRpcCallHistoryRecorderToProvider(provider, recorder) {
|
|
2758
|
+
const send = provider.send.bind(provider);
|
|
2759
|
+
provider.send = async (method, params) => {
|
|
2760
|
+
try {
|
|
2761
|
+
const response = await send(method, params);
|
|
2762
|
+
recorder.recordRpcCall({ method, params, response });
|
|
2763
|
+
return response;
|
|
2764
|
+
} catch (error) {
|
|
2765
|
+
recorder.recordRpcCall({ method, params, error: normalizeRpcCallHistoryError(error) });
|
|
2766
|
+
throw error;
|
|
2767
|
+
}
|
|
2768
|
+
};
|
|
2769
|
+
return provider;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
function normalizeRpcCallHistoryError(error) {
|
|
2773
|
+
return {
|
|
2774
|
+
name: error?.name ?? "Error",
|
|
2775
|
+
code: error?.code ?? null,
|
|
2776
|
+
message: error?.message ?? String(error),
|
|
2777
|
+
};
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
function appendRpcCallHistoryEntries({ historyDir, file, entries }) {
|
|
2781
|
+
const filePath = path.join(historyDir, file);
|
|
2782
|
+
const { method, event: eventName = null } = entries[0];
|
|
2783
|
+
const current = readJsonIfExists(filePath) ?? {
|
|
2784
|
+
method,
|
|
2785
|
+
...(eventName ? { event: eventName } : {}),
|
|
2786
|
+
entries: [],
|
|
2787
|
+
};
|
|
2788
|
+
expect(current.method === method, `RPC call history file method mismatch: ${filePath}.`);
|
|
2789
|
+
expect(Array.isArray(current.entries), `RPC call history file entries must be an array: ${filePath}.`);
|
|
2790
|
+
if (eventName) {
|
|
2791
|
+
expect(current.event === eventName, `RPC call history file event mismatch: ${filePath}.`);
|
|
2792
|
+
}
|
|
2793
|
+
current.updatedAt = new Date().toISOString();
|
|
2794
|
+
current.entries.push(...entries);
|
|
2795
|
+
writeJson(filePath, current);
|
|
2796
|
+
return {
|
|
2797
|
+
method,
|
|
2798
|
+
...(eventName ? { event: eventName } : {}),
|
|
2799
|
+
file,
|
|
2800
|
+
path: filePath,
|
|
2801
|
+
entriesAdded: entries.length,
|
|
2802
|
+
totalEntries: current.entries.length,
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
function buildRawJsonRpcRequest(method, params = []) {
|
|
2807
|
+
return {
|
|
2808
|
+
jsonrpc: "2.0",
|
|
2809
|
+
method,
|
|
2810
|
+
params: params ?? [],
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
function rpcCallHistoryFileName(method, eventName = null) {
|
|
2815
|
+
const suffix = eventName ? `.${safeRpcCallHistoryFileToken(eventName)}` : "";
|
|
2816
|
+
return `${safeRpcCallHistoryFileToken(method)}${suffix}.json`;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
function safeRpcCallHistoryFileToken(value) {
|
|
2820
|
+
return String(value).replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
function groupRawEthGetLogsByRecoveryEvent({ logs, groupedValues }) {
|
|
2824
|
+
if (logs.length === 0) {
|
|
2825
|
+
return new Map([["noLogs", []]]);
|
|
2826
|
+
}
|
|
2827
|
+
const eventNamesByLog = new Map();
|
|
2828
|
+
for (const group of groupedValues) {
|
|
2829
|
+
for (const event of group) {
|
|
2830
|
+
eventNamesByLog.set(recoveryLogHistoryKey(event), channelRecoveryEventName(event));
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
const buckets = new Map();
|
|
2834
|
+
for (const log of logs) {
|
|
2835
|
+
const eventName = eventNamesByLog.get(recoveryLogHistoryKey(log)) ?? "unknown";
|
|
2836
|
+
const bucket = buckets.get(eventName) ?? [];
|
|
2837
|
+
bucket.push(log);
|
|
2838
|
+
buckets.set(eventName, bucket);
|
|
2839
|
+
}
|
|
2840
|
+
return buckets;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
function recoveryLogHistoryKey(log) {
|
|
2844
|
+
return `${normalizeBytes32Hex(log.transactionHash)}:${Number(log.index ?? log.logIndex)}`;
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
function channelRecoveryEventName(event) {
|
|
2848
|
+
if (event.fragment?.name) {
|
|
2849
|
+
return event.fragment.name;
|
|
2850
|
+
}
|
|
2851
|
+
const topic0 = event.topics[0] ? normalizeBytes32Hex(event.topics[0]) : null;
|
|
2852
|
+
if (topic0 === normalizeBytes32Hex(CONTROLLER_STORAGE_KEY_OBSERVED_TOPIC)) {
|
|
2853
|
+
return "StorageKeyObserved";
|
|
2854
|
+
}
|
|
2855
|
+
if (topic0 === normalizeBytes32Hex(VAULT_STORAGE_WRITE_OBSERVED_TOPIC)) {
|
|
2856
|
+
return "LiquidBalanceStorageWriteObserved";
|
|
2857
|
+
}
|
|
2858
|
+
return "unknown";
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
function buildRawEthGetLogsRequest(request) {
|
|
2862
|
+
const filter = {
|
|
2863
|
+
address: request.address,
|
|
2864
|
+
topics: request.topics,
|
|
2865
|
+
fromBlock: ethers.toQuantity(request.fromBlock),
|
|
2866
|
+
toBlock: ethers.toQuantity(request.toBlock),
|
|
2867
|
+
};
|
|
2868
|
+
return buildRawJsonRpcRequest("eth_getLogs", [filter]);
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2636
2871
|
function nextAvailablePath(basePath) {
|
|
2637
2872
|
if (!fs.existsSync(basePath)) {
|
|
2638
2873
|
return basePath;
|
|
@@ -3435,15 +3670,19 @@ async function handleGuide({ args }) {
|
|
|
3435
3670
|
guide.state.deploymentArtifacts = artifactState;
|
|
3436
3671
|
guide.checks.push(guideCheck(
|
|
3437
3672
|
"installed deployment artifacts",
|
|
3438
|
-
artifactState.
|
|
3673
|
+
artifactState.readOnlyInstalled ? "ok" : "missing",
|
|
3439
3674
|
{
|
|
3440
3675
|
chainId: networkRuntime.network.chainId,
|
|
3441
3676
|
rootDir: artifactState.rootDir,
|
|
3442
|
-
missingFiles: artifactState.
|
|
3677
|
+
missingFiles: artifactState.readOnlyMissingFiles,
|
|
3678
|
+
fullMissingFiles: artifactState.fullMissingFiles,
|
|
3443
3679
|
},
|
|
3444
3680
|
));
|
|
3445
|
-
if (artifactState.
|
|
3446
|
-
flatDeploymentArtifactPathsByChainId.set(Number(networkRuntime.network.chainId),
|
|
3681
|
+
if (artifactState.readOnlyInstalled) {
|
|
3682
|
+
flatDeploymentArtifactPathsByChainId.set(Number(networkRuntime.network.chainId), {
|
|
3683
|
+
paths: artifactState.paths,
|
|
3684
|
+
preparedModes: new Set([PRIVATE_STATE_INSTALL_MODES.READ_ONLY]),
|
|
3685
|
+
});
|
|
3447
3686
|
}
|
|
3448
3687
|
|
|
3449
3688
|
const provider = networkRuntime.provider;
|
|
@@ -3452,7 +3691,7 @@ async function handleGuide({ args }) {
|
|
|
3452
3691
|
channelName: String(args.channelName),
|
|
3453
3692
|
network: networkRuntime.network,
|
|
3454
3693
|
provider,
|
|
3455
|
-
artifactsInstalled: artifactState.
|
|
3694
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3456
3695
|
});
|
|
3457
3696
|
guide.checks.push(guideCheck(
|
|
3458
3697
|
"channel",
|
|
@@ -3474,7 +3713,7 @@ async function handleGuide({ args }) {
|
|
|
3474
3713
|
networkName,
|
|
3475
3714
|
network: networkRuntime.network,
|
|
3476
3715
|
provider,
|
|
3477
|
-
artifactsInstalled: artifactState.
|
|
3716
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3478
3717
|
});
|
|
3479
3718
|
guide.checks.push(guideCheck(
|
|
3480
3719
|
"local account secret",
|
|
@@ -3493,7 +3732,7 @@ async function handleGuide({ args }) {
|
|
|
3493
3732
|
walletName: String(args.wallet),
|
|
3494
3733
|
networkName,
|
|
3495
3734
|
provider,
|
|
3496
|
-
artifactsInstalled: artifactState.
|
|
3735
|
+
artifactsInstalled: artifactState.readOnlyInstalled,
|
|
3497
3736
|
});
|
|
3498
3737
|
guide.checks.push(guideCheck(
|
|
3499
3738
|
"local wallet",
|
|
@@ -3596,21 +3835,18 @@ function inspectGuideNetworkRuntime(networkName) {
|
|
|
3596
3835
|
|
|
3597
3836
|
function inspectGuideDeploymentArtifacts(chainId) {
|
|
3598
3837
|
const paths = privateStateCliArtifactPaths(resolveArtifactCacheBaseRoot(), chainId);
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
paths.grothZkeyPath,
|
|
3604
|
-
paths.dappDeploymentPath,
|
|
3605
|
-
paths.dappStorageLayoutPath,
|
|
3606
|
-
paths.privateStateControllerAbiPath,
|
|
3607
|
-
paths.dappRegistrationPath,
|
|
3608
|
-
];
|
|
3609
|
-
const missingFiles = requiredFiles.filter((filePath) => !fs.existsSync(filePath));
|
|
3838
|
+
const readOnlyMissingFiles = missingInstalledDeploymentArtifactFiles(paths, PRIVATE_STATE_INSTALL_MODES.READ_ONLY)
|
|
3839
|
+
.map((entry) => entry.path);
|
|
3840
|
+
const fullMissingFiles = missingInstalledDeploymentArtifactFiles(paths, PRIVATE_STATE_INSTALL_MODES.FULL)
|
|
3841
|
+
.map((entry) => entry.path);
|
|
3610
3842
|
return {
|
|
3611
|
-
installed:
|
|
3843
|
+
installed: readOnlyMissingFiles.length === 0,
|
|
3844
|
+
readOnlyInstalled: readOnlyMissingFiles.length === 0,
|
|
3845
|
+
fullInstalled: fullMissingFiles.length === 0,
|
|
3612
3846
|
rootDir: paths.rootDir,
|
|
3613
|
-
missingFiles,
|
|
3847
|
+
missingFiles: readOnlyMissingFiles,
|
|
3848
|
+
readOnlyMissingFiles,
|
|
3849
|
+
fullMissingFiles,
|
|
3614
3850
|
paths,
|
|
3615
3851
|
};
|
|
3616
3852
|
}
|
|
@@ -8411,39 +8647,6 @@ function appendSplitWord(target, startIndex, value) {
|
|
|
8411
8647
|
target[startIndex + 1] = normalized >> 128n;
|
|
8412
8648
|
}
|
|
8413
8649
|
|
|
8414
|
-
async function fetchChannelBlockInfo(provider, blockNumber) {
|
|
8415
|
-
const blockTag = ethers.toQuantity(blockNumber);
|
|
8416
|
-
const block = await provider.send("eth_getBlockByNumber", [blockTag, false]);
|
|
8417
|
-
if (!block) {
|
|
8418
|
-
throw new Error(`Unable to fetch channel genesis block ${blockNumber}.`);
|
|
8419
|
-
}
|
|
8420
|
-
|
|
8421
|
-
const prevBlockHashes = [];
|
|
8422
|
-
for (let offset = 1; offset <= TOKAMAK_PREVIOUS_BLOCK_HASH_COUNT; offset += 1) {
|
|
8423
|
-
if (blockNumber <= offset) {
|
|
8424
|
-
prevBlockHashes.push("0x0");
|
|
8425
|
-
continue;
|
|
8426
|
-
}
|
|
8427
|
-
const previousBlock = await provider.send("eth_getBlockByNumber", [ethers.toQuantity(blockNumber - offset), false]);
|
|
8428
|
-
if (!previousBlock) {
|
|
8429
|
-
throw new Error(`Unable to fetch previous block hash for block ${blockNumber - offset}.`);
|
|
8430
|
-
}
|
|
8431
|
-
prevBlockHashes.push(previousBlock.hash);
|
|
8432
|
-
}
|
|
8433
|
-
|
|
8434
|
-
return {
|
|
8435
|
-
coinBase: block.miner,
|
|
8436
|
-
timeStamp: block.timestamp,
|
|
8437
|
-
blockNumber: block.number,
|
|
8438
|
-
prevRanDao: block.prevRandao ?? block.mixHash ?? block.difficulty ?? "0x0",
|
|
8439
|
-
gasLimit: block.gasLimit,
|
|
8440
|
-
chainId: await provider.send("eth_chainId", []),
|
|
8441
|
-
selfBalance: "0x0",
|
|
8442
|
-
baseFee: block.baseFeePerGas ?? "0x0",
|
|
8443
|
-
prevBlockHashes,
|
|
8444
|
-
};
|
|
8445
|
-
}
|
|
8446
|
-
|
|
8447
8650
|
async function fetchChannelRecoveryLogs({
|
|
8448
8651
|
provider,
|
|
8449
8652
|
bridgeAbiManifest,
|
|
@@ -8484,6 +8687,7 @@ async function fetchChannelRecoveryEventGroupsChunked({
|
|
|
8484
8687
|
fromBlock,
|
|
8485
8688
|
toBlock,
|
|
8486
8689
|
progressAction = null,
|
|
8690
|
+
rpcCallHistoryRecorder = null,
|
|
8487
8691
|
onChunk,
|
|
8488
8692
|
}) {
|
|
8489
8693
|
const recoveryFilter = buildChannelRecoveryLogFilter({
|
|
@@ -8501,7 +8705,7 @@ async function fetchChannelRecoveryEventGroupsChunked({
|
|
|
8501
8705
|
onProgress: progressAction
|
|
8502
8706
|
? createRpcLogScanProgress({ action: progressAction, label: "channel-recovery chunks" })
|
|
8503
8707
|
: null,
|
|
8504
|
-
onChunk: async ({ logs, chunkFromBlock, chunkToBlock }) => {
|
|
8708
|
+
onChunk: async ({ request, logs, chunkFromBlock, chunkToBlock }) => {
|
|
8505
8709
|
const groupedValues = normalizeWorkspaceMirrorDeltaEventGroups({
|
|
8506
8710
|
logs,
|
|
8507
8711
|
channelInfo,
|
|
@@ -8509,6 +8713,13 @@ async function fetchChannelRecoveryEventGroupsChunked({
|
|
|
8509
8713
|
fromBlock: chunkFromBlock,
|
|
8510
8714
|
toBlock: chunkToBlock,
|
|
8511
8715
|
});
|
|
8716
|
+
rpcCallHistoryRecorder?.recordEthGetLogs({
|
|
8717
|
+
request,
|
|
8718
|
+
logs,
|
|
8719
|
+
groupedValues,
|
|
8720
|
+
chunkFromBlock,
|
|
8721
|
+
chunkToBlock,
|
|
8722
|
+
});
|
|
8512
8723
|
await onChunk?.({
|
|
8513
8724
|
groupedValues,
|
|
8514
8725
|
chunkFromBlock,
|
|
@@ -8565,6 +8776,7 @@ async function reconstructChannelSnapshot({
|
|
|
8565
8776
|
toBlock = null,
|
|
8566
8777
|
progressAction = null,
|
|
8567
8778
|
onCheckpoint = null,
|
|
8779
|
+
rpcCallHistoryRecorder = null,
|
|
8568
8780
|
}) {
|
|
8569
8781
|
let startingSnapshot = baseSnapshot;
|
|
8570
8782
|
if (!startingSnapshot) {
|
|
@@ -8601,6 +8813,7 @@ async function reconstructChannelSnapshot({
|
|
|
8601
8813
|
fromBlock: scanFromBlock,
|
|
8602
8814
|
toBlock: latestBlock,
|
|
8603
8815
|
progressAction,
|
|
8816
|
+
rpcCallHistoryRecorder,
|
|
8604
8817
|
onChunk: async ({ groupedValues, chunkFromBlock, chunkToBlock }) => {
|
|
8605
8818
|
currentSnapshot = await applyChannelRecoveryEventGroupsToStateManager({
|
|
8606
8819
|
stateManager,
|
|
@@ -8953,13 +9166,14 @@ async function fetchLogsChunked(provider, {
|
|
|
8953
9166
|
while (cursor <= resolvedToBlock) {
|
|
8954
9167
|
const chunkToBlock = Math.min(resolvedToBlock, cursor + chunkSize - 1);
|
|
8955
9168
|
let logs;
|
|
9169
|
+
const request = {
|
|
9170
|
+
address,
|
|
9171
|
+
topics,
|
|
9172
|
+
fromBlock: cursor,
|
|
9173
|
+
toBlock: chunkToBlock,
|
|
9174
|
+
};
|
|
8956
9175
|
try {
|
|
8957
|
-
logs = await fetchLogsRateLimited(provider,
|
|
8958
|
-
address,
|
|
8959
|
-
topics,
|
|
8960
|
-
fromBlock: cursor,
|
|
8961
|
-
toBlock: chunkToBlock,
|
|
8962
|
-
});
|
|
9176
|
+
logs = await fetchLogsRateLimited(provider, request);
|
|
8963
9177
|
} catch (error) {
|
|
8964
9178
|
throw buildRpcLogQueryConfigError({
|
|
8965
9179
|
error,
|
|
@@ -8993,6 +9207,7 @@ async function fetchLogsChunked(provider, {
|
|
|
8993
9207
|
totalBlocks,
|
|
8994
9208
|
logsFound,
|
|
8995
9209
|
chunkLogs: logs.length,
|
|
9210
|
+
request,
|
|
8996
9211
|
logs,
|
|
8997
9212
|
});
|
|
8998
9213
|
cursor = chunkToBlock + 1;
|
|
@@ -9976,6 +10191,20 @@ function assertWalletChannelMoveArgs(args, commandName) {
|
|
|
9976
10191
|
|
|
9977
10192
|
function assertInstallZkEvmArgs(args) {
|
|
9978
10193
|
assertAllowedCommandSchema(args, "install");
|
|
10194
|
+
if (args.readOnly !== undefined && args.readOnly !== true) {
|
|
10195
|
+
throw new Error("install option --read-only does not accept a value.");
|
|
10196
|
+
}
|
|
10197
|
+
if (args.readOnly === true && args.docker !== undefined) {
|
|
10198
|
+
throw new Error("install --read-only does not accept --docker because proof runtimes are not installed.");
|
|
10199
|
+
}
|
|
10200
|
+
if (args.readOnly === true && args.groth16CliVersion !== undefined) {
|
|
10201
|
+
throw new Error("install --read-only does not accept --groth16-cli-version because Groth16 is not installed.");
|
|
10202
|
+
}
|
|
10203
|
+
if (args.readOnly === true && args.tokamakZkEvmCliVersion !== undefined) {
|
|
10204
|
+
throw new Error(
|
|
10205
|
+
"install --read-only does not accept --tokamak-zk-evm-cli-version because Tokamak zk-EVM is not installed.",
|
|
10206
|
+
);
|
|
10207
|
+
}
|
|
9979
10208
|
if (args.groth16CliVersion !== undefined) {
|
|
9980
10209
|
requireSemverVersion(args.groth16CliVersion, "--groth16-cli-version");
|
|
9981
10210
|
}
|
|
@@ -10114,10 +10343,16 @@ function assertCreateChannelArgs(args) {
|
|
|
10114
10343
|
|
|
10115
10344
|
function assertRecoverWorkspaceArgs(args) {
|
|
10116
10345
|
assertAllowedCommandSchema(args, "channel-recover-workspace");
|
|
10117
|
-
resolveWorkspaceRecoverySource(args);
|
|
10346
|
+
const source = resolveWorkspaceRecoverySource(args);
|
|
10118
10347
|
if (args.fromGenesis !== undefined && args.fromGenesis !== true) {
|
|
10119
10348
|
throw new Error("channel recover-workspace option --from-genesis does not accept a value.");
|
|
10120
10349
|
}
|
|
10350
|
+
if (args.outputRaw !== undefined && args.outputRaw !== true) {
|
|
10351
|
+
throw new Error("channel recover-workspace option --output-raw does not accept a value.");
|
|
10352
|
+
}
|
|
10353
|
+
if (args.outputRaw === true && source !== "rpc") {
|
|
10354
|
+
throw new Error("channel recover-workspace option --output-raw requires --source rpc.");
|
|
10355
|
+
}
|
|
10121
10356
|
}
|
|
10122
10357
|
|
|
10123
10358
|
function assertGetChannelArgs(args) {
|
|
@@ -10919,7 +11154,7 @@ function ensureDir(dirPath) {
|
|
|
10919
11154
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
10920
11155
|
}
|
|
10921
11156
|
|
|
10922
|
-
function loadExplicitCommandRuntime(args, { staticNetwork = false } = {}) {
|
|
11157
|
+
function loadExplicitCommandRuntime(args, { staticNetwork = false, prepareArtifacts = false } = {}) {
|
|
10923
11158
|
const networkName = requireNetworkName(args);
|
|
10924
11159
|
const network = {
|
|
10925
11160
|
...resolveCliNetwork(networkName),
|
|
@@ -10930,6 +11165,7 @@ function loadExplicitCommandRuntime(args, { staticNetwork = false } = {}) {
|
|
|
10930
11165
|
const provider = staticNetwork
|
|
10931
11166
|
? new JsonRpcProvider(rpcConfig.rpcUrl, Number(network.chainId), { staticNetwork: true })
|
|
10932
11167
|
: new JsonRpcProvider(rpcConfig.rpcUrl);
|
|
11168
|
+
if (prepareArtifacts) prepareDeploymentArtifactsForCommand(args.command, network.chainId);
|
|
10933
11169
|
return {
|
|
10934
11170
|
network,
|
|
10935
11171
|
rpcUrl: rpcConfig.rpcUrl,
|
|
@@ -10950,7 +11186,7 @@ async function assertProviderChainIdMatchesNetwork({ provider, network, rpcUrl }
|
|
|
10950
11186
|
);
|
|
10951
11187
|
}
|
|
10952
11188
|
|
|
10953
|
-
function loadWalletCommandRuntime(args) {
|
|
11189
|
+
function loadWalletCommandRuntime(args, { prepareArtifacts = false } = {}) {
|
|
10954
11190
|
const networkName = requireNetworkName(args);
|
|
10955
11191
|
loadWalletMetadata(requireWalletName(args), networkName);
|
|
10956
11192
|
const network = {
|
|
@@ -10959,6 +11195,7 @@ function loadWalletCommandRuntime(args) {
|
|
|
10959
11195
|
};
|
|
10960
11196
|
const rpcConfig = resolveCommandRpcConfig(args);
|
|
10961
11197
|
setActiveRpcLogConfig(rpcConfig);
|
|
11198
|
+
if (prepareArtifacts) prepareDeploymentArtifactsForCommand(args.command, network.chainId);
|
|
10962
11199
|
return {
|
|
10963
11200
|
network,
|
|
10964
11201
|
rpcConfig,
|
|
@@ -11525,7 +11762,6 @@ export {
|
|
|
11525
11762
|
handleJoinChannel,
|
|
11526
11763
|
loadExplicitCommandRuntime,
|
|
11527
11764
|
loadWalletCommandRuntime,
|
|
11528
|
-
prepareDeploymentArtifacts,
|
|
11529
11765
|
assertProviderChainIdMatchesNetwork,
|
|
11530
11766
|
formatCliErrorForDisplay,
|
|
11531
11767
|
};
|