shinjuku-shielded 0.3.44 → 0.3.45

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/manifest.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema": "carbon-shielded-wallet/bundle-manifest/v1",
3
3
  "file": "shinjuku-wallet.mjs",
4
- "sha256": "99e5ce600a930373051d72e16b2fe75bec451cfbdd509439e58546d0e77058d2",
5
- "bytes": 11247206,
6
- "sourceCommit": "5a8c47eba8d07d89334e63f6467f17692e009d30",
4
+ "sha256": "54ae7e6525d0c2a5330f3243891a2cbc5d728a4bcea81a61ba3aaf065bed8b63",
5
+ "bytes": 11266570,
6
+ "sourceCommit": "f4f870fa4e4b3f57cc4dfdb472b75e5a3fef8db2",
7
7
  "sourceDirty": false,
8
8
  "installRecordMatchesLockfile": true,
9
9
  "releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.44",
3
+ "version": "0.3.45",
4
4
  "mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
5
5
  "description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
6
- "shinjukuRelease": "99e5ce60",
7
- "shinjukuSha256": "99e5ce600a930373051d72e16b2fe75bec451cfbdd509439e58546d0e77058d2",
6
+ "shinjukuRelease": "54ae7e65",
7
+ "shinjukuSha256": "54ae7e6525d0c2a5330f3243891a2cbc5d728a4bcea81a61ba3aaf065bed8b63",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -50887,13 +50887,15 @@ function createHistoryCacheStore({
50887
50887
  }
50888
50888
  return { ...deserialize(JSON.parse(envelope.serialized)), savedAt: Number(envelope.savedAt) };
50889
50889
  },
50890
- async save(state) {
50890
+ // `savedAt`: a rewrite that keeps the time of the refresh it holds (compact.mjs
50891
+ // dropCachedFoldRoots), so the rewrite does not make old records count as fresh.
50892
+ async save(state, { savedAt } = {}) {
50891
50893
  const serialized = JSON.stringify(serialize(state));
50892
50894
  const envelope = JSON.stringify({
50893
50895
  schema,
50894
50896
  tag: tag2(serialized),
50895
50897
  serialized,
50896
- savedAt: now()
50898
+ savedAt: Number.isFinite(savedAt) ? savedAt : now()
50897
50899
  });
50898
50900
  await mkdir(dirname6(path), { recursive: true });
50899
50901
  const tmp = `${path}.tmp-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
@@ -50977,7 +50979,11 @@ function createCompactHistoryCacheStore({ path, hmacKey, now }) {
50977
50979
  newestSignature: state.attestation.newestSignature,
50978
50980
  coverage: encodeTagged(state.attestation.coverage)
50979
50981
  }
50980
- } : {}
50982
+ } : {},
50983
+ // 2026-10-16: the append root after each served record (hex, count 1..n) and the empty
50984
+ // tree's root, a fold hint for a new process (compact.mjs hintCompactFold). Optional: an
50985
+ // older build reads the file and drops it; a file without it folds as before.
50986
+ ...state.foldRoots ? { foldRoots: { zero: state.foldRoots.zero, roots: [...state.foldRoots.roots] } } : {}
50981
50987
  }),
50982
50988
  deserialize: (value) => {
50983
50989
  const init = value?.initialization;
@@ -50998,7 +51004,9 @@ function createCompactHistoryCacheStore({ path, hmacKey, now }) {
50998
51004
  accounts: Object.freeze([...init.accounts]),
50999
51005
  data: Buffer.from(init.data, "hex")
51000
51006
  }),
51001
- ...value.attestation === void 0 ? {} : { attestation: deserializeAttestation(value.attestation) }
51007
+ ...value.attestation === void 0 ? {} : { attestation: deserializeAttestation(value.attestation) },
51008
+ // A malformed hint is dropped, never the cache: the fold then runs from the empty tree.
51009
+ ...value.foldRoots && typeof value.foldRoots.zero === "string" && Array.isArray(value.foldRoots.roots) && value.foldRoots.roots.length === value.served.records.length && value.foldRoots.roots.every((root) => typeof root === "string") ? { foldRoots: { zero: value.foldRoots.zero, roots: [...value.foldRoots.roots] } } : {}
51002
51010
  };
51003
51011
  }
51004
51012
  });
@@ -52625,6 +52633,16 @@ function vaultAuthorityAddress3(program, pool2) {
52625
52633
  function depositAuthorityAddress3(program, pool2, outHex) {
52626
52634
  return memo(`da|${b58(program)}|${b58(pool2)}|${outHex}`, () => depositAuthorityAddress2(program, pool2, outHex));
52627
52635
  }
52636
+ function keepPoolState(report, snapshot) {
52637
+ const entry = SNAPSHOT_POOL_STATES.get(snapshot);
52638
+ if (entry !== void 0 && entry.programId === report.programId && entry.pool === report.pool) REPORT_POOL_STATES.set(report, entry);
52639
+ }
52640
+ function finalizedPoolStateOf(report, { programId, pool: pool2 }) {
52641
+ if (!report || !AUTHENTICATED_HISTORY_REPORTS.has(report)) return void 0;
52642
+ const entry = REPORT_POOL_STATES.get(report);
52643
+ if (entry === void 0 || entry.programId !== String(programId) || entry.pool !== String(pool2)) return void 0;
52644
+ return entry.state;
52645
+ }
52628
52646
  function p03SettlementConsumesBuffer(tag2) {
52629
52647
  return P03_SETTLEMENT_TAGS.includes(tag2) && !P03_INLINE_SETTLEMENT_TAGS.includes(tag2);
52630
52648
  }
@@ -52790,6 +52808,7 @@ function buildFinalizedP03HistoryReport({
52790
52808
  });
52791
52809
  AUTHENTICATED_HISTORY_REPORTS.add(report);
52792
52810
  if (attestation) HISTORY_ATTESTATIONS.set(report, attestation);
52811
+ keepPoolState(report, poolSnapshot);
52793
52812
  return report;
52794
52813
  }
52795
52814
  function assertAuthenticatedFinalizedP03History(report) {
@@ -52873,12 +52892,13 @@ async function refreshFinalizedP03HistorySnapshot({
52873
52892
  });
52874
52893
  AUTHENTICATED_HISTORY_REPORTS.add(refreshed);
52875
52894
  if (refreshedCoverage.attestation) HISTORY_ATTESTATIONS.set(refreshed, refreshedCoverage.attestation);
52895
+ keepPoolState(refreshed, snapshot);
52876
52896
  return refreshed;
52877
52897
  }
52878
52898
  async function readFinalizedPool(connection, program, pool2) {
52879
52899
  if (typeof connection.getMultipleAccountsInfoAndContext !== "function") {
52880
52900
  const response = await retryTransientRpc(() => connection.getAccountInfoAndContext(pool2, "finalized"));
52881
- const only = parseFinalizedPool(response, program);
52901
+ const only = parseFinalizedPool(response, program, pool2);
52882
52902
  if (only.replayStore === REPLAY_STORE_INDEXED) throw new Error("p03_history_e1_tree_read_unavailable");
52883
52903
  return only;
52884
52904
  }
@@ -52888,10 +52908,10 @@ async function readFinalizedPool(connection, program, pool2) {
52888
52908
  { commitment: "finalized" }
52889
52909
  ));
52890
52910
  if (!Array.isArray(both?.value) || both.value.length !== 2) throw new Error("p03_history_e1_tree_read_invalid");
52891
- const snapshot = parseFinalizedPool({ context: both.context, value: both.value[0] }, program);
52911
+ const snapshot = parseFinalizedPool({ context: both.context, value: both.value[0] }, program, pool2);
52892
52912
  if (snapshot.replayStore !== REPLAY_STORE_INDEXED) return snapshot;
52893
52913
  const treeAccount = both.value[1];
52894
- return Object.freeze({
52914
+ return withPoolStateOf(snapshot, Object.freeze({
52895
52915
  ...snapshot,
52896
52916
  e1TreeAccount: Object.freeze({
52897
52917
  slot: snapshot.slot,
@@ -52899,7 +52919,12 @@ async function readFinalizedPool(connection, program, pool2) {
52899
52919
  ownerProgramId: treeAccount ? canonicalKey(treeAccount.owner, "e1_tree_owner").toBase58() : null,
52900
52920
  data: treeAccount ? Buffer.from(treeAccount.data) : null
52901
52921
  })
52902
- });
52922
+ }));
52923
+ }
52924
+ function withPoolStateOf(snapshot, wrapped) {
52925
+ const entry = SNAPSHOT_POOL_STATES.get(snapshot);
52926
+ if (entry !== void 0) SNAPSHOT_POOL_STATES.set(wrapped, entry);
52927
+ return wrapped;
52903
52928
  }
52904
52929
  async function readFinalizedPoolForRefresh(connection, program, pool2) {
52905
52930
  if (typeof connection.getMultipleAccountsInfoAndContext !== "function") return readFinalizedPool(connection, program, pool2);
@@ -52910,24 +52935,25 @@ async function readFinalizedPoolForRefresh(connection, program, pool2) {
52910
52935
  ));
52911
52936
  if (!Array.isArray(both?.value) || both.value.length !== 2) throw new Error("p03_history_e1_tree_read_invalid");
52912
52937
  if (both.value[0]?.data && Buffer.from(both.value[0].data).length >= REFRESH_READ_BYTES) return readFinalizedPool(connection, program, pool2);
52913
- const snapshot = parseFinalizedPool({ context: both.context, value: both.value[0] }, program);
52938
+ const snapshot = parseFinalizedPool({ context: both.context, value: both.value[0] }, program, pool2);
52914
52939
  if (snapshot.replayStore !== REPLAY_STORE_INDEXED) return snapshot;
52915
52940
  const treeAccount = both.value[1];
52916
- return Object.freeze({
52941
+ return withPoolStateOf(snapshot, Object.freeze({
52917
52942
  ...snapshot,
52918
52943
  e1TreeHeader: Object.freeze({
52919
52944
  address: tree.toBase58(),
52920
52945
  ownerProgramId: treeAccount ? canonicalKey(treeAccount.owner, "e1_tree_owner").toBase58() : null,
52921
52946
  data: treeAccount ? Buffer.from(treeAccount.data) : null
52922
52947
  })
52923
- });
52948
+ }));
52924
52949
  }
52925
- function parseFinalizedPool(response, program) {
52950
+ function parseFinalizedPool(response, program, pool2) {
52926
52951
  const value = response?.value;
52927
52952
  const slot3 = response?.context?.slot;
52928
52953
  safeSlot(slot3, "snapshot_slot");
52929
52954
  if (!value) throw new Error("p03_history_pool_missing");
52930
- if (canonicalKey(value.owner, "pool_owner").toBase58() !== b58(program)) {
52955
+ const owner = canonicalKey(value.owner, "pool_owner");
52956
+ if (owner.toBase58() !== b58(program)) {
52931
52957
  throw new Error("p03_history_pool_owner_mismatch");
52932
52958
  }
52933
52959
  const data = Buffer.from(value.data);
@@ -52946,7 +52972,7 @@ function parseFinalizedPool(response, program) {
52946
52972
  field(data.subarray(48, 80), "snapshot_current_root");
52947
52973
  field(data.subarray(96, 128), "snapshot_anchor_0_root");
52948
52974
  field(data.subarray(144, 176), "snapshot_anchor_1_root");
52949
- return Object.freeze({
52975
+ const snapshot = Object.freeze({
52950
52976
  ...state,
52951
52977
  anchorMode: data[11],
52952
52978
  decimals: data[10],
@@ -52954,6 +52980,14 @@ function parseFinalizedPool(response, program) {
52954
52980
  accountData: data,
52955
52981
  slot: slot3
52956
52982
  });
52983
+ if (pool2 instanceof import_web396.PublicKey) {
52984
+ SNAPSHOT_POOL_STATES.set(snapshot, Object.freeze({
52985
+ programId: b58(program),
52986
+ pool: pool2.toBase58(),
52987
+ state: Object.freeze({ ...state, owner })
52988
+ }));
52989
+ }
52990
+ return snapshot;
52957
52991
  }
52958
52992
  function freezeFinalizedAnchors(snapshot) {
52959
52993
  const candidates = snapshot.anchors.map((anchor, ringSlot) => ({
@@ -54452,7 +54486,7 @@ function base58Decode(value) {
54452
54486
  while (zeros < value.length && value[zeros] === "1") zeros += 1;
54453
54487
  return Uint8Array.from(Buffer.concat([Buffer.alloc(zeros), body]));
54454
54488
  }
54455
- var import_web396, b58Cache, b58, REPLAY_STORE_INDEXED, CLOSE_REPLAY_TREE_TAG, EXTEND_ANCHOR_RING_TAG, WIDEN_ANCHOR_RING_TAG, WIDE_ANCHOR_RING_POOL_BYTES, LINK_SUCCESSOR_TAG, IMPORT_REPLAY_LEAVES_TAG, SETTLE_MOVE_TAG, SWEEP_PREDECESSOR_VAULT_TAG, RELINK_SUCCESSOR_TAG, ROTATE_PAYMENT_SETTLER_TAG, IMPORT_A_LEAF_BYTES, IMPORT_MEMBERSHIP_BYTES, IMPORT_PRESENT_SHIFT, IMPORT_MAX_ENTRIES, MOVE_HEAD_BYTES, MOVE_INSERTED_VALUES, DEFAULT_KEY, FIELD_BYTES2, PRIMARY_PROOF_BYTES, SUBTREE_LEAVES, PAGE_SIZE, FIELD_MODULUS3, BPF_LOADER_UPGRADEABLE_PROGRAM_ID, SYSTEM_PROGRAM, TEST_EXECUTABLES, derivationMemo, memo, reviewedExecutables, isProgramDataIdentityError, ASSUMED_ORIGINAL_EXECUTABLE, AUTHENTICATED_HISTORY_REPORTS, HISTORY_ATTESTATIONS, hasExecutableEvidence, P03_FINALIZED_HISTORY_SOURCE_MODEL, P03_PROGRAMDATA_COVERAGE_SOURCE_MODEL, P03_RUN_RECOVER_UNAVAILABLE_FROM_CHAIN, PROFILES, P03_SETTLEMENT_TAGS, P03_INLINE_SETTLEMENT_TAGS, P03_PAYMENT_REPLAY_INDICES, NO_CONTEXTS, REFRESH_READ_BYTES, E1_TREE_HEADER_BYTES, HISTORY_FETCH_CONCURRENCY, HISTORY_BULK_TRANSACTIONS, HISTORY_BULK_ADDRESSES, TRANSIENT_RPC_ATTEMPTS, TRANSIENT_RPC_BASE_DELAY_MS, LAGGING_NODE_STEP_OF_BASE, LAGGING_NODE_MAX_RETRIES, LAGGING_NODE_FAST_RETRIES, LAGGING_NODE_SLOW_STEP_OF_BASE, LAGGING_NODE_RPC_CODES;
54489
+ var import_web396, b58Cache, b58, REPLAY_STORE_INDEXED, CLOSE_REPLAY_TREE_TAG, EXTEND_ANCHOR_RING_TAG, WIDEN_ANCHOR_RING_TAG, WIDE_ANCHOR_RING_POOL_BYTES, LINK_SUCCESSOR_TAG, IMPORT_REPLAY_LEAVES_TAG, SETTLE_MOVE_TAG, SWEEP_PREDECESSOR_VAULT_TAG, RELINK_SUCCESSOR_TAG, ROTATE_PAYMENT_SETTLER_TAG, IMPORT_A_LEAF_BYTES, IMPORT_MEMBERSHIP_BYTES, IMPORT_PRESENT_SHIFT, IMPORT_MAX_ENTRIES, MOVE_HEAD_BYTES, MOVE_INSERTED_VALUES, DEFAULT_KEY, FIELD_BYTES2, PRIMARY_PROOF_BYTES, SUBTREE_LEAVES, PAGE_SIZE, FIELD_MODULUS3, BPF_LOADER_UPGRADEABLE_PROGRAM_ID, SYSTEM_PROGRAM, TEST_EXECUTABLES, derivationMemo, memo, reviewedExecutables, isProgramDataIdentityError, ASSUMED_ORIGINAL_EXECUTABLE, AUTHENTICATED_HISTORY_REPORTS, HISTORY_ATTESTATIONS, SNAPSHOT_POOL_STATES, REPORT_POOL_STATES, hasExecutableEvidence, P03_FINALIZED_HISTORY_SOURCE_MODEL, P03_PROGRAMDATA_COVERAGE_SOURCE_MODEL, P03_RUN_RECOVER_UNAVAILABLE_FROM_CHAIN, PROFILES, P03_SETTLEMENT_TAGS, P03_INLINE_SETTLEMENT_TAGS, P03_PAYMENT_REPLAY_INDICES, NO_CONTEXTS, REFRESH_READ_BYTES, E1_TREE_HEADER_BYTES, HISTORY_FETCH_CONCURRENCY, HISTORY_BULK_TRANSACTIONS, HISTORY_BULK_ADDRESSES, TRANSIENT_RPC_ATTEMPTS, TRANSIENT_RPC_BASE_DELAY_MS, LAGGING_NODE_STEP_OF_BASE, LAGGING_NODE_MAX_RETRIES, LAGGING_NODE_FAST_RETRIES, LAGGING_NODE_SLOW_STEP_OF_BASE, LAGGING_NODE_RPC_CODES;
54456
54490
  var init_walk = __esm({
54457
54491
  "wallet/src/history/walk.mjs"() {
54458
54492
  "use strict";
@@ -54517,6 +54551,8 @@ var init_walk = __esm({
54517
54551
  ASSUMED_ORIGINAL_EXECUTABLE = p03ReviewedExecutable(P03_COMPATIBLE_CODE.previous);
54518
54552
  AUTHENTICATED_HISTORY_REPORTS = /* @__PURE__ */ new WeakSet();
54519
54553
  HISTORY_ATTESTATIONS = /* @__PURE__ */ new WeakMap();
54554
+ SNAPSHOT_POOL_STATES = /* @__PURE__ */ new WeakMap();
54555
+ REPORT_POOL_STATES = /* @__PURE__ */ new WeakMap();
54520
54556
  hasExecutableEvidence = (coverage) => Array.isArray(coverage?.executables) && coverage.executables.length > 0;
54521
54557
  P03_FINALIZED_HISTORY_SOURCE_MODEL = "carbon/shielded-x402-wallet/p03-finalized-history/v1";
54522
54558
  P03_PROGRAMDATA_COVERAGE_SOURCE_MODEL = "carbon/shielded-x402-wallet/p03-programdata-finalized-history/v1";
@@ -54730,6 +54766,7 @@ function buildFinalizedP03RecoveryPath({
54730
54766
  circuitSource,
54731
54767
  anchor
54732
54768
  }) {
54769
+ noteHistoryActivity();
54733
54770
  const authenticated = assertAuthenticatedFinalizedP03History(history);
54734
54771
  const coverage = validateDeploymentCoverage(authenticated);
54735
54772
  validatePinnedCircuitSource(circuitSource);
@@ -54800,6 +54837,7 @@ function buildFinalizedP03RecoveryPath({
54800
54837
  });
54801
54838
  }
54802
54839
  function buildFinalizedP03Frontier({ history, circuitSource }) {
54840
+ noteHistoryActivity();
54803
54841
  const authenticated = assertAuthenticatedFinalizedP03History(history);
54804
54842
  validateDeploymentCoverage(authenticated);
54805
54843
  validatePinnedCircuitSource(circuitSource);
@@ -54836,6 +54874,26 @@ function validateDeploymentCoverage(history) {
54836
54874
  }
54837
54875
  return coverage;
54838
54876
  }
54877
+ function noteHistoryActivity(delta = 0) {
54878
+ historyBusy = Math.max(0, historyBusy + delta);
54879
+ historyActiveAt = performance.now();
54880
+ }
54881
+ function historyQuietFor(ms) {
54882
+ return historyBusy === 0 && performance.now() - historyActiveAt >= ms;
54883
+ }
54884
+ function noteCachedFoldRoots(pool2, roots, onDrop) {
54885
+ const entry = CACHED_FOLD_ROOTS.get(pool2);
54886
+ CACHED_FOLD_ROOTS.set(pool2, { roots: new Map([...entry?.roots ?? [], ...roots]), onDrop });
54887
+ }
54888
+ function forgetCachedFoldRoots(pool2, roots) {
54889
+ const entry = CACHED_FOLD_ROOTS.get(pool2);
54890
+ if (entry === void 0) return;
54891
+ for (const [count2, root] of roots) if (entry.roots.get(count2) === root) entry.roots.delete(count2);
54892
+ if (entry.roots.size === 0) CACHED_FOLD_ROOTS.delete(pool2);
54893
+ }
54894
+ function dropRecoveryFold() {
54895
+ lastFold = void 0;
54896
+ }
54839
54897
  function rebuildOrderedPrefixes(history) {
54840
54898
  const cached = REBUILT_BY_REPORT.get(history);
54841
54899
  if (cached !== void 0) return cached;
@@ -54845,7 +54903,15 @@ function rebuildOrderedPrefixes(history) {
54845
54903
  REBUILT_BY_REPORT.set(history, next.value);
54846
54904
  return next.value;
54847
54905
  }
54848
- async function prepareFinalizedP03RecoveryFold(history, { sliceMs = 20 } = {}) {
54906
+ async function prepareFinalizedP03RecoveryFold(history, options) {
54907
+ noteHistoryActivity(1);
54908
+ try {
54909
+ return await prepareFinalizedP03RecoveryFoldNow(history, options);
54910
+ } finally {
54911
+ noteHistoryActivity(-1);
54912
+ }
54913
+ }
54914
+ async function prepareFinalizedP03RecoveryFoldNow(history, { sliceMs = 20 } = {}) {
54849
54915
  const authenticated = assertAuthenticatedFinalizedP03History(history);
54850
54916
  if (REBUILT_BY_REPORT.has(authenticated)) return;
54851
54917
  const running = FOLDS_IN_FLIGHT.get(authenticated);
@@ -54899,6 +54965,8 @@ function* rebuildOrderedPrefixSteps(history) {
54899
54965
  let nodes = resumed > 0 ? prior.nodes : zeroRoots2.slice(0, OUTER_DEPTH);
54900
54966
  let root = resumed > 0 ? prior.roots[resumed] : zeroRoots2[OUTER_DEPTH];
54901
54967
  const roots = resumed > 0 ? prior.roots.slice(0, resumed + 1) : [root];
54968
+ const cached = CACHED_FOLD_ROOTS.get(history.pool);
54969
+ let cachedDropped = false;
54902
54970
  for (let ordinal = 0; ordinal < contexts.length; ordinal += 1) {
54903
54971
  const context = contexts[ordinal];
54904
54972
  const expectedIndex = BigInt(ordinal) * SUBTREE_LEAVES2;
@@ -54922,7 +54990,19 @@ function* rebuildOrderedPrefixSteps(history) {
54922
54990
  for (let level = 0; level < OUTER_DEPTH; level += 1) {
54923
54991
  if ((nextCount >> BigInt(level) & 1n) === 0n) nextNodes[level] = zeroRoots2[level];
54924
54992
  }
54925
- if (node3 !== context.appendRoot) throw new Error("p03_recovery_append_root_mismatch");
54993
+ if (node3 !== context.appendRoot) {
54994
+ if (cached === void 0 || ordinal + 1 >= contexts.length || cached.roots.get(ordinal + 1) !== context.appendRoot) {
54995
+ throw new Error("p03_recovery_append_root_mismatch");
54996
+ }
54997
+ if (!cachedDropped) {
54998
+ cachedDropped = true;
54999
+ markPhase("compact-roots-dropped");
55000
+ try {
55001
+ cached.onDrop();
55002
+ } catch {
55003
+ }
55004
+ }
55005
+ }
54926
55006
  nodes = nextNodes;
54927
55007
  root = node3;
54928
55008
  roots.push(root);
@@ -54950,6 +55030,36 @@ function* rebuildOrderedPrefixSteps(history) {
54950
55030
  nodes: frozenNodes
54951
55031
  });
54952
55032
  }
55033
+ function seedFinalizedP03RecoveryFold({ leaves, roots, frontier } = {}) {
55034
+ try {
55035
+ const zeroRoots2 = zeroUpperRoots();
55036
+ const count2 = Array.isArray(leaves) ? leaves.length : 0;
55037
+ if (count2 === 0 || !Array.isArray(roots) || roots.length !== count2 + 1 || !Array.isArray(frontier) || frontier.length !== OUTER_DEPTH || roots[0] !== zeroRoots2[OUTER_DEPTH]) return false;
55038
+ const isField = (value) => typeof value === "bigint" && value >= 0n && value < FIELD_MODULUS4;
55039
+ if (!leaves.every(isField) || !roots.every(isField) || !frontier.every(isField)) return false;
55040
+ let node3 = zeroRoots2[0];
55041
+ let position3 = BigInt(count2);
55042
+ for (let level = 0; level < OUTER_DEPTH; level += 1) {
55043
+ const filled = frontier[level];
55044
+ if ((position3 & 1n) === 0n) {
55045
+ if (filled !== zeroRoots2[level]) return false;
55046
+ node3 = hash3(node3, zeroRoots2[level]);
55047
+ } else {
55048
+ node3 = hash3(filled, node3);
55049
+ }
55050
+ position3 >>= 1n;
55051
+ }
55052
+ if (node3 !== roots[count2]) return false;
55053
+ lastFold = Object.freeze({
55054
+ leaves: Object.freeze([...leaves]),
55055
+ roots: Object.freeze([...roots]),
55056
+ nodes: Object.freeze([...frontier])
55057
+ });
55058
+ return true;
55059
+ } catch {
55060
+ return false;
55061
+ }
55062
+ }
54953
55063
  function zeroUpperRoots() {
54954
55064
  ZERO_UPPER_ROOTS ??= Object.freeze(computeZeroUpperRoots());
54955
55065
  return ZERO_UPPER_ROOTS;
@@ -55070,7 +55180,7 @@ function canonicalField(value, label) {
55070
55180
  }
55071
55181
  return value;
55072
55182
  }
55073
- var FIELD_MODULUS4, SUBTREE_LEAVES2, LOCAL_DEPTH, OUTER_DEPTH, TREE_DEPTH, P03_RECOVERY_PATH_SOURCE_MODEL, P03_PINNED_POSEIDON_PARAMETERS_SHA256, P03_PINNED_ZERO_LEAF, hashCalls, hash3, REBUILT_BY_REPORT, lastFold, FOLDS_IN_FLIGHT, foldInFlight, ZERO_UPPER_ROOTS, LOCAL_ZERO_ROOTS, lastOuter;
55183
+ var FIELD_MODULUS4, SUBTREE_LEAVES2, LOCAL_DEPTH, OUTER_DEPTH, TREE_DEPTH, P03_RECOVERY_PATH_SOURCE_MODEL, P03_PINNED_POSEIDON_PARAMETERS_SHA256, P03_PINNED_ZERO_LEAF, hashCalls, hash3, REBUILT_BY_REPORT, lastFold, historyBusy, historyActiveAt, CACHED_FOLD_ROOTS, FOLDS_IN_FLIGHT, foldInFlight, ZERO_UPPER_ROOTS, LOCAL_ZERO_ROOTS, lastOuter;
55074
55184
  var init_recoveryPath = __esm({
55075
55185
  "wallet/src/recovery/recoveryPath.mjs"() {
55076
55186
  "use strict";
@@ -55096,6 +55206,9 @@ var init_recoveryPath = __esm({
55096
55206
  ], 3);
55097
55207
  };
55098
55208
  REBUILT_BY_REPORT = /* @__PURE__ */ new WeakMap();
55209
+ historyBusy = 0;
55210
+ historyActiveAt = -Infinity;
55211
+ CACHED_FOLD_ROOTS = /* @__PURE__ */ new Map();
55099
55212
  FOLDS_IN_FLIGHT = /* @__PURE__ */ new WeakMap();
55100
55213
  }
55101
55214
  });
@@ -55126,47 +55239,147 @@ function zeroRoots() {
55126
55239
  zeroRootsMemo = Object.freeze(roots);
55127
55240
  return zeroRootsMemo;
55128
55241
  }
55129
- function foldCompactLeaves(leaves, counts) {
55242
+ function foldCompactLeaves(leaves, counts, frontier) {
55130
55243
  const zero = zeroRoots();
55131
55244
  const filled = new Array(OUTER_DEPTH2);
55132
55245
  const roots = /* @__PURE__ */ new Map();
55133
- const rootAt = (count2) => {
55134
- let node3 = zero[0];
55135
- for (let level = 0; level < OUTER_DEPTH2; level += 1) {
55136
- node3 = bitAt(count2, level) === 1 ? hash4(filled[level], node3) : hash4(node3, zero[level]);
55137
- }
55138
- return node3;
55139
- };
55140
55246
  if (counts.has(0)) roots.set(0, zero[OUTER_DEPTH2]);
55141
55247
  leaves.forEach((leaf, position3) => {
55142
- let node3 = leaf;
55143
- let level = 0;
55144
- while (bitAt(position3, level) === 1) {
55145
- node3 = hash4(filled[level], node3);
55146
- level += 1;
55147
- }
55148
- filled[level] = node3;
55149
- if (counts.has(position3 + 1)) roots.set(position3 + 1, rootAt(position3 + 1));
55248
+ appendCompactLeaf(filled, leaf, position3);
55249
+ if (counts.has(position3 + 1)) roots.set(position3 + 1, compactRootAt(filled, position3 + 1));
55150
55250
  });
55251
+ if (Array.isArray(frontier)) {
55252
+ for (let level = 0; level < OUTER_DEPTH2; level += 1) {
55253
+ frontier[level] = bitAt(leaves.length, level) === 1 ? filled[level] : zero[level];
55254
+ }
55255
+ }
55151
55256
  return roots;
55152
55257
  }
55153
- function foldCompactLeavesReusing(pool2, leaves, counts) {
55258
+ function appendCompactLeaf(filled, leaf, position3) {
55259
+ let node3 = leaf;
55260
+ let level = 0;
55261
+ while (bitAt(position3, level) === 1) {
55262
+ node3 = hash4(filled[level], node3);
55263
+ level += 1;
55264
+ }
55265
+ filled[level] = node3;
55266
+ }
55267
+ function compactRootAt(filled, count2) {
55268
+ const zero = zeroRoots();
55269
+ let node3 = zero[0];
55270
+ for (let level = 0; level < OUTER_DEPTH2; level += 1) {
55271
+ node3 = bitAt(count2, level) === 1 ? hash4(filled[level], node3) : hash4(node3, zero[level]);
55272
+ }
55273
+ return node3;
55274
+ }
55275
+ function foldCompactLeavesReusing(pool2, leaves, counts, { frontier, fresh = /* @__PURE__ */ new Set(), stats } = {}) {
55154
55276
  const prior = lastFolds.get(pool2);
55155
55277
  let common = 0;
55156
55278
  if (prior !== void 0) {
55157
55279
  const most = Math.min(prior.leaves.length, leaves.length);
55158
55280
  while (common < most && prior.leaves[common] === leaves[common]) common += 1;
55159
55281
  }
55160
- const known = (at) => prior !== void 0 && at <= common && prior.roots.has(at);
55161
- const roots = foldCompactLeaves(leaves, new Set([...counts].filter((at) => !known(at))));
55162
- for (const at of counts) if (known(at)) roots.set(at, prior.roots.get(at));
55282
+ const known = (at) => prior !== void 0 && at <= common && prior.roots.has(at) && !fresh.has(at);
55283
+ const roots = foldCompactLeaves(leaves, new Set([...counts].filter((at) => !known(at))), frontier);
55284
+ if (prior !== void 0 && [...fresh].some((at) => at <= common && prior.roots.has(at) && roots.has(at) && prior.roots.get(at) !== roots.get(at))) {
55285
+ lastFolds.delete(pool2);
55286
+ if (stats) stats.refolded = true;
55287
+ return foldCompactLeavesReusing(pool2, leaves, counts, { frontier, fresh, stats });
55288
+ }
55289
+ let reused = 0;
55290
+ const cachedRoots = /* @__PURE__ */ new Map();
55291
+ for (const at of counts) {
55292
+ if (known(at)) {
55293
+ roots.set(at, prior.roots.get(at));
55294
+ reused += 1;
55295
+ if (prior.tainted?.has(at)) cachedRoots.set(at, prior.roots.get(at));
55296
+ }
55297
+ }
55298
+ if (stats) Object.assign(stats, { reused, cachedRoots });
55163
55299
  const kept = new Map(roots);
55300
+ const tainted = new Set(cachedRoots.keys());
55164
55301
  if (prior !== void 0) {
55165
- for (const [at, root] of prior.roots) if (at <= common && !kept.has(at)) kept.set(at, root);
55302
+ for (const [at, root] of prior.roots) {
55303
+ if (at > common || kept.has(at)) continue;
55304
+ kept.set(at, root);
55305
+ if (prior.tainted?.has(at)) tainted.add(at);
55306
+ }
55166
55307
  }
55167
- lastFolds.set(pool2, { leaves: leaves.slice(), roots: kept });
55308
+ lastFolds.set(pool2, { leaves: leaves.slice(), roots: kept, ...tainted.size > 0 ? { tainted } : {} });
55168
55309
  return roots;
55169
55310
  }
55311
+ function hintCompactFold(pool2, hint) {
55312
+ if (lastFolds.has(pool2) || droppedPools.has(pool2) || !hint || !Array.isArray(hint.records) || !hint.foldRoots) return false;
55313
+ const { records, foldRoots } = hint;
55314
+ if (!Array.isArray(foldRoots.roots) || foldRoots.roots.length === 0 || foldRoots.roots.length !== records.length || foldRoots.zero !== hex64(zeroRoots()[OUTER_DEPTH2])) return false;
55315
+ const field4 = (value) => {
55316
+ if (typeof value !== "string" || !HEX64.test(value)) return void 0;
55317
+ const parsed = BigInt(`0x${value}`);
55318
+ return parsed < FIELD_MODULUS5 ? parsed : void 0;
55319
+ };
55320
+ const leaves = [];
55321
+ const roots = /* @__PURE__ */ new Map();
55322
+ for (let at = 0; at < records.length; at += 1) {
55323
+ const leaf = field4(records[at]?.outCommitment);
55324
+ const root = field4(foldRoots.roots[at]);
55325
+ if (leaf === void 0 || root === void 0) return false;
55326
+ leaves.push(leaf);
55327
+ roots.set(at + 1, root);
55328
+ }
55329
+ lastFolds.set(pool2, { leaves, roots, tainted: new Set(roots.keys()) });
55330
+ return true;
55331
+ }
55332
+ function dropCachedFoldRoots(pool2, cache) {
55333
+ if (droppedPools.has(pool2)) return;
55334
+ droppedPools.add(pool2);
55335
+ lastFolds.delete(pool2);
55336
+ dropRecoveryFold();
55337
+ if (cache === void 0) return;
55338
+ (async () => {
55339
+ const current = await cache.load();
55340
+ if (!current || current.pool !== pool2 || current.foldRoots === void 0) return;
55341
+ const { foldRoots: _dropped, savedAt, ...rest } = current;
55342
+ await cache.save(rest, { savedAt });
55343
+ })().catch(() => {
55344
+ });
55345
+ }
55346
+ function startCachedRootsVerify({ pool: pool2, leaves, cachedRoots, cache }) {
55347
+ if (verifying.has(pool2) || cachedRoots.size === 0) return;
55348
+ verifying.add(pool2);
55349
+ verifyCachedRoots({ pool: pool2, leaves, cachedRoots, cache }).catch(() => {
55350
+ }).finally(() => verifying.delete(pool2));
55351
+ }
55352
+ async function verifyCachedRoots({ pool: pool2, leaves, cachedRoots, cache }) {
55353
+ const last = Math.max(...cachedRoots.keys());
55354
+ if (last > leaves.length) return;
55355
+ let sliceStart = 0;
55356
+ const quiet = async () => {
55357
+ while (!historyQuietFor(verifyQuietMs)) await unrefTurn(VERIFY_POLL_MS);
55358
+ sliceStart = performance.now();
55359
+ };
55360
+ await quiet();
55361
+ const filled = new Array(OUTER_DEPTH2);
55362
+ for (let position3 = 0; position3 < last; position3 += 1) {
55363
+ appendCompactLeaf(filled, leaves[position3], position3);
55364
+ const expected = cachedRoots.get(position3 + 1);
55365
+ if (expected !== void 0 && compactRootAt(filled, position3 + 1) !== expected) {
55366
+ markPhase("compact-roots-dropped");
55367
+ dropCachedFoldRoots(pool2, cache);
55368
+ return;
55369
+ }
55370
+ if (performance.now() - sliceStart >= VERIFY_SLICE_MS) {
55371
+ await unrefImmediate();
55372
+ await quiet();
55373
+ }
55374
+ }
55375
+ const entry = lastFolds.get(pool2);
55376
+ if (entry?.tainted) {
55377
+ for (const [at, root] of cachedRoots) if (entry.roots.get(at) === root) entry.tainted.delete(at);
55378
+ if (entry.tainted.size === 0) delete entry.tainted;
55379
+ }
55380
+ forgetCachedFoldRoots(pool2, cachedRoots);
55381
+ markPhase("compact-roots-verified");
55382
+ }
55170
55383
  function fieldOf(hex4) {
55171
55384
  if (typeof hex4 !== "string" || !HEX64.test(hex4)) throw refuse3("p03_compact_history_record_invalid");
55172
55385
  const value = BigInt(`0x${hex4}`);
@@ -55630,7 +55843,15 @@ async function ownInitialization(own, served, { program, poolKey, snapshot, know
55630
55843
  }
55631
55844
  return instruction;
55632
55845
  }
55633
- async function readCompactP03History({
55846
+ async function readCompactP03History(options) {
55847
+ noteHistoryActivity(1);
55848
+ try {
55849
+ return await readCompactP03HistoryNow(options);
55850
+ } finally {
55851
+ noteHistoryActivity(-1);
55852
+ }
55853
+ }
55854
+ async function readCompactP03HistoryNow({
55634
55855
  history,
55635
55856
  own,
55636
55857
  programId,
@@ -55655,6 +55876,9 @@ async function readCompactP03History({
55655
55876
  // compactP03HistoryReport: run beside the spot checks once the initialization is verified
55656
55877
  // ({ snapshot, initialization, contexts }); its result comes back as `alongside`.
55657
55878
  alongside,
55879
+ // compactP03HistoryReport: the compact cache's records and append roots ({ records, foldRoots }),
55880
+ // a hint for the fold when this process has not folded the pool yet (hintCompactFold).
55881
+ foldHint,
55658
55882
  // Called once with the served contexts in chain order, before the fold and every own-RPC
55659
55883
  // check: they are NOT verified yet. A payment asks the memo service for their memos here
55660
55884
  // (payAndFetch.mjs), and uses an answer only for a context the verified report names. Its
@@ -55751,7 +55975,21 @@ async function readCompactP03History({
55751
55975
  for (const anchor of anchors) counts.add(Number(anchor.index / SUBTREE_LEAVES3));
55752
55976
  if (appendRoots) for (let at = 1; at <= count2; at += 1) counts.add(at);
55753
55977
  for (const at of counts) if (at > count2) throw refuse3("p03_compact_history_snapshot_invalid");
55754
- roots = foldCompactLeavesReusing(poolString, contexts.map((context) => context.outCommitment), counts);
55978
+ const frontier = appendRoots ? [] : void 0;
55979
+ const hinted = hintCompactFold(poolString, foldHint);
55980
+ const leaves = contexts.map((context) => context.outCommitment);
55981
+ const fresh = /* @__PURE__ */ new Set([count2, ...picks.map((ordinal) => ordinal + 1)]);
55982
+ if (hinted && count2 > 0) for (let sample = 0; sample < 4; sample += 1) fresh.add(1 + randomInt2(count2));
55983
+ const stats = {};
55984
+ roots = foldCompactLeavesReusing(poolString, leaves, counts, { frontier, fresh, stats });
55985
+ if (stats.reused > 0 && anchors.some((anchor) => roots.get(Number(anchor.index / SUBTREE_LEAVES3)) !== anchor.root)) {
55986
+ lastFolds.delete(poolString);
55987
+ stats.refolded = true;
55988
+ roots = foldCompactLeavesReusing(poolString, leaves, counts, { frontier, fresh });
55989
+ }
55990
+ const cachedRoots = stats.refolded ? /* @__PURE__ */ new Map() : stats.cachedRoots ?? /* @__PURE__ */ new Map();
55991
+ if (stats.refolded) markPhase("compact-roots-refold");
55992
+ else if (cachedRoots.size > 0) markPhase("compact-roots-cached");
55755
55993
  if (roots.get(count2) !== snapshot.currentRoot) throw refuse3("p03_compact_history_root_mismatch");
55756
55994
  for (const anchor of anchors) {
55757
55995
  if (roots.get(Number(anchor.index / SUBTREE_LEAVES3)) !== anchor.root) throw refuse3("p03_compact_history_root_mismatch");
@@ -55779,6 +56017,11 @@ async function readCompactP03History({
55779
56017
  replayStore: snapshot.replayStore
55780
56018
  }),
55781
56019
  contexts: Object.freeze(finished),
56020
+ // With appendRoots: the fold's frontier after every context (foldCompactLeaves). Bound to
56021
+ // currentRoot only by the recovery fold's seed check (seedFinalizedP03RecoveryFold).
56022
+ outerFrontier: frontier === void 0 ? void 0 : Object.freeze(frontier),
56023
+ // Append roots taken from the compact cache and not hashed in this process (count -> root).
56024
+ cachedRoots,
55782
56025
  // Tag 31 imports up to the snapshot, in chain order (validateImport shape).
55783
56026
  imports: Object.freeze(imports),
55784
56027
  spentReplayValues: Object.freeze([...new Set(finished.flatMap((context) => context.replayValues.map(String)))].sort()),
@@ -55889,7 +56132,8 @@ async function compactP03HistoryReport({
55889
56132
  ...knownSnapshot !== void 0 ? { knownSnapshot } : {},
55890
56133
  ...onList !== void 0 ? { onList } : {},
55891
56134
  ...warm ? { served: cached.served } : {},
55892
- ...cached ? { initialization: cached.initialization } : {}
56135
+ ...cached ? { initialization: cached.initialization } : {},
56136
+ ...cached?.foldRoots ? { foldHint: { records: cached.served.records, foldRoots: cached.foldRoots } } : {}
55893
56137
  });
55894
56138
  const initialization = compact.verifiedInitialization;
55895
56139
  if (initialization === void 0) throw refuse3("p03_compact_history_pool_empty");
@@ -55932,6 +56176,21 @@ async function compactP03HistoryReport({
55932
56176
  // link or the predecessors finds none and refuses (recover.mjs) or walks in full.
55933
56177
  ...compact.imports.length > 0 ? { succession: Object.freeze({ imports: compactSuccessionImports(compact.imports) }) } : {}
55934
56178
  });
56179
+ if (compact.outerFrontier !== void 0 && seedFinalizedP03RecoveryFold({
56180
+ leaves: report.contexts.map((context) => context.outCommitment),
56181
+ roots: [zeroRoots()[OUTER_DEPTH2], ...report.contexts.map((context) => context.appendRoot)],
56182
+ frontier: compact.outerFrontier
56183
+ })) markPhase("fold-seeded-compact");
56184
+ if (compact.cachedRoots.size > 0) {
56185
+ const poolString = poolKey.toBase58();
56186
+ noteCachedFoldRoots(report.pool, compact.cachedRoots, () => dropCachedFoldRoots(poolString, cache));
56187
+ startCachedRootsVerify({
56188
+ pool: poolString,
56189
+ leaves: report.contexts.map((context) => context.outCommitment),
56190
+ cachedRoots: compact.cachedRoots,
56191
+ cache
56192
+ });
56193
+ }
55935
56194
  if (cache) {
55936
56195
  try {
55937
56196
  await cache.save({
@@ -55945,7 +56204,12 @@ async function compactP03HistoryReport({
55945
56204
  },
55946
56205
  served: compact.served,
55947
56206
  initialization,
55948
- attestation: attested.attestation
56207
+ attestation: attested.attestation,
56208
+ // The append root after each served record, a hint for a new process's fold (hintCompactFold).
56209
+ ...compact.outerFrontier !== void 0 && !droppedPools.has(poolKey.toBase58()) ? { foldRoots: {
56210
+ zero: hex64(zeroRoots()[OUTER_DEPTH2]),
56211
+ roots: report.contexts.map((context) => hex64(context.appendRoot))
56212
+ } } : {}
55949
56213
  });
55950
56214
  } catch {
55951
56215
  }
@@ -55965,7 +56229,7 @@ async function tryCompactP03HistoryReport(options) {
55965
56229
  return { ok: false, reason: refusalReason(error), ...typeof error?.detail === "string" ? { detail: error.detail } : {}, error };
55966
56230
  }
55967
56231
  }
55968
- var import_web397, P03_COMPACT_HISTORY_SOURCE_MODEL, P03_COMPACT_PAGE, P03_COMPACT_SPOT_CHECKS, FIELD_MODULUS5, SUBTREE_LEAVES3, LOCAL_DEPTH2, OUTER_DEPTH2, PRIMARY_PROOF_BYTES2, FIELD_BYTES3, ED25519_SPKI_PREFIX2, VERSION_1_PREFIX2, HEX64, BASE58, REPLAY_STORE_INDEXED2, PROFILES2, MOVE_HEAD_BYTES2, MOVE_INSERTED_VALUES2, refuse3, hash4, bitAt, zeroRootsMemo, lastFolds, isSignature, isIndex, IMPORT_KEYS, IMPORT_MAX_VALUES, LIST_ATTEMPTS, OWN_READ_TIMEOUT_MS, BOUNDED_OWN_METHODS;
56232
+ var import_web397, P03_COMPACT_HISTORY_SOURCE_MODEL, P03_COMPACT_PAGE, P03_COMPACT_SPOT_CHECKS, FIELD_MODULUS5, SUBTREE_LEAVES3, LOCAL_DEPTH2, OUTER_DEPTH2, PRIMARY_PROOF_BYTES2, FIELD_BYTES3, ED25519_SPKI_PREFIX2, VERSION_1_PREFIX2, HEX64, BASE58, REPLAY_STORE_INDEXED2, PROFILES2, MOVE_HEAD_BYTES2, MOVE_INSERTED_VALUES2, refuse3, hash4, bitAt, zeroRootsMemo, lastFolds, hex64, droppedPools, verifyQuietMs, VERIFY_SLICE_MS, VERIFY_POLL_MS, verifying, unrefTurn, unrefImmediate, isSignature, isIndex, IMPORT_KEYS, IMPORT_MAX_VALUES, LIST_ATTEMPTS, OWN_READ_TIMEOUT_MS, BOUNDED_OWN_METHODS;
55969
56233
  var init_compact = __esm({
55970
56234
  "wallet/src/history/compact.mjs"() {
55971
56235
  "use strict";
@@ -56077,6 +56341,20 @@ var init_compact = __esm({
56077
56341
  hash4 = (left, right) => poseidon2([left, right], 3);
56078
56342
  bitAt = (value, level) => Math.floor(value / 2 ** level) % 2;
56079
56343
  lastFolds = /* @__PURE__ */ new Map();
56344
+ hex64 = (value) => value.toString(16).padStart(64, "0");
56345
+ droppedPools = /* @__PURE__ */ new Set();
56346
+ verifyQuietMs = 3e4;
56347
+ VERIFY_SLICE_MS = 20;
56348
+ VERIFY_POLL_MS = 250;
56349
+ verifying = /* @__PURE__ */ new Set();
56350
+ unrefTurn = (ms) => new Promise((resolve38) => {
56351
+ const timer = setTimeout(resolve38, ms);
56352
+ timer.unref?.();
56353
+ });
56354
+ unrefImmediate = () => new Promise((resolve38) => {
56355
+ const turn = setImmediate(resolve38);
56356
+ turn.unref?.();
56357
+ });
56080
56358
  isSignature = (value) => typeof value === "string" && value.length >= 64 && value.length <= 88 && BASE58.test(value);
56081
56359
  isIndex = (value) => Number.isSafeInteger(value) && value >= 0;
56082
56360
  IMPORT_KEYS = ["afterOrdinal", "instructionIndex", "record", "signature", "slot", "transactionIndex", "values"];
@@ -56667,6 +56945,7 @@ async function loadWalletP03History(args) {
56667
56945
  const report2 = await prewarm.promise;
56668
56946
  PREWARMED_REPORTS.add(report2);
56669
56947
  markPhase("walk-prewarmed");
56948
+ if (runKey !== void 0) recentLoads.set(runKey, { startedAt: prewarm.startedAt, report: report2 });
56670
56949
  return report2;
56671
56950
  } catch {
56672
56951
  }
@@ -72585,9 +72864,35 @@ async function readFinalizedClock(connection) {
72585
72864
  const data = info?.data;
72586
72865
  if (!data || data.length < 40) return void 0;
72587
72866
  const timestamp = Buffer.from(data).readBigInt64LE(32);
72588
- return timestamp >= 0n && timestamp <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(timestamp) : void 0;
72867
+ if (timestamp < 0n || timestamp > BigInt(Number.MAX_SAFE_INTEGER)) return void 0;
72868
+ if (typeof connection === "object" && connection !== null) {
72869
+ lastClockAnswers.set(connection, { time: Number(timestamp), arrivedAt: performance.now() });
72870
+ }
72871
+ return Number(timestamp);
72589
72872
  }
72590
- function startFinalizedChainTime(connection) {
72873
+ function startFinalizedChainTime(connection, { reuseRecent = false } = {}) {
72874
+ const recentClock = () => {
72875
+ const last = typeof connection === "object" && connection !== null ? lastClockAnswers.get(connection) : void 0;
72876
+ const age = last === void 0 ? Infinity : performance.now() - last.arrivedAt;
72877
+ return age <= PROOF_CHAIN_TIME_REUSE_MS ? { time: last.time, age } : void 0;
72878
+ };
72879
+ const recent = reuseRecent ? recentClock() : void 0;
72880
+ if (recent !== void 0) {
72881
+ let fallback;
72882
+ const timer = setTimeout(() => {
72883
+ fallback = startFinalizedChainTime(connection);
72884
+ }, PROOF_CHAIN_TIME_REUSE_MS - recent.age);
72885
+ timer.unref?.();
72886
+ return async () => {
72887
+ clearTimeout(timer);
72888
+ const now = recentClock();
72889
+ if (now !== void 0) {
72890
+ markPhase("chain-time-reused");
72891
+ return now.time + Math.floor(now.age / 1e3);
72892
+ }
72893
+ return (fallback ?? startFinalizedChainTime(connection))();
72894
+ };
72895
+ }
72591
72896
  const startedAt = performance.now();
72592
72897
  let arrivedAt;
72593
72898
  const early = readFinalizedClock(connection).then((time) => {
@@ -72605,16 +72910,32 @@ function startFinalizedChainTime(connection) {
72605
72910
  return time + Math.floor(age / 1e3);
72606
72911
  };
72607
72912
  }
72913
+ function walkPoolState(history, programId, pool2) {
72914
+ let state;
72915
+ try {
72916
+ state = finalizedPoolStateOf(history, { programId: new import_web3106.PublicKey(programId).toBase58(), pool: new import_web3106.PublicKey(pool2).toBase58() });
72917
+ } catch {
72918
+ return void 0;
72919
+ }
72920
+ if (state !== void 0) markPhase("recover-pool-from-walk");
72921
+ return state;
72922
+ }
72608
72923
  async function everyAccountHeld({ store, connection, programId, serviceUrl: serviceUrl2, reservedReplayValues, amountAtomic, deps = {} }) {
72609
72924
  if (typeof deps.walkHistory !== "function") fail15("walk_history_required");
72610
72925
  const viewing = deriveWalletViewingAuthority2({ seedBytes: seedBytes5(store.state), generator: pinnedGenerator4() });
72611
72926
  const history = assertAuthenticatedFinalizedP03History(await withRecentWalletHistory(() => deps.walkHistory()));
72927
+ const poolState2 = walkPoolState(history, programId, store.state.pool);
72612
72928
  const recovery = await (deps.recover ?? runRecover)({
72613
72929
  store,
72614
72930
  connection,
72615
72931
  programId: new import_web3106.PublicKey(programId),
72616
72932
  serviceUrl: serviceUrl2,
72617
- deps: { fetchImpl: deps.fetchImpl, finalizedHistory: history, transitionContextFor: history.transitionContextFor }
72933
+ deps: {
72934
+ fetchImpl: deps.fetchImpl,
72935
+ finalizedHistory: history,
72936
+ transitionContextFor: history.transitionContextFor,
72937
+ ...poolState2 !== void 0 ? { poolState: poolState2 } : {}
72938
+ }
72618
72939
  });
72619
72940
  const poolDomain = history.contexts[0]?.poolDomain;
72620
72941
  const held = (entry) => {
@@ -72661,10 +72982,7 @@ async function prepareRecoveredPayment({
72661
72982
  const chainProgramId = new import_web3106.PublicKey(programId);
72662
72983
  const generator2 = pinnedGenerator4();
72663
72984
  const viewing = deriveWalletViewingAuthority2({ seedBytes: seedBytes5(state), generator: generator2 });
72664
- const chainTime2 = deps.chainTime === void 0 ? startFinalizedChainTime(connection) : void 0;
72665
- const poolState2 = deps.recover === void 0 ? readPoolState2(connection, pool2) : void 0;
72666
- poolState2?.catch(() => {
72667
- });
72985
+ const chainTime2 = deps.chainTime === void 0 ? startFinalizedChainTime(connection, { reuseRecent: true }) : void 0;
72668
72986
  if (deps.provePayment === void 0 && proofTools !== void 0) {
72669
72987
  (deps.prewarmProof ?? ((tools) => setImmediate(() => {
72670
72988
  prewarmP03PaymentProofTools(tools).catch(() => {
@@ -72732,6 +73050,7 @@ async function prepareRecoveredPayment({
72732
73050
  if (deps.quoteMarginSeconds !== void 0 && BigInt(witnessQuote.validBefore) - BigInt(timestamp) < BigInt(deps.quoteMarginSeconds)) {
72733
73051
  fail15("quote_life_short_requote");
72734
73052
  }
73053
+ const poolState2 = walkPoolState(history, chainProgramId, pool2) ?? (deps.recover === void 0 ? readPoolState2(connection, pool2) : void 0);
72735
73054
  const recovery = await (deps.recover ?? runRecover)({
72736
73055
  store,
72737
73056
  connection,
@@ -72993,7 +73312,7 @@ function assertProvedPaymentBinding(proved, { poolDomain, inputAccountCommitment
72993
73312
  fail15("proved_request_binding_invalid");
72994
73313
  }
72995
73314
  }
72996
- var import_web3106, MODEL_DIR3, seedBytes5, EARLY_CHAIN_TIME_MAX_AGE_MS, settledNoteExits;
73315
+ var import_web3106, MODEL_DIR3, seedBytes5, EARLY_CHAIN_TIME_MAX_AGE_MS, settledNoteExits, PROOF_CHAIN_TIME_REUSE_MS, lastClockAnswers;
72997
73316
  var init_prepareRecoveredPayment = __esm({
72998
73317
  "wallet/src/pay/prepareRecoveredPayment.mjs"() {
72999
73318
  "use strict";
@@ -73015,6 +73334,8 @@ var init_prepareRecoveredPayment = __esm({
73015
73334
  seedBytes5 = (state) => Uint8Array.from(Buffer.from(state.seedHex, "hex"));
73016
73335
  EARLY_CHAIN_TIME_MAX_AGE_MS = 3e4;
73017
73336
  settledNoteExits = /* @__PURE__ */ new Map();
73337
+ PROOF_CHAIN_TIME_REUSE_MS = 5e3;
73338
+ lastClockAnswers = /* @__PURE__ */ new WeakMap();
73018
73339
  }
73019
73340
  });
73020
73341
 
@@ -92013,21 +92334,60 @@ function floatOffer({ paymentRequired, store, config }) {
92013
92334
  }
92014
92335
  return { requirement, priceAtomic, feeAtomic, paidAtomic: (BigInt(priceAtomic) + BigInt(feeAtomic)).toString(), config };
92015
92336
  }
92337
+ function walletEta(seedHex) {
92338
+ const key = hash8(`carbon-road/float-eta/v1|${seedHex}`);
92339
+ if (etaEntry?.key === key) return etaEntry.eta;
92340
+ const { eta } = deriveWalletViewingAuthority2({ seedBytes: Uint8Array.from(Buffer.from(seedHex, "hex")), generator: loadPayerGenerator() });
92341
+ etaEntry = { key, eta };
92342
+ return eta;
92343
+ }
92344
+ function warmFloatPay({ store, connection } = {}) {
92345
+ return (async () => {
92346
+ try {
92347
+ const { network, pool: pool2, seedHex } = store.state;
92348
+ const poolKey = `${network}:${pool2}`;
92349
+ const failedAt = poolDomainWarmFailedAt.get(poolKey);
92350
+ const backingOff = failedAt !== void 0 && Date.now() - failedAt < WARM_RETRY_MS;
92351
+ let read;
92352
+ if (connection && !backingOff && poolDomains.get(poolKey) === void 0 && !poolDomainReads.has(poolKey)) {
92353
+ read = (async () => {
92354
+ const state = await readPoolState2(connection, new import_web3109.PublicKey(pool2));
92355
+ if (!state?.poolDomain) throw new Error("pool_unreadable");
92356
+ const poolDomain = BigInt(state.poolDomain);
92357
+ poolDomains.set(poolKey, poolDomain);
92358
+ return poolDomain;
92359
+ })();
92360
+ poolDomainReads.set(poolKey, read);
92361
+ read.then(
92362
+ () => {
92363
+ poolDomainReads.delete(poolKey);
92364
+ poolDomainWarmFailedAt.delete(poolKey);
92365
+ },
92366
+ () => {
92367
+ poolDomainReads.delete(poolKey);
92368
+ poolDomainWarmFailedAt.set(poolKey, Date.now());
92369
+ }
92370
+ );
92371
+ }
92372
+ walletEta(seedHex);
92373
+ await read;
92374
+ } catch {
92375
+ }
92376
+ })();
92377
+ }
92016
92378
  async function ownRefundAddress(store, connection) {
92017
92379
  const poolKey = `${store.state.network}:${store.state.pool}`;
92018
92380
  let poolDomain = poolDomains.get(poolKey);
92381
+ if (poolDomain === void 0 && poolDomainReads.has(poolKey)) {
92382
+ poolDomain = await poolDomainReads.get(poolKey).catch(() => void 0);
92383
+ }
92019
92384
  if (poolDomain === void 0) {
92020
92385
  const pool2 = await readPoolState2(connection, new import_web3109.PublicKey(store.state.pool));
92021
92386
  if (!pool2?.poolDomain) fail18("p03_float_pool_unreadable_retry_same_request");
92022
92387
  poolDomain = BigInt(pool2.poolDomain);
92023
92388
  poolDomains.set(poolKey, poolDomain);
92024
92389
  }
92025
- payerGenerator ??= JSON.parse(readFileSync(fileURLToPath9(new URL(
92026
- "../../vendor/shielded-x402-model/vectors/rust-vectors.json",
92027
- new URL("__bundled_source__/wallet/src/pay/floatPay.mjs", import.meta.url).href
92028
- )), "utf8")).payerKeys.generator;
92029
- const { eta } = deriveWalletViewingAuthority2({ seedBytes: Uint8Array.from(Buffer.from(store.state.seedHex, "hex")), generator: payerGenerator });
92030
- return deriveShieldedSolanaP03Recipient({ eta, poolDomain, resourceNonce: randomBytes11(32) }).payTo;
92390
+ return deriveShieldedSolanaP03Recipient({ eta: walletEta(store.state.seedHex), poolDomain, resourceNonce: randomBytes11(32) }).payTo;
92031
92391
  }
92032
92392
  function canonicalBody({ requestId, resourceUrl, requirement, refundTo }) {
92033
92393
  const opaque = `w-${hash8(`carbon-road/float-request/v1|${requestId}`).slice(0, 40)}`;
@@ -92356,7 +92716,7 @@ function paidResult(record, replayed) {
92356
92716
  float: { floatId: record.floatId }
92357
92717
  };
92358
92718
  }
92359
- var import_web3109, FLOAT_PAYMENT_SCHEMA, REGENERATE_CODES, FLOAT_PAYMENT_WAL_PREFIX, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_SETTLED_AFTER_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, CONFIG_TIMEOUT_MS, CONFIG_CACHE_MS, DECIMAL3, POSITIVE, PENDING_CODES, hash8, fail18, floatPaymentWalName, configCache, poolDomains, payerGenerator, plainText;
92719
+ var import_web3109, FLOAT_PAYMENT_SCHEMA, REGENERATE_CODES, FLOAT_PAYMENT_WAL_PREFIX, FLOAT_CONFIG_SCHEMA, FLOAT_PAY_PATH, MAX_BODY_BYTES, FLOAT_REFUND_ETA_SECONDS, REFUND_SETTLED_AFTER_MS, FINISHING_POLL_MS, FINISHING_LIMIT_MS, SELLER_TIMEOUT_MS, CONFIG_TIMEOUT_MS, CONFIG_CACHE_MS, DECIMAL3, POSITIVE, PENDING_CODES, hash8, fail18, floatPaymentWalName, configCache, poolDomains, poolDomainReads, poolDomainWarmFailedAt, WARM_RETRY_MS, payerGenerator, etaEntry, loadPayerGenerator, plainText;
92360
92720
  var init_floatPay = __esm({
92361
92721
  "wallet/src/pay/floatPay.mjs"() {
92362
92722
  "use strict";
@@ -92396,6 +92756,13 @@ var init_floatPay = __esm({
92396
92756
  floatPaymentWalName = (requestKey) => `${FLOAT_PAYMENT_WAL_PREFIX}${requestKey}`;
92397
92757
  configCache = /* @__PURE__ */ new Map();
92398
92758
  poolDomains = /* @__PURE__ */ new Map();
92759
+ poolDomainReads = /* @__PURE__ */ new Map();
92760
+ poolDomainWarmFailedAt = /* @__PURE__ */ new Map();
92761
+ WARM_RETRY_MS = 3e4;
92762
+ loadPayerGenerator = () => payerGenerator ??= JSON.parse(readFileSync(fileURLToPath9(new URL(
92763
+ "../../vendor/shielded-x402-model/vectors/rust-vectors.json",
92764
+ new URL("__bundled_source__/wallet/src/pay/floatPay.mjs", import.meta.url).href
92765
+ )), "utf8")).payerKeys.generator;
92399
92766
  plainText = (value) => value.replace(/[^ -~]+/g, " ").trim().slice(0, 300);
92400
92767
  }
92401
92768
  });
@@ -92852,6 +93219,22 @@ function writeFinalized(store, name, record, settlement) {
92852
93219
  store.writeWal(name, finalized);
92853
93220
  return finalized;
92854
93221
  }
93222
+ function finalizePendingFromHistory({ store, history, programId, olderThanMs }) {
93223
+ let written = 0;
93224
+ for (const name of store.listWal().filter((entry) => entry.startsWith("resource-payment-"))) {
93225
+ try {
93226
+ const record = readPriorPayment(store, name);
93227
+ if (record === FINAL_UNCHANGED || !isPending(record)) continue;
93228
+ if (olderThanMs !== void 0 && !(Number.isSafeInteger(record.answeredAtMs) && Date.now() - record.answeredAtMs >= olderThanMs)) continue;
93229
+ const settlement = settlementInHistory(history, record.paymentHeader, store.state, programId);
93230
+ if (!settlement) continue;
93231
+ writeFinalized(store, name, record, settlement);
93232
+ written += 1;
93233
+ } catch {
93234
+ }
93235
+ }
93236
+ return written;
93237
+ }
92855
93238
  async function awaitResourceReceiptFinality({
92856
93239
  store,
92857
93240
  connection,
@@ -93203,7 +93586,27 @@ async function payResourceOnce({
93203
93586
  releaseReservation(store, name.slice("resource-payment-".length));
93204
93587
  }
93205
93588
  };
93589
+ let priorHistory;
93206
93590
  try {
93591
+ if (deps.settlePriorBeforeQuote === true && !record && !reconciling) {
93592
+ const answeredLongAgo = (other) => isPending(other) && Number.isSafeInteger(other.answeredAtMs) && Date.now() - other.answeredAtMs >= FINALITY_GATE_SKIP_AFTER_MS;
93593
+ if (others.some((name) => !finalOthers.has(name) && answeredLongAgo(store.readWal(name)))) {
93594
+ try {
93595
+ priorHistory = assertAuthenticatedFinalizedP03History(
93596
+ await withPhaseScope(mark, "prior-walk", () => withRecentWalletHistory(() => finality.walkHistory()))
93597
+ );
93598
+ const settled = finalizePendingFromHistory({
93599
+ store,
93600
+ history: priorHistory,
93601
+ programId,
93602
+ olderThanMs: FINALITY_GATE_SKIP_AFTER_MS
93603
+ });
93604
+ mark("prior-finality-settled-from-walk", String(settled));
93605
+ } catch {
93606
+ priorHistory = void 0;
93607
+ }
93608
+ }
93609
+ }
93207
93610
  for (const name of others) {
93208
93611
  if (reconciling) break;
93209
93612
  if (finalOthers.has(name)) continue;
@@ -93240,7 +93643,11 @@ async function payResourceOnce({
93240
93643
  serviceUrl: serviceUrl2,
93241
93644
  reservedReplayValues: held,
93242
93645
  amountAtomic: maximumAtomic,
93243
- deps: { fetchImpl: deps.fetchImpl, walkHistory: finality.walkHistory }
93646
+ // The report read above when there is one (the prewarm is taken once).
93647
+ deps: {
93648
+ fetchImpl: deps.fetchImpl,
93649
+ walkHistory: priorHistory !== void 0 ? async () => priorHistory : finality.walkHistory
93650
+ }
93244
93651
  }));
93245
93652
  } catch {
93246
93653
  first = false;
@@ -94953,13 +95360,26 @@ var init_EncryptedJsonFile = __esm({
94953
95360
  * one value under one key encrypt it once (the P03 settle journal).
94954
95361
  */
94955
95362
  async writeText(payload2) {
95363
+ await this.writeTextStamped(payload2);
95364
+ return payload2;
95365
+ }
95366
+ /**
95367
+ * writeText() that returns the written file's `ino:size:mtimeNs`, read by
95368
+ * fstat on the fsynced temporary file before the rename (a rename keeps all
95369
+ * three), so a file another writer renames in later can never carry this
95370
+ * write's stamp. Undefined when the file is not durable (no fsync handle).
95371
+ */
95372
+ async writeTextStamped(payload2) {
94956
95373
  await mkdir3(dirname18(this.filePath), { recursive: true });
94957
95374
  const temporaryPath = `${this.filePath}.${process.pid}.${randomBytes16(6).toString("hex")}.tmp`;
94958
95375
  await writeFile2(temporaryPath, payload2, { mode: 384 });
95376
+ let stamp;
94959
95377
  if (this.options.durable) {
94960
95378
  const temporary = await open2(temporaryPath, "r+");
94961
95379
  try {
94962
95380
  await temporary.sync();
95381
+ const stats = await temporary.stat({ bigint: true });
95382
+ stamp = `${stats.ino}:${stats.size}:${stats.mtimeNs}`;
94963
95383
  } finally {
94964
95384
  await temporary.close();
94965
95385
  }
@@ -94978,7 +95398,7 @@ var init_EncryptedJsonFile = __esm({
94978
95398
  }
94979
95399
  }
94980
95400
  this.migratedPlaintext = false;
94981
- return payload2;
95401
+ return stamp;
94982
95402
  }
94983
95403
  shouldRewriteEncrypted() {
94984
95404
  return this.encrypted && this.migratedPlaintext;
@@ -96657,8 +97077,7 @@ function createMemoEcdhWorker(options) {
96657
97077
  if (job !== void 0) jobs.push(job);
96658
97078
  }
96659
97079
  if (jobs.length === 0) return void 0;
96660
- const result = Promise.all(jobs.map((job) => job.result)).then((parts) => parts.flatMap((part) => part ?? [])).catch(() => void 0);
96661
- return { result, cancel: () => {
97080
+ return { parts: jobs.map((job) => job.result), cancel: () => {
96662
97081
  for (const job of jobs) job.cancel();
96663
97082
  } };
96664
97083
  };
@@ -97502,14 +97921,14 @@ async function createSellerAdapter({
97502
97921
  if (job !== void 0) {
97503
97922
  precomputesRunning += 1;
97504
97923
  owned.cancel = job.cancel;
97505
- precomputed = job.result.then((entries) => {
97924
+ precomputed = Promise.all(job.parts.map((part) => part.then((entries) => {
97506
97925
  if (entries === void 0 || owned.done) return;
97507
97926
  for (const [key, sharedX] of entries) {
97508
97927
  if (sharedXByPoint.has(key)) continue;
97509
97928
  sharedXByPoint.set(key, sharedX);
97510
97929
  owned.keys.push(key);
97511
97930
  }
97512
- }).catch(() => void 0).finally(() => {
97931
+ }).catch(() => void 0))).finally(() => {
97513
97932
  precomputesRunning -= 1;
97514
97933
  });
97515
97934
  }
@@ -119444,7 +119863,10 @@ async function payAndFetch(session, url, init = {}, opts = {}) {
119444
119863
  let price;
119445
119864
  let challenge3;
119446
119865
  if (!rerun) {
119447
- if (store !== void 0) startHistoryPrewarm(session, store, mark);
119866
+ if (store !== void 0) {
119867
+ startHistoryPrewarm(session, store, mark);
119868
+ warmFloatPay({ store, connection: session.connection });
119869
+ }
119448
119870
  const response = await unpaidRequest(target, () => keepAliveInit({
119449
119871
  method,
119450
119872
  headers,
@@ -121139,6 +121561,7 @@ function combinePoolBalances(partsAtomic, movingAtomic2 = "0") {
121139
121561
 
121140
121562
  // wallet/src/mcp/tools.mjs
121141
121563
  init_recover();
121564
+ init_recoveryPath();
121142
121565
  init_walk();
121143
121566
  init_payResource();
121144
121567
  init_floatPay();
@@ -123278,7 +123701,7 @@ function moveBody({ amountAtomic, refundTo, fromPool, n, toPool }) {
123278
123701
  const bodyText = `{"amountAtomic":${JSON.stringify(amountAtomic)},"refundTo":${JSON.stringify(refundTo)},"requestId":${JSON.stringify(requestId)},"toPool":${JSON.stringify(toPool)}}`;
123279
123702
  return { bodyText, moveId: hash10(bodyText) };
123280
123703
  }
123281
- function walletEta(store) {
123704
+ function walletEta2(store) {
123282
123705
  const generator2 = JSON.parse(readFileSync(fileURLToPath15(new URL(
123283
123706
  "../../vendor/shielded-x402-model/vectors/rust-vectors.json",
123284
123707
  new URL("__bundled_source__/wallet/src/move/job.mjs", import.meta.url).href
@@ -123561,7 +123984,7 @@ async function runMove({
123561
123984
  return answer("done", void 0, { ...base, ...dust });
123562
123985
  }
123563
123986
  const n = moveLegs(store, from.pool).reduce((high, entry) => Math.max(high, entry.n), 0) + 1;
123564
- const refundTo = ownTargetAddress(walletEta(open3(targetPath, passphrase2)), to.poolDomain);
123987
+ const refundTo = ownTargetAddress(walletEta2(open3(targetPath, passphrase2)), to.poolDomain);
123565
123988
  const { bodyText, moveId } = moveBody({ amountAtomic: plan.leg.amountAtomic, refundTo, fromPool: from.pool, n, toPool: to.pool });
123566
123989
  leg = {
123567
123990
  schema: MOVE_WAL_SCHEMA,
@@ -126902,6 +127325,7 @@ async function refreshWallet({ session, store, history: walked, share }) {
126902
127325
  }
126903
127326
  });
126904
127327
  assertAuthenticatedFinalizedP03History(history);
127328
+ finalizePendingFromHistory({ store, history, programId: session.programId });
126905
127329
  const snapshot = snapshotFromRecovery({
126906
127330
  state: store.state,
126907
127331
  programId: session.programId,
@@ -126913,6 +127337,8 @@ async function refreshWallet({ session, store, history: walked, share }) {
126913
127337
  });
126914
127338
  writeBalanceSnapshot(store, snapshot);
126915
127339
  returnArrivedFloatRefundBudgets(store, snapshot);
127340
+ prepareFinalizedP03RecoveryFold(history).catch(() => {
127341
+ });
126916
127342
  }
126917
127343
  function shieldedUnknown(store) {
126918
127344
  return computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local" }).split?.shieldedAtomic == null;
@@ -127442,12 +127868,15 @@ function createWalletTools({
127442
127868
  runDeferredRefresh();
127443
127869
  });
127444
127870
  }
127445
- async function refreshIfStale() {
127871
+ async function refreshIfStale(onPhase = () => {
127872
+ }) {
127446
127873
  let stale;
127447
127874
  try {
127448
127875
  stale = shieldedUnknown(session.openStore());
127449
127876
  } catch {
127450
127877
  return;
127878
+ } finally {
127879
+ onPhase("mcp-stale-read");
127451
127880
  }
127452
127881
  if (!stale || refreshFailedAt && Date.now() - refreshFailedAt < REFRESH_RETRY_MS) return;
127453
127882
  if (finalityWait || refreshRun && refreshInBackground) return;
@@ -127629,13 +128058,16 @@ function createWalletTools({
127629
128058
  return refuse9("mcp_argument_invalid", "request_id must be 1-128 characters of A-Z a-z 0-9 . _ : -", "leave request_id out for a new payment");
127630
128059
  }
127631
128060
  knownIds.set(sha256Hex2(Buffer.from(requestId, "utf8")), requestId);
128061
+ const gateTimes = [["mcp-args", Date.now()]];
127632
128062
  const pocketRequest = { requestId, url: target.url, method: request.method, headers: request.headers, body: request.body };
127633
128063
  const early = autoPockets.beforePay(pocketRequest);
127634
128064
  if (early) {
127635
128065
  const one2 = localBalance(session);
127636
128066
  return json({ ...early, ...one2 ? { balanceAtomic: one2.balanceAtomic, balance: one2.balance, breakdown: { ...one2.breakdown, ...early.breakdown ?? {} } } : {} });
127637
128067
  }
127638
- await refreshIfStale();
128068
+ gateTimes.push(["mcp-pockets", Date.now()]);
128069
+ await refreshIfStale((phase) => gateTimes.push([phase, Date.now()]));
128070
+ gateTimes.push(["mcp-refresh", Date.now()]);
127639
128071
  const switched = await switchGate(cap.maxPaymentAtomic, requestId, "x402_pay");
127640
128072
  if (switched) return switched;
127641
128073
  let timing;
@@ -127644,12 +128076,13 @@ function createWalletTools({
127644
128076
  } catch {
127645
128077
  timing = void 0;
127646
128078
  }
127647
- const mark = (phase) => {
128079
+ const mark = (phase, at) => {
127648
128080
  try {
127649
- timing?.(phase);
128081
+ timing?.(phase, void 0, at);
127650
128082
  } catch {
127651
128083
  }
127652
128084
  };
128085
+ for (const [phase, at] of gateTimes) mark(phase, at);
127653
128086
  mark("mcp-gates");
127654
128087
  const payOnce = async () => {
127655
128088
  const end = autoPockets.paymentStart();