shinjuku-shielded 0.3.45 → 0.3.46

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": "54ae7e6525d0c2a5330f3243891a2cbc5d728a4bcea81a61ba3aaf065bed8b63",
5
- "bytes": 11266570,
6
- "sourceCommit": "f4f870fa4e4b3f57cc4dfdb472b75e5a3fef8db2",
4
+ "sha256": "fe90fa0a418682c08b49b05bcda64ffd7b6cf8803166f95968205c80a2fcab4b",
5
+ "bytes": 11282021,
6
+ "sourceCommit": "4664c1b8a728712acc576493a6cabb03ccbe4167",
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.45",
3
+ "version": "0.3.46",
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": "54ae7e65",
7
- "shinjukuSha256": "54ae7e6525d0c2a5330f3243891a2cbc5d728a4bcea81a61ba3aaf065bed8b63",
6
+ "shinjukuRelease": "fe90fa0a",
7
+ "shinjukuSha256": "fe90fa0a418682c08b49b05bcda64ffd7b6cf8803166f95968205c80a2fcab4b",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -48326,6 +48326,9 @@ function encryptJson(key, value) {
48326
48326
  return { nonceHex: nonce.toString("hex"), tagHex: cipher.getAuthTag().toString("hex"), ciphertextHex: ciphertext.toString("hex") };
48327
48327
  }
48328
48328
  function decryptJson(key, envelope, label) {
48329
+ return decryptJsonText(key, envelope, label).value;
48330
+ }
48331
+ function decryptJsonText(key, envelope, label) {
48329
48332
  try {
48330
48333
  const decipher = createDecipheriv(
48331
48334
  "aes-256-gcm",
@@ -48337,7 +48340,8 @@ function decryptJson(key, envelope, label) {
48337
48340
  decipher.update(Buffer.from(envelope.ciphertextHex, "hex")),
48338
48341
  decipher.final()
48339
48342
  ]);
48340
- return JSON.parse(plaintext.toString("utf8"));
48343
+ const text3 = plaintext.toString("utf8");
48344
+ return { text: text3, value: JSON.parse(text3) };
48341
48345
  } catch {
48342
48346
  throw new WalletStoreError(`${label}_decrypt_failed`);
48343
48347
  }
@@ -48409,6 +48413,9 @@ function writeEnvelope(path, key, schema, value) {
48409
48413
  `, "utf8"));
48410
48414
  }
48411
48415
  function readWalEnvelope(path, key) {
48416
+ return readWalEnvelopeText(path, key).value;
48417
+ }
48418
+ function readWalEnvelopeText(path, key) {
48412
48419
  let envelope;
48413
48420
  try {
48414
48421
  envelope = JSON.parse(readFileSync(path, "utf8"));
@@ -48416,7 +48423,51 @@ function readWalEnvelope(path, key) {
48416
48423
  throw new WalletStoreError("wallet_wal_unreadable");
48417
48424
  }
48418
48425
  if (envelope?.schema !== WAL_SCHEMA) throw new WalletStoreError("wallet_wal_schema_invalid");
48419
- return decryptJson(key, envelope, "wallet_wal");
48426
+ return { ...decryptJsonText(key, envelope, "wallet_wal"), sealId: `${envelope.nonceHex}:${envelope.tagHex}` };
48427
+ }
48428
+ function walSealOf(path) {
48429
+ const head = Buffer.alloc(WAL_SEAL_HEAD_BYTES);
48430
+ let length;
48431
+ const fd = openSync(path, "r");
48432
+ try {
48433
+ length = readSync(fd, head, 0, WAL_SEAL_HEAD_BYTES, 0);
48434
+ } finally {
48435
+ closeSync(fd);
48436
+ }
48437
+ const text3 = head.subarray(0, length).toString("utf8");
48438
+ if (!text3.startsWith(WAL_SEAL_PREFIX)) return void 0;
48439
+ const match = WAL_SEAL_REST.exec(text3.slice(WAL_SEAL_PREFIX.length));
48440
+ return match ? `${match[1]}:${match[2]}` : void 0;
48441
+ }
48442
+ function readWalCached(path, key) {
48443
+ const byPath = walPlaintextsOf(key);
48444
+ let statId;
48445
+ try {
48446
+ statId = walStatId(path);
48447
+ } catch (error) {
48448
+ if (error?.code === "ENOENT") {
48449
+ byPath.delete(path);
48450
+ return void 0;
48451
+ }
48452
+ statId = void 0;
48453
+ }
48454
+ const cached = statId === void 0 ? void 0 : byPath.get(path);
48455
+ if (cached !== void 0 && cached.statId === statId) {
48456
+ let seal;
48457
+ try {
48458
+ seal = walSealOf(path);
48459
+ } catch {
48460
+ seal = void 0;
48461
+ }
48462
+ if (seal !== void 0 && seal === cached.sealId) return JSON.parse(cached.text);
48463
+ }
48464
+ byPath.delete(path);
48465
+ const read = readWalEnvelopeText(path, key);
48466
+ if (statId !== void 0) {
48467
+ if (byPath.size >= WAL_PLAINTEXTS_PER_KEY) byPath.delete(byPath.keys().next().value);
48468
+ byPath.set(path, { statId, sealId: read.sealId, text: read.text });
48469
+ }
48470
+ return read.value;
48420
48471
  }
48421
48472
  function walNames(directory) {
48422
48473
  return readdirSync(directory).filter((name) => name.endsWith(".json") && name !== WAL_OWNER_FILE).map((name) => {
@@ -48564,29 +48615,45 @@ function openWalletStore(path, passphrase2) {
48564
48615
  writeWal(name, record) {
48565
48616
  assertWalName(name);
48566
48617
  bindWalDirectory(walDirectory, key);
48567
- writeEnvelope(join3(walDirectory, `${name}.json`), key, WAL_SCHEMA, record);
48618
+ const walPath = join3(walDirectory, `${name}.json`);
48619
+ walPlaintextsOf(key).delete(walPath);
48620
+ try {
48621
+ writeEnvelope(walPath, key, WAL_SCHEMA, record);
48622
+ } finally {
48623
+ walPlaintextsOf(key).delete(walPath);
48624
+ }
48568
48625
  },
48569
48626
  readWal(name) {
48570
48627
  assertWalName(name);
48571
48628
  bindWalDirectory(walDirectory, key);
48572
48629
  const walPath = join3(walDirectory, `${name}.json`);
48573
- if (!existsSync(walPath)) return void 0;
48574
- return readWalEnvelope(walPath, key);
48630
+ if (name.startsWith(WAL_UNCACHED_PREFIX)) {
48631
+ if (!existsSync(walPath)) return void 0;
48632
+ return readWalEnvelope(walPath, key);
48633
+ }
48634
+ return readWalCached(walPath, key);
48575
48635
  },
48576
48636
  listWal() {
48577
48637
  bindWalDirectory(walDirectory, key);
48578
- return walNames(walDirectory);
48638
+ const names = walNames(walDirectory);
48639
+ const byPath = walPlaintextsOf(key);
48640
+ if (byPath.size > 0) {
48641
+ const listed = new Set(names.map((name) => join3(walDirectory, `${name}.json`)));
48642
+ for (const path2 of byPath.keys()) if (dirname2(path2) === walDirectory && !listed.has(path2)) byPath.delete(path2);
48643
+ }
48644
+ return names;
48579
48645
  },
48580
48646
  removeWal(name) {
48581
48647
  assertWalName(name);
48582
48648
  bindWalDirectory(walDirectory, key);
48583
48649
  const walPath = join3(walDirectory, `${name}.json`);
48650
+ walPlaintextsOf(key).delete(walPath);
48584
48651
  if (existsSync(walPath)) unlinkSync(walPath);
48585
48652
  }
48586
48653
  };
48587
48654
  return store;
48588
48655
  }
48589
- var STORE_SCHEMA, WAL_SCHEMA, SCRYPT, WAL_OWNER_FILE, WAL_OWNER_SCHEMA, WalletStoreError, KEY_CACHE_LIMIT, keyCacheSecret, keyCache, keyStats, keyCacheId, rememberKey, verifiedWalOwners, ownerStatId, assertPassphrase, assertWalName;
48656
+ var STORE_SCHEMA, WAL_SCHEMA, SCRYPT, WAL_OWNER_FILE, WAL_OWNER_SCHEMA, WalletStoreError, KEY_CACHE_LIMIT, keyCacheSecret, keyCache, keyStats, keyCacheId, rememberKey, walPlaintexts, WAL_PLAINTEXTS_PER_KEY, WAL_UNCACHED_PREFIX, WAL_SEAL_HEAD_BYTES, WAL_SEAL_PREFIX, WAL_SEAL_REST, walStatIdForTests, walStatId, walPlaintextsOf, verifiedWalOwners, ownerStatId, assertPassphrase, assertWalName;
48590
48657
  var init_store = __esm({
48591
48658
  "wallet/src/store/store.mjs"() {
48592
48659
  "use strict";
@@ -48612,6 +48679,24 @@ var init_store = __esm({
48612
48679
  keyCache.set(id, key);
48613
48680
  while (keyCache.size > KEY_CACHE_LIMIT) keyCache.delete(keyCache.keys().next().value);
48614
48681
  };
48682
+ walPlaintexts = /* @__PURE__ */ new WeakMap();
48683
+ WAL_PLAINTEXTS_PER_KEY = 4096;
48684
+ WAL_UNCACHED_PREFIX = "resource-proof-";
48685
+ WAL_SEAL_HEAD_BYTES = 512;
48686
+ WAL_SEAL_PREFIX = `{
48687
+ "schema": ${JSON.stringify(WAL_SCHEMA)},
48688
+ "nonceHex": "`;
48689
+ WAL_SEAL_REST = /^([0-9a-f]{24})",\n "tagHex": "([0-9a-f]{32})",\n/;
48690
+ walStatId = (path) => {
48691
+ if (walStatIdForTests) return walStatIdForTests(path);
48692
+ const stat = statSync(path, { bigint: true });
48693
+ return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
48694
+ };
48695
+ walPlaintextsOf = (key) => {
48696
+ let byPath = walPlaintexts.get(key);
48697
+ if (!byPath) walPlaintexts.set(key, byPath = /* @__PURE__ */ new Map());
48698
+ return byPath;
48699
+ };
48615
48700
  verifiedWalOwners = /* @__PURE__ */ new WeakMap();
48616
48701
  ownerStatId = (path) => {
48617
48702
  const stat = statSync(path, { bigint: true });
@@ -49274,6 +49359,7 @@ function keepAliveDispatcher() {
49274
49359
  const global2 = globalThis[GLOBAL_DISPATCHER];
49275
49360
  if (global2?.constructor?.name !== "Agent") return void 0;
49276
49361
  shared = new global2.constructor({ keepAliveTimeout: KEEP_ALIVE_MS, keepAliveMaxTimeout: KEEP_ALIVE_MS });
49362
+ shared.on?.("connect", () => markPhase("socket-new"));
49277
49363
  return shared;
49278
49364
  } catch {
49279
49365
  return void 0;
@@ -49287,6 +49373,7 @@ var GLOBAL_DISPATCHER, KEEP_ALIVE_MS, shared;
49287
49373
  var init_keepAlive = __esm({
49288
49374
  "wallet/src/fetch/keepAlive.mjs"() {
49289
49375
  "use strict";
49376
+ init_phaseTiming();
49290
49377
  GLOBAL_DISPATCHER = /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1");
49291
49378
  KEEP_ALIVE_MS = 2e4;
49292
49379
  }
@@ -50129,7 +50216,8 @@ function connectSplit(own, historyUrl, commitment = "finalized", { pause: pause3
50129
50216
  const counts = Object.freeze({
50130
50217
  history: Object.fromEntries([...HISTORY_RPC_METHODS, "getTransactions"].map((name) => [name, 0])),
50131
50218
  // getTransaction here counts crossCheck's reads only; the walk's own getTransaction always goes to the history source.
50132
- own: Object.fromEntries([...ownRouted, "getTransaction"].map((name) => [name, 0])),
50219
+ // getSignaturesForAddress here counts the reads asked through historyRpcOwnConnection only.
50220
+ own: Object.fromEntries([...ownRouted, "getTransaction", "getSignaturesForAddress"].map((name) => [name, 0])),
50133
50221
  // signaturesVerified: history-source transactions whose Ed25519 signatures
50134
50222
  // verified (verifiedTransaction); crossChecked: served transactions the
50135
50223
  // own RPC read again and found equal (crossCheck).
@@ -50293,6 +50381,19 @@ function connectSplit(own, historyUrl, commitment = "finalized", { pause: pause3
50293
50381
  get: () => (counts.history[name] ?? 0) + (counts.own[name] ?? 0),
50294
50382
  enumerable: true
50295
50383
  }])));
50384
+ const ownCounted = new Proxy(own, {
50385
+ get(target, property) {
50386
+ const value = Reflect.get(target, property);
50387
+ if (typeof value !== "function") return value;
50388
+ if (Object.hasOwn(counts.own, property)) {
50389
+ return (...args) => {
50390
+ counts.own[property] += 1;
50391
+ return value.apply(target, args);
50392
+ };
50393
+ }
50394
+ return value.bind(target);
50395
+ }
50396
+ });
50296
50397
  const crossCheck = async ({ count: count2 = HISTORY_CROSS_CHECK_COUNT } = {}) => {
50297
50398
  const eligible = [...served.keys()];
50298
50399
  const picks = Math.min(count2, eligible.length);
@@ -50341,6 +50442,7 @@ function connectSplit(own, historyUrl, commitment = "finalized", { pause: pause3
50341
50442
  if (property === "historyRpcIntegrity") return historyRpcIntegrity;
50342
50443
  if (property === "historyRpcWarm") return historyRpcWarm;
50343
50444
  if (property === "historyRpcSource") return history;
50445
+ if (property === "historyRpcOwnConnection") return ownCounted;
50344
50446
  const value = Reflect.get(target, property);
50345
50447
  return typeof value === "function" ? value.bind(target) : value;
50346
50448
  }
@@ -50983,7 +51085,13 @@ function createCompactHistoryCacheStore({ path, hmacKey, now }) {
50983
51085
  // 2026-10-16: the append root after each served record (hex, count 1..n) and the empty
50984
51086
  // tree's root, a fold hint for a new process (compact.mjs hintCompactFold). Optional: an
50985
51087
  // 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] } } : {}
51088
+ // `unverified`: some roots were reused from an earlier file and not hashed again by the
51089
+ // process that wrote this one (a new process then folds them itself; hintCompactFold).
51090
+ ...state.foldRoots ? { foldRoots: {
51091
+ zero: state.foldRoots.zero,
51092
+ roots: [...state.foldRoots.roots],
51093
+ ...state.foldRoots.unverified === true ? { unverified: true } : {}
51094
+ } } : {}
50987
51095
  }),
50988
51096
  deserialize: (value) => {
50989
51097
  const init = value?.initialization;
@@ -51006,7 +51114,11 @@ function createCompactHistoryCacheStore({ path, hmacKey, now }) {
51006
51114
  }),
51007
51115
  ...value.attestation === void 0 ? {} : { attestation: deserializeAttestation(value.attestation) },
51008
51116
  // 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] } } : {}
51117
+ ...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: {
51118
+ zero: value.foldRoots.zero,
51119
+ roots: [...value.foldRoots.roots],
51120
+ ...value.foldRoots.unverified === true ? { unverified: true } : {}
51121
+ } } : {}
51010
51122
  };
51011
51123
  }
51012
51124
  });
@@ -53100,7 +53212,12 @@ async function programDataCoverageFor({
53100
53212
  onFullAttestation,
53101
53213
  // Called before the two reads are asked once more after a transport failure or a timeout
53102
53214
  // (compact.mjs: a new Tor circuit). Absent: no second try.
53103
- onReuseRetry
53215
+ onReuseRetry,
53216
+ // The connection for the two reuse reads ONLY (compact.mjs: the split's own RPC, bounded),
53217
+ // so one RPC answers both, at or after snapshotSlot, with no history-source floor below it
53218
+ // (2026-10-16 c1s: the signature read on the proxy cost a -32016 retry, about 0.2 s).
53219
+ // The full attestation and its newest signature keep `connection`. Absent: `connection`.
53220
+ reuseConnection = connection
53104
53221
  }) {
53105
53222
  if (deploymentIdentity === void 0) return { coverage: void 0, attestation: void 0, reused: false };
53106
53223
  let priorRefused = false;
@@ -53112,12 +53229,12 @@ async function programDataCoverageFor({
53112
53229
  try {
53113
53230
  const [, newest2] = await Promise.all([
53114
53231
  readProgramDataHeader({
53115
- connection,
53232
+ connection: reuseConnection,
53116
53233
  address: address5,
53117
53234
  snapshotSlot,
53118
53235
  deployedAtSlot: BigInt(prior.coverage.deployedAtSlot)
53119
53236
  }),
53120
- newestSignature(connection, address5, snapshotSlot)
53237
+ newestSignature(reuseConnection, address5, snapshotSlot)
53121
53238
  ]);
53122
53239
  if (newest2.signature === prior.newestSignature) {
53123
53240
  const coverage2 = Object.freeze({ ...prior.coverage, throughFinalizedSlot: BigInt(snapshotSlot) });
@@ -55311,6 +55428,10 @@ function foldCompactLeavesReusing(pool2, leaves, counts, { frontier, fresh = /*
55311
55428
  function hintCompactFold(pool2, hint) {
55312
55429
  if (lastFolds.has(pool2) || droppedPools.has(pool2) || !hint || !Array.isArray(hint.records) || !hint.foldRoots) return false;
55313
55430
  const { records, foldRoots } = hint;
55431
+ if (foldRoots.unverified === true) {
55432
+ markPhase("compact-roots-unverified");
55433
+ return false;
55434
+ }
55314
55435
  if (!Array.isArray(foldRoots.roots) || foldRoots.roots.length === 0 || foldRoots.roots.length !== records.length || foldRoots.zero !== hex64(zeroRoots()[OUTER_DEPTH2])) return false;
55315
55436
  const field4 = (value) => {
55316
55437
  if (typeof value !== "string" || !HEX64.test(value)) return void 0;
@@ -55334,15 +55455,31 @@ function dropCachedFoldRoots(pool2, cache) {
55334
55455
  droppedPools.add(pool2);
55335
55456
  lastFolds.delete(pool2);
55336
55457
  dropRecoveryFold();
55458
+ rewriteFoldRoots(pool2, cache, () => void 0);
55459
+ }
55460
+ function rewriteFoldRoots(pool2, cache, next) {
55337
55461
  if (cache === void 0) return;
55338
55462
  (async () => {
55339
55463
  const current = await cache.load();
55340
55464
  if (!current || current.pool !== pool2 || current.foldRoots === void 0) return;
55341
- const { foldRoots: _dropped, savedAt, ...rest } = current;
55342
- await cache.save(rest, { savedAt });
55465
+ const { foldRoots, savedAt, ...rest } = current;
55466
+ const replaced = next(foldRoots);
55467
+ if (replaced === foldRoots) return;
55468
+ await cache.save({ ...rest, ...replaced === void 0 ? {} : { foldRoots: replaced } }, { savedAt });
55343
55469
  })().catch(() => {
55344
55470
  });
55345
55471
  }
55472
+ function markFoldRootsVerified(pool2, cache) {
55473
+ rewriteFoldRoots(pool2, cache, (foldRoots) => {
55474
+ const hashed = lastFolds.get(pool2);
55475
+ if (foldRoots.unverified !== true || droppedPools.has(pool2) || hashed === void 0 || hashed.tainted) return foldRoots;
55476
+ const every = foldRoots.roots.every((root, at) => {
55477
+ const own = hashed.roots.get(at + 1);
55478
+ return own !== void 0 && hex64(own) === root;
55479
+ });
55480
+ return every ? { zero: foldRoots.zero, roots: foldRoots.roots } : foldRoots;
55481
+ });
55482
+ }
55346
55483
  function startCachedRootsVerify({ pool: pool2, leaves, cachedRoots, cache }) {
55347
55484
  if (verifying.has(pool2) || cachedRoots.size === 0) return;
55348
55485
  verifying.add(pool2);
@@ -55350,7 +55487,8 @@ function startCachedRootsVerify({ pool: pool2, leaves, cachedRoots, cache }) {
55350
55487
  }).finally(() => verifying.delete(pool2));
55351
55488
  }
55352
55489
  async function verifyCachedRoots({ pool: pool2, leaves, cachedRoots, cache }) {
55353
- const last = Math.max(...cachedRoots.keys());
55490
+ let last = 0;
55491
+ for (const at of cachedRoots.keys()) if (at > last) last = at;
55354
55492
  if (last > leaves.length) return;
55355
55493
  let sliceStart = 0;
55356
55494
  const quiet = async () => {
@@ -55379,6 +55517,7 @@ async function verifyCachedRoots({ pool: pool2, leaves, cachedRoots, cache }) {
55379
55517
  }
55380
55518
  forgetCachedFoldRoots(pool2, cachedRoots);
55381
55519
  markPhase("compact-roots-verified");
55520
+ markFoldRootsVerified(pool2, cache);
55382
55521
  }
55383
55522
  function fieldOf(hex4) {
55384
55523
  if (typeof hex4 !== "string" || !HEX64.test(hex4)) throw refuse3("p03_compact_history_record_invalid");
@@ -55605,9 +55744,7 @@ async function readPages(history, pool2, needed, first, { wakeSlot } = {}) {
55605
55744
  throw Object.assign(refuse3("p03_compact_history_source_refused"), { cause: response.error });
55606
55745
  }
55607
55746
  const result = response?.result;
55608
- if (!result || typeof result !== "object" || result.pool !== pool2 || result.fromOrdinal !== from || !isIndex(result.total) || !isIndex(result.syncedSlot) || !Array.isArray(result.records) || result.records.length !== Math.max(0, Math.min(result.total, from + P03_COMPACT_PAGE) - from) || !result.initialization || !isSignature(result.initialization.signature) || !isIndex(result.initialization.slot)) {
55609
- throw refuse3("p03_compact_history_source_answer_invalid");
55610
- }
55747
+ if (!pageShapeValid(result, pool2, from)) throw refuse3("p03_compact_history_source_answer_invalid");
55611
55748
  if (initialization !== void 0 && (result.initialization.signature !== initialization.signature || result.initialization.slot !== initialization.slot || result.syncedSlot < syncedSlot)) {
55612
55749
  throw refuse3("p03_compact_history_source_answer_invalid");
55613
55750
  }
@@ -55637,6 +55774,25 @@ async function readPages(history, pool2, needed, first, { wakeSlot } = {}) {
55637
55774
  }
55638
55775
  return { records: records.slice(0, needed), imports, initialization, syncedSlot };
55639
55776
  }
55777
+ async function readCompactPoolSnapshot({ connection, programId, pool: pool2 }) {
55778
+ return readFinalizedPool(withBoundedOwnReads(connection), new import_web397.PublicKey(programId), new import_web397.PublicKey(pool2));
55779
+ }
55780
+ function pageShapeValid(result, pool2, from) {
55781
+ return Boolean(result) && typeof result === "object" && result.pool === pool2 && result.fromOrdinal === from && isIndex(result.total) && isIndex(result.syncedSlot) && Array.isArray(result.records) && result.records.length === Math.max(0, Math.min(result.total, from + P03_COMPACT_PAGE) - from) && Boolean(result.initialization) && isSignature(result.initialization.signature) && isIndex(result.initialization.slot);
55782
+ }
55783
+ function isCompactPageZeroAnswer(response, pool2) {
55784
+ if (response === null || typeof response !== "object" || "error" in response) return false;
55785
+ const result = response.result;
55786
+ if (!pageShapeValid(result, pool2, 0)) return false;
55787
+ if (result.imports === void 0) return true;
55788
+ if (!Array.isArray(result.imports)) return false;
55789
+ try {
55790
+ for (const entry of result.imports) validateImport(entry, 0);
55791
+ return true;
55792
+ } catch {
55793
+ return false;
55794
+ }
55795
+ }
55640
55796
  function splitWire(bytes2) {
55641
55797
  if (bytes2.length < 2) throw refuse3("p03_compact_history_spot_check_invalid");
55642
55798
  if (bytes2[0] === VERSION_1_PREFIX2) {
@@ -55865,14 +56021,26 @@ async function readCompactP03HistoryNow({
55865
56021
  initialization: knownInitialization,
55866
56022
  // walletHistory.mjs: the pool's current index that a refresh read on this same own RPC moments
55867
56023
  // ago and refused as moved (p03_history_refresh_transition_detected carries it; that read held
55868
- // only the tree's header). The page request starts at once, beside the pool account read below,
55869
- // unless the cached records already reach that index.
56024
+ // only the tree's header), or, after a payment took this run's last report, that report's index
56025
+ // plus one subtree (its own settle moved the pool; refresh-skipped-own-pay). A hint only: the page
56026
+ // request starts at once, beside the pool account read below, unless the cached records already
56027
+ // reach that index. No check uses it; the pool account read below decides the count.
55870
56028
  knownIndex,
55871
56029
  // walletHistory.mjs compactFirst: the full pool account (readFinalizedPool, tree included) that
55872
56030
  // an earlier try of this same load read and folded nothing to because the source was behind
55873
56031
  // (p03_compact_history_source_behind carries it as behindSnapshot). Folded to again instead of
55874
56032
  // a second read of the pool account and its 386 KB tree; every check below runs on it as before.
55875
56033
  knownSnapshot,
56034
+ // walletHistory.mjs compactFirst, with knownSnapshot only: the answer ({ response }) of the read that
56035
+ // ended the behind wait, a full page 0 asked with minContextSlot = knownSnapshot.slot
56036
+ // (waitForCompactSource). It is page 0 here instead of a second request for it; readPages checks
56037
+ // it exactly as any page. Without knownSnapshot it is ignored.
56038
+ knownFirst,
56039
+ // walletHistory.mjs loadWalletP03HistoryNow, through compactFirst's first try only: the promise of
56040
+ // readCompactPoolSnapshot started beside a refresh that then missed. It is this read's pool account
56041
+ // read (the same finalized read and parse; every check below runs on it as before); when it failed,
56042
+ // the pool account is read here as before. Ignored with knownSnapshot.
56043
+ poolPreRead,
55876
56044
  // compactP03HistoryReport: run beside the spot checks once the initialization is verified
55877
56045
  // ({ snapshot, initialization, contexts }); its result comes back as `alongside`.
55878
56046
  alongside,
@@ -55896,22 +56064,36 @@ async function readCompactP03HistoryNow({
55896
56064
  own = withBoundedOwnReads(own);
55897
56065
  const hintIndex = knownSnapshot?.currentIndex ?? knownIndex;
55898
56066
  const cachedReachesKnown = hintIndex !== void 0 && served !== void 0 && Array.isArray(served.records) && Boolean(served.initialization) && BigInt(served.records.length) * SUBTREE_LEAVES3 >= hintIndex;
55899
- const first = served === void 0 || hintIndex !== void 0 && !cachedReachesKnown ? requestPage(source, poolString, 0) : void 0;
55900
- if (first !== void 0) markPhase("compact-page0-sent");
55901
- const snapshot = knownSnapshot ?? await readFinalizedPool(own, program, poolKey);
56067
+ const reusedFirst = knownSnapshot !== void 0 && knownFirst !== void 0 ? knownFirst : void 0;
56068
+ const first = reusedFirst ?? (served === void 0 || hintIndex !== void 0 && !cachedReachesKnown ? requestPage(source, poolString, 0) : void 0);
56069
+ if (first !== void 0 && reusedFirst === void 0) markPhase("compact-page0-sent");
56070
+ let snapshot = knownSnapshot;
56071
+ if (snapshot === void 0 && poolPreRead !== void 0) {
56072
+ markPhase("compact-pool-handed-over");
56073
+ try {
56074
+ snapshot = await poolPreRead;
56075
+ } catch {
56076
+ markPhase("compact-pool-preread-failed");
56077
+ }
56078
+ }
56079
+ snapshot ??= await readFinalizedPool(own, program, poolKey);
55902
56080
  markPhase(knownSnapshot !== void 0 ? "compact-pool-reused" : "compact-pool");
55903
56081
  if (snapshot.terminal) throw refuse3("p03_compact_history_pool_terminal");
55904
56082
  if (snapshot.currentIndex % SUBTREE_LEAVES3 !== 0n) throw refuse3("p03_compact_history_snapshot_invalid");
55905
56083
  const count2 = Number(snapshot.currentIndex / SUBTREE_LEAVES3);
55906
56084
  if (!Number.isSafeInteger(count2)) throw refuse3("p03_compact_history_snapshot_invalid");
55907
56085
  const anchors = freezeFinalizedAnchors(snapshot);
56086
+ const readServedPages = () => {
56087
+ if (reusedFirst !== void 0) markPhase("compact-behind-page0-reused");
56088
+ return readPages(source, poolString, count2, first, { wakeSlot: snapshot.slot });
56089
+ };
55908
56090
  const page = count2 === 0 ? { records: [], imports: [], initialization: void 0, syncedSlot: void 0 } : served !== void 0 && Array.isArray(served.records) && served.records.length >= count2 && served.initialization ? {
55909
56091
  records: served.records.slice(0, count2),
55910
56092
  imports: Array.isArray(served.imports) ? served.imports : [],
55911
56093
  initialization: served.initialization,
55912
56094
  syncedSlot: served.syncedSlot,
55913
56095
  cached: true
55914
- } : await readPages(source, poolString, count2, first, { wakeSlot: snapshot.slot }).catch((error) => {
56096
+ } : await readServedPages().catch((error) => {
55915
56097
  if (error?.compactHistoryRefusal === "p03_compact_history_source_behind") error.behindSnapshot = snapshot;
55916
56098
  throw error;
55917
56099
  });
@@ -56060,6 +56242,8 @@ async function compactP03HistoryReport({
56060
56242
  priorAttestation,
56061
56243
  knownIndex,
56062
56244
  knownSnapshot,
56245
+ knownFirst,
56246
+ poolPreRead,
56063
56247
  onList
56064
56248
  }) {
56065
56249
  if (deploymentIdentity === void 0) throw new Error("p03_history_deployment_identity_required");
@@ -56078,6 +56262,13 @@ async function compactP03HistoryReport({
56078
56262
  try {
56079
56263
  const attested2 = await programDataCoverage({
56080
56264
  connection: withBoundedOwnReads(connection),
56265
+ // The two reuse reads on the split's own RPC, both bounded (it has no timeout): one RPC answers
56266
+ // both at the snapshot slot (walk.mjs programDataCoverageFor reuseConnection; production c1s:
56267
+ // the signature read on the history proxy cost a -32016 retry while it was behind).
56268
+ ...connection.historyRpcOwnConnection === void 0 ? {} : { reuseConnection: /* @__PURE__ */ ((own) => ({
56269
+ getAccountInfoAndContext: (...args) => boundedOwnRead(() => own.getAccountInfoAndContext(...args)),
56270
+ getSignaturesForAddress: (...args) => boundedOwnRead(() => own.getSignaturesForAddress(...args))
56271
+ }))(connection.historyRpcOwnConnection) },
56081
56272
  program,
56082
56273
  initialization: initialization2,
56083
56274
  snapshotSlot: snapshot2.slot,
@@ -56130,6 +56321,8 @@ async function compactP03HistoryReport({
56130
56321
  alongside: attest,
56131
56322
  ...knownIndex !== void 0 ? { knownIndex } : {},
56132
56323
  ...knownSnapshot !== void 0 ? { knownSnapshot } : {},
56324
+ ...knownFirst !== void 0 ? { knownFirst } : {},
56325
+ ...poolPreRead !== void 0 ? { poolPreRead } : {},
56133
56326
  ...onList !== void 0 ? { onList } : {},
56134
56327
  ...warm ? { served: cached.served } : {},
56135
56328
  ...cached ? { initialization: cached.initialization } : {},
@@ -56192,6 +56385,8 @@ async function compactP03HistoryReport({
56192
56385
  });
56193
56386
  }
56194
56387
  if (cache) {
56388
+ const poolString = poolKey.toBase58();
56389
+ const writesFoldRoots = compact.outerFrontier !== void 0 && !droppedPools.has(poolString);
56195
56390
  try {
56196
56391
  await cache.save({
56197
56392
  programId: program.toBase58(),
@@ -56206,11 +56401,16 @@ async function compactP03HistoryReport({
56206
56401
  initialization,
56207
56402
  attestation: attested.attestation,
56208
56403
  // 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: {
56404
+ // `unverified` while some came from the cache unhashed here: the check clears it once it
56405
+ // hashed them (markFoldRootsVerified); a process that exits first leaves it, and the next
56406
+ // process folds them itself.
56407
+ ...writesFoldRoots ? { foldRoots: {
56210
56408
  zero: hex64(zeroRoots()[OUTER_DEPTH2]),
56211
- roots: report.contexts.map((context) => hex64(context.appendRoot))
56409
+ roots: report.contexts.map((context) => hex64(context.appendRoot)),
56410
+ ...compact.cachedRoots.size > 0 ? { unverified: true } : {}
56212
56411
  } } : {}
56213
56412
  });
56413
+ if (writesFoldRoots && droppedPools.has(poolString)) rewriteFoldRoots(poolString, cache, () => void 0);
56214
56414
  } catch {
56215
56415
  }
56216
56416
  }
@@ -56944,6 +57144,7 @@ async function loadWalletP03History(args) {
56944
57144
  try {
56945
57145
  const report2 = await prewarm.promise;
56946
57146
  PREWARMED_REPORTS.add(report2);
57147
+ PAYMENT_TAKEN_REPORTS.add(report2);
56947
57148
  markPhase("walk-prewarmed");
56948
57149
  if (runKey !== void 0) recentLoads.set(runKey, { startedAt: prewarm.startedAt, report: report2 });
56949
57150
  return report2;
@@ -56955,6 +57156,7 @@ async function loadWalletP03History(args) {
56955
57156
  const recent = recentLoads.get(runKey);
56956
57157
  if (recent !== void 0 && Date.now() - recent.startedAt <= HISTORY_PREWARM_JOIN_MS) {
56957
57158
  PREWARMED_REPORTS.add(recent.report);
57159
+ PAYMENT_TAKEN_REPORTS.add(recent.report);
56958
57160
  markPhase("walk-recent");
56959
57161
  return recent.report;
56960
57162
  }
@@ -56996,9 +57198,27 @@ async function loadWalletP03HistoryNow({ store, connection: given, programId, po
56996
57198
  const remembered = runKey === void 0 || forceRead ? void 0 : lastRunReports.get(runKey);
56997
57199
  const earlier = remembered !== void 0 && Date.now() - remembered.at <= HISTORY_WARM_FRESH_MS ? remembered.report : void 0;
56998
57200
  let movedIndex;
56999
- if (earlier !== void 0) {
57201
+ let poolPreRead;
57202
+ const compactNext = Boolean(split5) && cache === void 0 && (source === "pinned" || source === "flag");
57203
+ if (earlier !== void 0 && compactNext && PAYMENT_TAKEN_REPORTS.has(earlier)) {
57204
+ markPhase("refresh-skipped-own-pay");
57205
+ if (typeof onCompactList === "function" && Array.isArray(earlier.contexts)) {
57206
+ try {
57207
+ onCompactList(earlier.contexts);
57208
+ } catch {
57209
+ }
57210
+ }
57211
+ const index = earlier.finalizedPoolSnapshot?.currentIndex;
57212
+ if (typeof index === "bigint") movedIndex = index + SUBTREE_LEAVES4;
57213
+ } else if (earlier !== void 0) {
57000
57214
  markPhase("refresh-start");
57001
57215
  const refreshing = refreshFinalizedP03HistorySnapshot({ connection, programId, pool: pool2, history: earlier });
57216
+ if (compactNext) {
57217
+ poolPreRead = readCompactPoolSnapshot({ connection, programId, pool: pool2 });
57218
+ poolPreRead.catch(() => {
57219
+ });
57220
+ markPhase("compact-pool-prestarted");
57221
+ }
57002
57222
  if (typeof onCompactList === "function" && Array.isArray(earlier.contexts)) {
57003
57223
  try {
57004
57224
  onCompactList(earlier.contexts);
@@ -57020,7 +57240,7 @@ async function loadWalletP03HistoryNow({ store, connection: given, programId, po
57020
57240
  if (strict) floor?.strict();
57021
57241
  }
57022
57242
  }
57023
- if (split5 && cache === void 0 && (source === "pinned" || source === "flag")) {
57243
+ if (compactNext) {
57024
57244
  const compact = await compactFirst({
57025
57245
  store,
57026
57246
  connection,
@@ -57030,6 +57250,7 @@ async function loadWalletP03HistoryNow({ store, connection: given, programId, po
57030
57250
  deploymentIdentity,
57031
57251
  forceRead,
57032
57252
  knownIndex: movedIndex,
57253
+ poolPreRead,
57033
57254
  onCompactList
57034
57255
  });
57035
57256
  if (compact !== void 0) {
@@ -57071,7 +57292,7 @@ async function loadWalletP03HistoryNow({ store, connection: given, programId, po
57071
57292
  if (runKey !== void 0) rememberRunReport(runKey, result.report);
57072
57293
  return result.report;
57073
57294
  }
57074
- async function compactFirst({ store, connection, source, programId, pool: pool2, deploymentIdentity, forceRead, knownIndex, onCompactList }) {
57295
+ async function compactFirst({ store, connection, source, programId, pool: pool2, deploymentIdentity, forceRead, knownIndex, poolPreRead, onCompactList }) {
57075
57296
  const started = Date.now();
57076
57297
  let behindNoticed = false;
57077
57298
  let behindTries = 0;
@@ -57096,8 +57317,10 @@ async function compactFirst({ store, connection, source, programId, pool: pool2,
57096
57317
  }
57097
57318
  };
57098
57319
  let behindSnapshot;
57320
+ let behindPage;
57099
57321
  for (let tries = 0; ; tries += 1) {
57100
- const result = await tryCompactP03HistoryReport(behindSnapshot !== void 0 ? { ...options, knownSnapshot: behindSnapshot } : tries === 0 && knownIndex !== void 0 ? { ...options, knownIndex } : options);
57322
+ const result = await tryCompactP03HistoryReport(behindSnapshot !== void 0 ? { ...options, knownSnapshot: behindSnapshot, ...behindPage !== void 0 ? { knownFirst: behindPage } : {} } : tries === 0 ? { ...options, ...knownIndex !== void 0 ? { knownIndex } : {}, ...poolPreRead !== void 0 ? { poolPreRead } : {} } : options);
57323
+ behindPage = void 0;
57101
57324
  if (result.ok) {
57102
57325
  markPhase("walk-compact");
57103
57326
  const who = source === "pinned" ? "the pinned history proxy" : "--history-rpc";
@@ -57117,7 +57340,7 @@ async function compactFirst({ store, connection, source, programId, pool: pool2,
57117
57340
  markPhase("compact-behind-wait");
57118
57341
  behindTries += 1;
57119
57342
  behindSnapshot = result.error?.behindSnapshot;
57120
- await waitForCompactSource(options.history, pool2, behindTries === 1 ? behindSnapshot?.slot : void 0, behindDelay);
57343
+ behindPage = await waitForCompactSource(options.history, pool2, behindTries === 1 ? behindSnapshot?.slot : void 0, behindDelay);
57121
57344
  continue;
57122
57345
  }
57123
57346
  writeStderr(`history: the compact transition list was refused (${result.reason}${result.detail ? `; cause ${result.detail}` : ""}); walking the pool history instead
@@ -57131,7 +57354,7 @@ async function waitForCompactSource(source, pool2, slot3, budgetMs) {
57131
57354
  const until = Date.now() + budgetMs;
57132
57355
  for (; ; ) {
57133
57356
  const abort = new AbortController();
57134
- const params = [pool2, { commitment: "finalized", fromOrdinal: 0, toOrdinal: 1, minContextSlot: slot3 }];
57357
+ const params = [pool2, { commitment: "finalized", fromOrdinal: 0, toOrdinal: P03_COMPACT_PAGE, minContextSlot: slot3 }];
57135
57358
  const read = (typeof source.abortableRpcRequest === "function" ? source.abortableRpcRequest("getP03Transitions", params, abort.signal) : source._rpcRequest("getP03Transitions", params)).catch(() => ({ failed: true }));
57136
57359
  let timer;
57137
57360
  const answer = await Promise.race([read, new Promise((resolve38) => {
@@ -57141,7 +57364,7 @@ async function waitForCompactSource(source, pool2, slot3, budgetMs) {
57141
57364
  if (answer === void 0) abort.abort();
57142
57365
  if (answer?.result !== void 0) {
57143
57366
  markPhase("compact-behind-caught-up");
57144
- return void 0;
57367
+ return isCompactPageZeroAnswer(answer, pool2) ? { response: answer } : void 0;
57145
57368
  }
57146
57369
  if (answer !== void 0 && answer?.error?.code !== -32016) return sleep5(Math.max(0, until - Date.now()));
57147
57370
  const left = until - Date.now();
@@ -57198,7 +57421,7 @@ function reportHistoryRpc(split5, source, result, crossChecked) {
57198
57421
  writeStderr(`history: ${who} answered ${list(split5.history)}; your own RPC answered ${list(split5.own)} (the pool account the history must match, and the cross-check)${window2}${integrity}
57199
57422
  `);
57200
57423
  }
57201
- var strictScope, withStrictHistorySource, recentScope, withRecentWalletHistory, recentLoads, forgetRecentWalletHistory, historyCacheKey, HISTORY_PREWARM_JOIN_MS, prewarmedWalks, PREWARMED_REPORTS, isPrewarmedWalletHistory, COMPACT_BEHIND_POLL_MS, COMPACT_BEHIND_READ_MS, COMPACT_BEHIND_RETRY_MS, lastRunReports, writeStderr, announcedSources;
57424
+ var strictScope, withStrictHistorySource, recentScope, withRecentWalletHistory, recentLoads, forgetRecentWalletHistory, historyCacheKey, HISTORY_PREWARM_JOIN_MS, SUBTREE_LEAVES4, prewarmedWalks, PREWARMED_REPORTS, PAYMENT_TAKEN_REPORTS, isPrewarmedWalletHistory, COMPACT_BEHIND_POLL_MS, COMPACT_BEHIND_READ_MS, COMPACT_BEHIND_RETRY_MS, lastRunReports, writeStderr, announcedSources;
57202
57425
  var init_walletHistory = __esm({
57203
57426
  "wallet/src/history/walletHistory.mjs"() {
57204
57427
  "use strict";
@@ -57220,8 +57443,10 @@ var init_walletHistory = __esm({
57220
57443
  };
57221
57444
  historyCacheKey = (store) => createHmac5("sha256", Buffer.from(store.state.seedHex, "hex")).update("carbon-shielded-wallet/history-cache-key/v1").digest("hex");
57222
57445
  HISTORY_PREWARM_JOIN_MS = 1e4;
57446
+ SUBTREE_LEAVES4 = 128n;
57223
57447
  prewarmedWalks = /* @__PURE__ */ new Map();
57224
57448
  PREWARMED_REPORTS = /* @__PURE__ */ new WeakSet();
57449
+ PAYMENT_TAKEN_REPORTS = /* @__PURE__ */ new WeakSet();
57225
57450
  isPrewarmedWalletHistory = (report) => report !== null && typeof report === "object" && PREWARMED_REPORTS.has(report);
57226
57451
  COMPACT_BEHIND_POLL_MS = 150;
57227
57452
  COMPACT_BEHIND_READ_MS = 1e3;
@@ -73681,8 +73906,8 @@ function bindLeavesToPool({ leaves, currentRoot, currentIndex, anchors }) {
73681
73906
  const root = leafField(currentRoot);
73682
73907
  if (root === void 0) return unbound("root missing");
73683
73908
  const index = typeof currentIndex === "bigint" ? currentIndex : Number.isSafeInteger(currentIndex) ? BigInt(currentIndex) : void 0;
73684
- if (index === void 0 || index < 0n || index % SUBTREE_LEAVES4 !== 0n) return unbound("index missing");
73685
- if (BigInt(leaves.length) * SUBTREE_LEAVES4 !== index) return unbound("leaf count mismatch");
73909
+ if (index === void 0 || index < 0n || index % SUBTREE_LEAVES5 !== 0n) return unbound("index missing");
73910
+ if (BigInt(leaves.length) * SUBTREE_LEAVES5 !== index) return unbound("leaf count mismatch");
73686
73911
  if (!Array.isArray(anchors)) return unbound("anchors missing");
73687
73912
  const parsed = [];
73688
73913
  for (const leaf of leaves) {
@@ -73695,7 +73920,7 @@ function bindLeavesToPool({ leaves, currentRoot, currentIndex, anchors }) {
73695
73920
  for (const anchor of anchors) {
73696
73921
  const anchorIndex = typeof anchor?.index === "bigint" ? anchor.index : void 0;
73697
73922
  const anchorRoot = leafField(anchor?.root);
73698
- if (anchorIndex === void 0 || anchorRoot === void 0 || anchorIndex < 0n || anchorIndex % SUBTREE_LEAVES4 !== 0n || anchorIndex / SUBTREE_LEAVES4 >= BigInt(roots.length) || roots[Number(anchorIndex / SUBTREE_LEAVES4)] !== anchorRoot) return unbound("anchor mismatch");
73923
+ if (anchorIndex === void 0 || anchorRoot === void 0 || anchorIndex < 0n || anchorIndex % SUBTREE_LEAVES5 !== 0n || anchorIndex / SUBTREE_LEAVES5 >= BigInt(roots.length) || roots[Number(anchorIndex / SUBTREE_LEAVES5)] !== anchorRoot) return unbound("anchor mismatch");
73699
73924
  }
73700
73925
  return Object.freeze({ bound: true, leaves: Object.freeze(parsed) });
73701
73926
  }
@@ -73706,14 +73931,14 @@ function ownLeafStatus({ outCommitment, leaves, currentRoot, currentIndex, ancho
73706
73931
  if (!binding.bound) return Object.freeze({ status: "unknown", reason: binding.reason });
73707
73932
  return Object.freeze({ status: binding.leaves.includes(own) ? "landed" : "absent" });
73708
73933
  }
73709
- var FIELD_MODULUS8, SUBTREE_LEAVES4, LOCAL_DEPTH3, OUTER_DEPTH3, hash6, zeroRootsMemo2, lastFold2, unbound;
73934
+ var FIELD_MODULUS8, SUBTREE_LEAVES5, LOCAL_DEPTH3, OUTER_DEPTH3, hash6, zeroRootsMemo2, lastFold2, unbound;
73710
73935
  var init_leafBinding = __esm({
73711
73936
  "wallet/src/history/leafBinding.mjs"() {
73712
73937
  "use strict";
73713
73938
  init_reference2();
73714
73939
  init_recoveryPath();
73715
73940
  FIELD_MODULUS8 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
73716
- SUBTREE_LEAVES4 = 128n;
73941
+ SUBTREE_LEAVES5 = 128n;
73717
73942
  LOCAL_DEPTH3 = 7;
73718
73943
  OUTER_DEPTH3 = 41;
73719
73944
  hash6 = (left, right) => poseidon2([left, right], 3);
@@ -93587,6 +93812,7 @@ async function payResourceOnce({
93587
93812
  }
93588
93813
  };
93589
93814
  let priorHistory;
93815
+ let submitClockRead;
93590
93816
  try {
93591
93817
  if (deps.settlePriorBeforeQuote === true && !record && !reconciling) {
93592
93818
  const answeredLongAgo = (other) => isPending(other) && Number.isSafeInteger(other.answeredAtMs) && Date.now() - other.answeredAtMs >= FINALITY_GATE_SKIP_AFTER_MS;
@@ -93748,6 +93974,7 @@ async function payResourceOnce({
93748
93974
  store.writeWal(walName2, record);
93749
93975
  }
93750
93976
  mark("prove-start");
93977
+ submitClockRead = startFinalizedChainTime(connection);
93751
93978
  let prepared;
93752
93979
  try {
93753
93980
  prepared = await withPhaseScope(mark, "prove", () => (deps.prepare ?? prepareRecoveredPayment)({
@@ -93832,8 +94059,20 @@ async function payResourceOnce({
93832
94059
  if (hash9(record.paymentHeader) !== record.headerSha256) fail19("wal_header_mismatch");
93833
94060
  if (record.state !== "submitted") {
93834
94061
  const required = record.paymentRequired.accepts.find((entry) => entry.scheme === "shielded-exact");
93835
- const time = await readFinalizedClock(connection);
93836
- if (!Number.isSafeInteger(time) || time >= Number(required.extra.validBefore)) fail19("quote_expired_before_submission");
94062
+ const validBefore = Number(required.extra.validBefore);
94063
+ let time;
94064
+ try {
94065
+ time = submitClockRead === void 0 ? void 0 : await submitClockRead();
94066
+ } catch {
94067
+ time = void 0;
94068
+ }
94069
+ submitClockRead = void 0;
94070
+ if (Number.isSafeInteger(time) && time + SUBMIT_CLOCK_MARGIN_SECONDS < validBefore) mark("submit-clock-early");
94071
+ else {
94072
+ time = await readFinalizedClock(connection);
94073
+ mark("submit-clock-fresh");
94074
+ }
94075
+ if (!Number.isSafeInteger(time) || time >= validBefore) fail19("quote_expired_before_submission");
93837
94076
  mark("submit-clock");
93838
94077
  await assertRefusedPaymentsCannotLand({
93839
94078
  store,
@@ -93911,7 +94150,7 @@ async function payResourceOnce({
93911
94150
  withPhaseScope(mark, "anchor-next", () => requestSubAnchorForNewLeaf());
93912
94151
  return { replayed: false, receipt, resultBase64, receiptFinality: "pending" };
93913
94152
  }
93914
- var import_web3111, fail19, failUnresolved, hash9, OWNER_UNSHIELD_REQUEST, OWNER_UNSHIELD_ORIGIN, POCKET_FILL_ID, POOL_MOVE_PATH, RECEIPT_FINALITY_TIMEOUT_MS, RECEIPT_FINALITY_POLL_MS, FINALITY_GATE_MARGIN_SLOTS, FINALITY_GATE_POLL_MS, FINALITY_GATE_SETTLE_MARGIN_SLOTS, FINALITY_GATE_SETTLE_WINDOW_SLOTS, receiptSettleSlot, FINALITY_GATE_SKIP_AFTER_MS, PENDING_FINALITY, isPending, REPLAY_INPUTS, PAYMENT_OUTPUT_INPUT2, QUOTE_MARGIN_SECONDS, SELLER_REFUSED_PAY_AGAIN, SELLER_REASON_FACILITATOR_UNDERFUNDED, ANCHOR_EPOCH_MS, ANCHOR_MARGIN_MS, ANCHOR_WAIT_CAP_MS, DEAD_PAYMENT_MARGIN_SECONDS, SYSVAR_OWNER, quoteLiveAt, replayValuesOf, finalPayments, FINAL_UNCHANGED;
94153
+ var import_web3111, fail19, failUnresolved, hash9, OWNER_UNSHIELD_REQUEST, OWNER_UNSHIELD_ORIGIN, POCKET_FILL_ID, POOL_MOVE_PATH, RECEIPT_FINALITY_TIMEOUT_MS, RECEIPT_FINALITY_POLL_MS, FINALITY_GATE_MARGIN_SLOTS, FINALITY_GATE_POLL_MS, FINALITY_GATE_SETTLE_MARGIN_SLOTS, FINALITY_GATE_SETTLE_WINDOW_SLOTS, receiptSettleSlot, FINALITY_GATE_SKIP_AFTER_MS, PENDING_FINALITY, isPending, REPLAY_INPUTS, PAYMENT_OUTPUT_INPUT2, QUOTE_MARGIN_SECONDS, SUBMIT_CLOCK_MARGIN_SECONDS, SELLER_REFUSED_PAY_AGAIN, SELLER_REASON_FACILITATOR_UNDERFUNDED, ANCHOR_EPOCH_MS, ANCHOR_MARGIN_MS, ANCHOR_WAIT_CAP_MS, DEAD_PAYMENT_MARGIN_SECONDS, SYSVAR_OWNER, quoteLiveAt, replayValuesOf, finalPayments, FINAL_UNCHANGED;
93915
94154
  var init_payResource = __esm({
93916
94155
  "wallet/src/pay/payResource.mjs"() {
93917
94156
  "use strict";
@@ -93964,6 +94203,7 @@ var init_payResource = __esm({
93964
94203
  REPLAY_INPUTS = [3, 10, 11, 12, 7];
93965
94204
  PAYMENT_OUTPUT_INPUT2 = 4;
93966
94205
  QUOTE_MARGIN_SECONDS = 120;
94206
+ SUBMIT_CLOCK_MARGIN_SECONDS = 30;
93967
94207
  SELLER_REFUSED_PAY_AGAIN = "payment_refused_pay_again";
93968
94208
  SELLER_REASON_FACILITATOR_UNDERFUNDED = "facilitator_underfunded";
93969
94209
  ANCHOR_EPOCH_MS = 3e5;
@@ -97397,13 +97637,40 @@ function createAnchorReader({ connection, profile }) {
97397
97637
  const program = new import_web3120.PublicKey(profile.programId);
97398
97638
  const pool2 = new import_web3120.PublicKey(profile.pool);
97399
97639
  const programData = import_web3120.PublicKey.findProgramAddressSync([program.toBuffer()], LOADER2)[0];
97400
- return async ({ requireCapacity = false } = {}) => {
97640
+ const headerKey = `${programData.toBase58()}:${profile.programDataSha256}`;
97641
+ const headerSlice = { offset: 0, length: PROGRAM_DATA_HEADER_BYTES };
97642
+ const accountChecks = (poolInfo, clock2, programInfo, code) => !poolInfo?.owner.equals(program) || poolInfo.executable || !clock2 || clock2.data.length < 40 || !programInfo?.owner.equals(LOADER2) || !programInfo.executable || !code?.owner.equals(LOADER2) || code.executable || code.data.length < PROGRAM_DATA_HEADER_BYTES || programInfo.data.length !== 36 || programInfo.data.readUInt32LE(0) !== 2 || !programInfo.data.subarray(4).equals(programData.toBuffer()) || code.data.readUInt32LE(0) !== 3;
97643
+ const readFull = async () => {
97401
97644
  const snapshot = await connection.getMultipleAccountsInfoAndContext(
97402
97645
  [pool2, import_web3120.SYSVAR_CLOCK_PUBKEY, program, programData],
97403
97646
  { commitment: "finalized" }
97404
97647
  );
97405
97648
  const [poolInfo, clock2, programInfo, code] = snapshot.value;
97406
- if (!poolInfo?.owner.equals(program) || poolInfo.executable || !clock2 || clock2.data.length < 40 || !programInfo?.owner.equals(LOADER2) || !programInfo.executable || !code?.owner.equals(LOADER2) || code.executable || code.data.length < 45 || programInfo.data.length !== 36 || programInfo.data.readUInt32LE(0) !== 2 || !programInfo.data.subarray(4).equals(programData.toBuffer()) || code.data.readUInt32LE(0) !== 3 || sha2(code.data) !== profile.programDataSha256) fail26("chain_pin_mismatch");
97649
+ if (accountChecks(poolInfo, clock2, programInfo, code) || sha2(code.data) !== profile.programDataSha256) fail26("chain_pin_mismatch");
97650
+ hashedProgramDataHeaders.set(headerKey, Buffer.from(code.data.subarray(0, PROGRAM_DATA_HEADER_BYTES)));
97651
+ return { slot: snapshot.context.slot, poolInfo, clock: clock2 };
97652
+ };
97653
+ const readHeaderOnly = async (hashed) => {
97654
+ const headerRead = (minContextSlot) => connection.getAccountInfoAndContext(
97655
+ programData,
97656
+ { commitment: "finalized", dataSlice: headerSlice, ...minContextSlot === void 0 ? {} : { minContextSlot } }
97657
+ );
97658
+ const [snapshot, firstHeader] = await Promise.all([
97659
+ connection.getMultipleAccountsInfoAndContext([pool2, import_web3120.SYSVAR_CLOCK_PUBKEY, program], { commitment: "finalized" }),
97660
+ headerRead()
97661
+ ]);
97662
+ const slot3 = snapshot.context.slot;
97663
+ const header = firstHeader.context.slot >= slot3 ? firstHeader : await headerRead(slot3).catch(() => void 0);
97664
+ if (!header || header.context.slot < slot3) return readFull();
97665
+ const [poolInfo, clock2, programInfo] = snapshot.value;
97666
+ const code = header.value;
97667
+ if (accountChecks(poolInfo, clock2, programInfo, code) || code.data.length !== PROGRAM_DATA_HEADER_BYTES) fail26("chain_pin_mismatch");
97668
+ if (!code.data.equals(hashed) || code.data.readBigUInt64LE(4) > BigInt(slot3)) return readFull();
97669
+ return { slot: slot3, poolInfo, clock: clock2 };
97670
+ };
97671
+ return async ({ requireCapacity = false } = {}) => {
97672
+ const hashed = hashedProgramDataHeaders.get(headerKey);
97673
+ const { slot: slot3, poolInfo, clock: clock2 } = hashed && typeof connection.getAccountInfoAndContext === "function" ? await readHeaderOnly(hashed) : await readFull();
97407
97674
  const state = parseSolanaP03PoolState(poolInfo.data);
97408
97675
  if (!state.initialized || state.decimals !== profile.decimals || new import_web3120.PublicKey(state.mint).toBase58() !== profile.mint || bigint(state.poolDomain) !== BigInt(profile.poolDomain)) fail26("pool_identity_mismatch");
97409
97676
  if (requireCapacity && (state.terminal || state.paymentCount >= state.policy.maxPayments)) fail26("pool_not_ready");
@@ -97416,7 +97683,7 @@ function createAnchorReader({ connection, profile }) {
97416
97683
  return {
97417
97684
  ...selected,
97418
97685
  chainTimestamp,
97419
- finalizedSlot: snapshot.context.slot,
97686
+ finalizedSlot: slot3,
97420
97687
  retainedAnchors: anchors.filter((a) => a !== selected)
97421
97688
  };
97422
97689
  };
@@ -97508,7 +97775,21 @@ async function createSellerAdapter({
97508
97775
  sharedXOf,
97509
97776
  log: (line) => console.error(line)
97510
97777
  });
97511
- const readChainAnchor = createAnchorReader({ connection: memoizeFinalizedReads(connection), profile });
97778
+ const readPinnedAnchor = createAnchorReader({ connection: memoizeFinalizedReads(connection), profile });
97779
+ let lastAnchorRead;
97780
+ const readChainAnchor = async (options) => {
97781
+ const startedAt = Date.now();
97782
+ const chain = await readPinnedAnchor(options);
97783
+ if (!lastAnchorRead || startedAt >= lastAnchorRead.startedAt) lastAnchorRead = { chain, startedAt };
97784
+ return chain;
97785
+ };
97786
+ const recentAnchorEvidence = () => {
97787
+ if (!lastAnchorRead) return void 0;
97788
+ const ageMs = Date.now() - lastAnchorRead.startedAt;
97789
+ if (!(ageMs >= 0 && ageMs <= INTAKE_REUSE_MAX_AGE_MS)) return void 0;
97790
+ const { chain } = lastAnchorRead;
97791
+ return { ...chain, chainTimestamp: chain.chainTimestamp + BigInt(Math.ceil(ageMs / 1e3)) + 1n };
97792
+ };
97512
97793
  let anchorRequest;
97513
97794
  const requestFacilitatorAnchor = () => anchorRequest ??= (async () => {
97514
97795
  const response = await fetchImpl(`${config.facilitatorBaseUrl}/anchor`, {
@@ -97554,12 +97835,12 @@ async function createSellerAdapter({
97554
97835
  await sleep5(ANCHOR_POLL_MS);
97555
97836
  }
97556
97837
  };
97557
- const issuer = (resource, amount) => new ShieldedSolanaP03QuoteIssuer({
97838
+ const issuer = (resource, amount, readCurrentQuoteAnchor = readAnchor) => new ShieldedSolanaP03QuoteIssuer({
97558
97839
  ...profile,
97559
97840
  resource,
97560
97841
  amount,
97561
97842
  randomBytes: randomBytes17,
97562
- readCurrentQuoteAnchor: readAnchor
97843
+ readCurrentQuoteAnchor
97563
97844
  });
97564
97845
  for (const route of config.routes) issuer(route.resource, route.amountAtomic);
97565
97846
  if (existsSync(config.storePath)) {
@@ -97887,10 +98168,11 @@ async function createSellerAdapter({
97887
98168
  await put(nonce, renewed);
97888
98169
  return renewed;
97889
98170
  }
97890
- async function acceptPayment(route, body, header2) {
98171
+ async function acceptPayment(route, body, header2, arrivedAt) {
97891
98172
  const payment = decodePayment(header2);
97892
98173
  const nonce = payment.accepted?.extra?.resourceNonce;
97893
98174
  const mark = timing.start();
98175
+ if (Number.isFinite(arrivedAt) && arrivedAt <= Date.now()) mark("http-arrival", void 0, arrivedAt);
97894
98176
  const original = state.offers[nonce];
97895
98177
  if (!original || original.method !== route.method || original.url !== route.resource.url || original.bodyDigest !== `0x${sha2(body)}` || canonical4(payment.accepted) !== canonical4(original.paymentRequired.accepts[0]) || canonical4(payment.resource) !== canonical4(original.paymentRequired.resource)) fail26("offer_binding_mismatch");
97896
98178
  if (original.paymentHeader && original.paymentHeader !== header2) fail26("payment_retry_mismatch");
@@ -97910,9 +98192,14 @@ async function createSellerAdapter({
97910
98192
  try {
97911
98193
  if (!offer.outboundJson) {
97912
98194
  const parsed = parseSolanaP03HttpPaymentPayload(payment.payload);
97913
- const quoteIssuer = issuer(offer.resource, payment.accepted.amount);
97914
98195
  const authInput = { requirements: payment.accepted, resource: payment.resource, publicInput7: parsed.publicInputs[7] };
97915
- await quoteIssuer.authenticateForClaim(authInput);
98196
+ const recent = recentAnchorEvidence();
98197
+ const early = recent === void 0 ? void 0 : await issuer(offer.resource, payment.accepted.amount, async () => recent).authenticate(authInput).catch(() => void 0);
98198
+ let intakeRead;
98199
+ const quoteIssuer = issuer(offer.resource, payment.accepted.amount, () => intakeRead);
98200
+ if (early === void 0) await quoteIssuer.authenticateForClaim(authInput);
98201
+ intakeRead = readAnchor();
98202
+ intakeRead.catch(() => void 0);
97916
98203
  const authenticated = quoteIssuer.authenticate(authInput);
97917
98204
  authenticated.catch(() => void 0);
97918
98205
  const owned = { keys: [], done: false, cancel: void 0 };
@@ -97933,12 +98220,10 @@ async function createSellerAdapter({
97933
98220
  });
97934
98221
  }
97935
98222
  let recoveredNote;
97936
- let intakeRead;
97937
98223
  try {
97938
- const auth = await authenticated;
98224
+ const auth = early ?? await authenticated;
98225
+ if (early !== void 0) mark("intake-reused-read");
97939
98226
  mark("intake-authenticated");
97940
- intakeRead = readAnchor();
97941
- intakeRead.catch(() => void 0);
97942
98227
  if (precomputed !== void 0) {
97943
98228
  let timer;
97944
98229
  await Promise.race([precomputed, new Promise((resolveWait) => {
@@ -97946,13 +98231,19 @@ async function createSellerAdapter({
97946
98231
  })]);
97947
98232
  clearTimeout(timer);
97948
98233
  }
97949
- recoveredNote = await scanner.recoverMerchantNoteYielding({ parsed, authenticatedQuote: auth });
98234
+ try {
98235
+ recoveredNote = await scanner.recoverMerchantNoteYielding({ parsed, authenticatedQuote: auth });
98236
+ } catch (error) {
98237
+ await authenticated;
98238
+ throw error;
98239
+ }
97950
98240
  } finally {
97951
98241
  owned.done = true;
97952
98242
  owned.cancel?.();
97953
98243
  for (const key of owned.keys) sharedXByPoint.delete(key);
97954
98244
  }
97955
98245
  mark("intake-note-recovered");
98246
+ await authenticated;
97956
98247
  const chain = await intakeRead;
97957
98248
  intakeChain = chain;
97958
98249
  mark("intake-anchor-read");
@@ -98061,12 +98352,12 @@ async function createSellerAdapter({
98061
98352
  if (!route || origin === void 0 || origin === config.publicOrigin || !(config.aliasOrigins ?? []).includes(origin)) return route;
98062
98353
  return { ...route, resource: { ...route.resource, url: `${origin}${route.path}` } };
98063
98354
  };
98064
- async function handleUnlocked({ method, path, body, paymentHeader, origin }) {
98355
+ async function handleUnlocked({ method, path, body, paymentHeader, origin, arrivedAt }) {
98065
98356
  const route = resourceAt(config.routes.find((candidate) => candidate.method === method && candidate.path === path), origin);
98066
98357
  if (paymentHeader !== void 0) return acceptPayment(route ?? {
98067
98358
  method,
98068
98359
  resource: { url: `${(config.aliasOrigins ?? []).includes(origin) ? origin : config.publicOrigin}${path}` }
98069
- }, body, paymentHeader);
98360
+ }, body, paymentHeader, arrivedAt);
98070
98361
  if (!route) return { status: 404, code: "resource_not_found" };
98071
98362
  const result = route.resultFor ? await route.resultFor(body) : route.result;
98072
98363
  if (route.resultFor && (result?.status !== 200 || typeof result.contentType !== "string" || typeof result.bodyBase64 !== "string")) fail26("route_result_invalid");
@@ -98182,7 +98473,7 @@ async function createSellerAdapter({
98182
98473
  }));
98183
98474
  return { server, handle, close, signerPublicKey, settledTransactions, offerSummaries };
98184
98475
  }
98185
- var import_web3120, BINDING, SCHEMA2, OFFERS_LAYOUT, SNAPSHOT_EVERY_MS, LOADER2, canonical4, storeProfileIdentity, jsonSafe, bigint, encodeHeader, PAYMENT_REFUSED, FACILITATOR_UNDERFUNDED, DEFINITE_VERIFY_REFUSALS, definiteVerifyRefusal, refusedBeforeSettlement, ANCHOR_REQUEST_TIMEOUT_MS2, ANCHOR_POLL_ATTEMPTS, ANCHOR_POLL_MS, MEMO_PRECOMPUTES_MAX, MEMO_PRECOMPUTE_WAIT_MS, PRE_SETTLE_REUSE_MARGIN_S, PRE_SETTLE_REUSE_MAX_AGE_MS, FINALIZED_MEMO_MAX_AGE_MS, pause, FOLLOW_UP_DELAYS_MS, FOLLOW_UP_RESETTLE_FROM, CONFIRMED_TRANSACTION_READ;
98476
+ var import_web3120, BINDING, SCHEMA2, OFFERS_LAYOUT, SNAPSHOT_EVERY_MS, LOADER2, canonical4, storeProfileIdentity, jsonSafe, bigint, encodeHeader, PROGRAM_DATA_HEADER_BYTES, hashedProgramDataHeaders, PAYMENT_REFUSED, FACILITATOR_UNDERFUNDED, DEFINITE_VERIFY_REFUSALS, definiteVerifyRefusal, refusedBeforeSettlement, ANCHOR_REQUEST_TIMEOUT_MS2, ANCHOR_POLL_ATTEMPTS, ANCHOR_POLL_MS, MEMO_PRECOMPUTES_MAX, MEMO_PRECOMPUTE_WAIT_MS, PRE_SETTLE_REUSE_MARGIN_S, PRE_SETTLE_REUSE_MAX_AGE_MS, FINALIZED_MEMO_MAX_AGE_MS, INTAKE_REUSE_MAX_AGE_MS, pause, FOLLOW_UP_DELAYS_MS, FOLLOW_UP_RESETTLE_FROM, CONFIRMED_TRANSACTION_READ;
98186
98477
  var init_service = __esm({
98187
98478
  "wallet/src/seller/service.mjs"() {
98188
98479
  "use strict";
@@ -98214,6 +98505,8 @@ var init_service = __esm({
98214
98505
  jsonSafe = (v) => JSON.parse(JSON.stringify(v, (_, item) => typeof item === "bigint" ? item.toString() : item));
98215
98506
  bigint = (bytes2) => BigInt(`0x${Buffer.from(bytes2).toString("hex")}`);
98216
98507
  encodeHeader = (v) => Buffer.from(JSON.stringify(v)).toString("base64");
98508
+ PROGRAM_DATA_HEADER_BYTES = 45;
98509
+ hashedProgramDataHeaders = /* @__PURE__ */ new Map();
98217
98510
  PAYMENT_REFUSED = "payment_refused_pay_again";
98218
98511
  FACILITATOR_UNDERFUNDED = "facilitator_underfunded";
98219
98512
  DEFINITE_VERIFY_REFUSALS = /* @__PURE__ */ new Set([
@@ -98239,6 +98532,7 @@ var init_service = __esm({
98239
98532
  PRE_SETTLE_REUSE_MARGIN_S = 60;
98240
98533
  PRE_SETTLE_REUSE_MAX_AGE_MS = 2e4;
98241
98534
  FINALIZED_MEMO_MAX_AGE_MS = 1e3;
98535
+ INTAKE_REUSE_MAX_AGE_MS = 1e4;
98242
98536
  pause = (ms) => new Promise((resolve38) => setTimeout(resolve38, ms));
98243
98537
  FOLLOW_UP_DELAYS_MS = Object.freeze([
98244
98538
  15e3,
@@ -114159,13 +114453,13 @@ function upperZeroRoots() {
114159
114453
  function subtreeBit(subtreeCount, level) {
114160
114454
  return BigInt(subtreeCount) >> BigInt(level) & 1n;
114161
114455
  }
114162
- var SUBTREE_DEPTH, SUBTREE_LEAVES5, TREE_DEPTH4, UPPER_LEVELS, EPOCH_SECONDS2, zeroLeaf, cachedZeroRoots, TreeFrontier, DEFAULT_START_TIME;
114456
+ var SUBTREE_DEPTH, SUBTREE_LEAVES6, TREE_DEPTH4, UPPER_LEVELS, EPOCH_SECONDS2, zeroLeaf, cachedZeroRoots, TreeFrontier, DEFAULT_START_TIME;
114163
114457
  var init_multipool_model = __esm({
114164
114458
  "wallet/vendor/shielded-x402-model/src/multipool-model.mjs"() {
114165
114459
  "use strict";
114166
114460
  init_reference2();
114167
114461
  SUBTREE_DEPTH = 7;
114168
- SUBTREE_LEAVES5 = 128;
114462
+ SUBTREE_LEAVES6 = 128;
114169
114463
  TREE_DEPTH4 = 48;
114170
114464
  UPPER_LEVELS = TREE_DEPTH4 - SUBTREE_DEPTH;
114171
114465
  EPOCH_SECONDS2 = 300n;
@@ -114180,23 +114474,23 @@ var init_multipool_model = __esm({
114180
114474
  this.root = _TreeFrontier.rootFromRecord(this.record());
114181
114475
  }
114182
114476
  get index() {
114183
- return Number(this.subtreeCount) * SUBTREE_LEAVES5;
114477
+ return Number(this.subtreeCount) * SUBTREE_LEAVES6;
114184
114478
  }
114185
114479
  record() {
114186
114480
  const zero = upperZeroRoots();
114187
114481
  return {
114188
- index: Number(this.subtreeCount) * SUBTREE_LEAVES5,
114482
+ index: Number(this.subtreeCount) * SUBTREE_LEAVES6,
114189
114483
  root: this.root === void 0 ? void 0 : this.root.toString(),
114190
114484
  frontierNodes: this.filled.map((node3, level) => (subtreeBit(this.subtreeCount, level) === 1n ? node3 : zero[level]).toString())
114191
114485
  };
114192
114486
  }
114193
114487
  static rootFromRecord({ index, frontierNodes }) {
114194
- if (index % SUBTREE_LEAVES5 !== 0) throw new Error("frontier_index_misaligned");
114488
+ if (index % SUBTREE_LEAVES6 !== 0) throw new Error("frontier_index_misaligned");
114195
114489
  if (frontierNodes && frontierNodes.length !== UPPER_LEVELS) {
114196
114490
  throw new Error("frontier_record_width");
114197
114491
  }
114198
114492
  const zero = upperZeroRoots();
114199
- const subtreeCount = BigInt(index / SUBTREE_LEAVES5);
114493
+ const subtreeCount = BigInt(index / SUBTREE_LEAVES6);
114200
114494
  let accumulator = zero[0];
114201
114495
  for (let level = 0; level < UPPER_LEVELS; level += 1) {
114202
114496
  accumulator = subtreeBit(subtreeCount, level) === 1n ? poseidon2([BigInt(frontierNodes[level]), accumulator], 3) : poseidon2([accumulator, zero[level]], 3);
@@ -114241,7 +114535,7 @@ __export(pool_exports, {
114241
114535
  EMPTY_ROOT: () => EMPTY_ROOT,
114242
114536
  JUBJUB_G: () => JUBJUB_G,
114243
114537
  PoolTree: () => PoolTree,
114244
- SUBTREE_LEAVES: () => SUBTREE_LEAVES6,
114538
+ SUBTREE_LEAVES: () => SUBTREE_LEAVES7,
114245
114539
  ZERO_LEAF: () => ZERO_LEAF,
114246
114540
  account: () => account,
114247
114541
  accountNullifier: () => accountNullifier2,
@@ -114269,8 +114563,8 @@ function account(w, i, b) {
114269
114563
  return { d: w.d, pDX: w.pDX, i, b, commitment };
114270
114564
  }
114271
114565
  function subtree(slot3, commitment) {
114272
- if (!Number.isInteger(slot3) || slot3 < 0 || slot3 >= SUBTREE_LEAVES6) throw new Error("slot must be in [0, 128)");
114273
- const leaves = Array(SUBTREE_LEAVES6).fill(ZERO_LEAF);
114566
+ if (!Number.isInteger(slot3) || slot3 < 0 || slot3 >= SUBTREE_LEAVES7) throw new Error("slot must be in [0, 128)");
114567
+ const leaves = Array(SUBTREE_LEAVES7).fill(ZERO_LEAF);
114274
114568
  leaves[slot3] = commitment;
114275
114569
  const levels = merkleLevels2(leaves);
114276
114570
  const siblings = [];
@@ -114291,7 +114585,7 @@ function accountNullifier2(a, eta, position3) {
114291
114585
  function dummyNoteNullifier(poolDomain, nullifier, eta, slot3) {
114292
114586
  return sponge2([DOMAINS.dummyNoteNullifierV2, poolDomain, nullifier, eta, BigInt(slot3)]);
114293
114587
  }
114294
- var HERE, VECTORS, big, DOMAINS, JUBJUB_G, ZERO_LEAF, SUBTREE_LEAVES6, EMPTY_ROOT, PoolTree;
114588
+ var HERE, VECTORS, big, DOMAINS, JUBJUB_G, ZERO_LEAF, SUBTREE_LEAVES7, EMPTY_ROOT, PoolTree;
114295
114589
  var init_pool = __esm({
114296
114590
  "packages/ctvault-v0b/src/pool.ts"() {
114297
114591
  "use strict";
@@ -114305,7 +114599,7 @@ var init_pool = __esm({
114305
114599
  JUBJUB_G = { x: big(VECTORS.payerKeys.generator.x), y: big(VECTORS.payerKeys.generator.y) };
114306
114600
  ZERO_LEAF = poseidon2([DOMAINS.note, 0n, 0n, 0n, 0n], 6);
114307
114601
  if (ZERO_LEAF.toString() !== VECTORS.zeroLeaf) throw new Error("zero leaf drifts from the Rust vectors");
114308
- SUBTREE_LEAVES6 = 128;
114602
+ SUBTREE_LEAVES7 = 128;
114309
114603
  EMPTY_ROOT = upperZeroRoots()[UPPER_LEVELS];
114310
114604
  PoolTree = class {
114311
114605
  frontier = new TreeFrontier();
@@ -114347,7 +114641,7 @@ var init_pool = __esm({
114347
114641
  if (subtreeIndex >= n) throw new Error("the leaf is not in that root");
114348
114642
  const st = this.subtrees[subtreeIndex];
114349
114643
  const up = this.upper(n, subtreeIndex);
114350
- return { leafIndex: BigInt(subtreeIndex * SUBTREE_LEAVES6 + st.slot), siblings: [...st.siblings, ...up.siblings], root: up.root };
114644
+ return { leafIndex: BigInt(subtreeIndex * SUBTREE_LEAVES7 + st.slot), siblings: [...st.siblings, ...up.siblings], root: up.root };
114351
114645
  }
114352
114646
  upper(n, index) {
114353
114647
  const zero = upperZeroRoots();
@@ -121272,6 +121566,23 @@ function provenInputs(proofRecord) {
121272
121566
  }
121273
121567
  return commitments;
121274
121568
  }
121569
+ var PROOF_RECORD = "resource-proof-";
121570
+ function lazyProofEntry(store, name) {
121571
+ let loaded = false;
121572
+ let record;
121573
+ const read = () => {
121574
+ if (!loaded) {
121575
+ record = store.readWal(name);
121576
+ loaded = true;
121577
+ }
121578
+ return record;
121579
+ };
121580
+ return { name, type: "payment-proof", phase: "part", get record() {
121581
+ return read();
121582
+ }, get state() {
121583
+ return String(read()?.state);
121584
+ } };
121585
+ }
121275
121586
  function classify(name, record) {
121276
121587
  const state = String(record?.state);
121277
121588
  if (name.startsWith("deposit-") && record?.schema === DEPOSIT_WAL_SCHEMA) {
@@ -121282,7 +121593,7 @@ function classify(name, record) {
121282
121593
  const phase = state === "receipt" && record?.receiptFinality === "never-finalized" ? "void" : { quoted: "in-flight", ready: "in-flight", submitted: "in-flight", receipt: "done", cancelled: "void" }[state] ?? "other";
121283
121594
  return { type: "payment", phase, state };
121284
121595
  }
121285
- if (name.startsWith("resource-proof-")) return { type: "payment-proof", phase: "part", state };
121596
+ if (name.startsWith(PROOF_RECORD)) return { type: "payment-proof", phase: "part", state };
121286
121597
  if (name.startsWith("self-pay-") && record?.schema === SELF_PAY_WAL_SCHEMA) {
121287
121598
  const phase = { started: "in-flight", paid: "in-flight", exited: "done", merged: "done", released: "void", abandoned: "void" }[state] ?? "other";
121288
121599
  return { type: "unshield", phase, state };
@@ -121309,13 +121620,23 @@ function publicUrl(value) {
121309
121620
  return null;
121310
121621
  }
121311
121622
  }
121312
- function computeBalance({ store, snapshotRead, source = "local", now = Date.now(), firstDepositEstimate = false }) {
121623
+ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(), firstDepositEstimate = false, onPhase }) {
121624
+ const mark = (phase, outcome) => {
121625
+ try {
121626
+ onPhase?.(phase, outcome);
121627
+ } catch {
121628
+ }
121629
+ };
121313
121630
  const state = store.state;
121314
121631
  const decimals = Number(state.decimals);
121315
- const records = store.listWal().sort().map((name) => {
121632
+ const names = store.listWal().sort();
121633
+ mark("bal-wal-list", "n" + names.length);
121634
+ const records = names.map((name) => {
121635
+ if (name.startsWith(PROOF_RECORD)) return lazyProofEntry(store, name);
121316
121636
  const record = store.readWal(name);
121317
121637
  return { name, record, ...classify(name, record) };
121318
121638
  });
121639
+ mark("bal-wal-read", "n" + records.length);
121319
121640
  const byName = new Map(records.map((entry) => [entry.name, entry]));
121320
121641
  const reasons = [];
121321
121642
  const pendingDeposits = records.filter((entry) => entry.type === "deposit" && entry.phase !== "done" && entry.phase !== "void").map((entry) => ({
@@ -121363,6 +121684,7 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
121363
121684
  } catch {
121364
121685
  pockets = void 0;
121365
121686
  }
121687
+ mark("bal-pockets");
121366
121688
  detail.pockets = pockets ?? null;
121367
121689
  const report = (status, atomic3, next2) => ({
121368
121690
  // The one number: shielded + pockets. Null when either part is unknown.
@@ -121435,7 +121757,7 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
121435
121757
  };
121436
121758
  for (const entry of records) {
121437
121759
  const before = Object.hasOwn(snapshot.walStates, entry.name) ? snapshot.walStates[entry.name] : void 0;
121438
- const beforePhase = before === void 0 ? "absent" : classify(entry.name, { ...entry.record, state: before }).phase;
121760
+ const beforePhase = before === void 0 ? "absent" : entry.type === "payment-proof" ? entry.phase : classify(entry.name, { ...entry.record, state: before }).phase;
121439
121761
  if (entry.phase === "done" && beforePhase !== "done") {
121440
121762
  const paying = settlingPayment(entry);
121441
121763
  if (paying) {
@@ -127340,8 +127662,10 @@ async function refreshWallet({ session, store, history: walked, share }) {
127340
127662
  prepareFinalizedP03RecoveryFold(history).catch(() => {
127341
127663
  });
127342
127664
  }
127343
- function shieldedUnknown(store) {
127344
- return computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local" }).split?.shieldedAtomic == null;
127665
+ function shieldedUnknown(store, onPhase) {
127666
+ const snapshotRead = readBalanceSnapshot(store);
127667
+ onPhase?.("bal-snapshot");
127668
+ return computeBalance({ store, snapshotRead, source: "local", onPhase }).split?.shieldedAtomic == null;
127345
127669
  }
127346
127670
  var AUTO_BACKUPS_KEPT = 5;
127347
127671
  var AUTO_BACKUP_NAME = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z(-\d+)?$/;
@@ -127516,9 +127840,13 @@ function localBalance(session) {
127516
127840
  return null;
127517
127841
  }
127518
127842
  }
127519
- function localBalanceOf(store) {
127843
+ function localBalanceOf(store, onPhase) {
127520
127844
  try {
127521
- return oneBalance(computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local" }), store);
127845
+ const snapshotRead = readBalanceSnapshot(store);
127846
+ onPhase?.("bal-snapshot");
127847
+ const report = computeBalance({ store, snapshotRead, source: "local", onPhase });
127848
+ onPhase?.("bal-computed");
127849
+ return oneBalance(report, store);
127522
127850
  } catch {
127523
127851
  return null;
127524
127852
  }
@@ -127872,7 +128200,9 @@ function createWalletTools({
127872
128200
  }) {
127873
128201
  let stale;
127874
128202
  try {
127875
- stale = shieldedUnknown(session.openStore());
128203
+ const store = session.openStore();
128204
+ onPhase("mcp-stale-open");
128205
+ stale = shieldedUnknown(store, (phase, outcome) => onPhase(`gate:${phase}`, outcome));
127876
128206
  } catch {
127877
128207
  return;
127878
128208
  } finally {
@@ -128066,7 +128396,7 @@ function createWalletTools({
128066
128396
  return json({ ...early, ...one2 ? { balanceAtomic: one2.balanceAtomic, balance: one2.balance, breakdown: { ...one2.breakdown, ...early.breakdown ?? {} } } : {} });
128067
128397
  }
128068
128398
  gateTimes.push(["mcp-pockets", Date.now()]);
128069
- await refreshIfStale((phase) => gateTimes.push([phase, Date.now()]));
128399
+ await refreshIfStale((phase, outcome) => gateTimes.push([phase, Date.now(), outcome]));
128070
128400
  gateTimes.push(["mcp-refresh", Date.now()]);
128071
128401
  const switched = await switchGate(cap.maxPaymentAtomic, requestId, "x402_pay");
128072
128402
  if (switched) return switched;
@@ -128076,13 +128406,13 @@ function createWalletTools({
128076
128406
  } catch {
128077
128407
  timing = void 0;
128078
128408
  }
128079
- const mark = (phase, at) => {
128409
+ const mark = (phase, at, outcome) => {
128080
128410
  try {
128081
- timing?.(phase, void 0, at);
128411
+ timing?.(phase, outcome, at);
128082
128412
  } catch {
128083
128413
  }
128084
128414
  };
128085
- for (const [phase, at] of gateTimes) mark(phase, at);
128415
+ for (const [phase, at, outcome] of gateTimes) mark(phase, at, outcome);
128086
128416
  mark("mcp-gates");
128087
128417
  const payOnce = async () => {
128088
128418
  const end = autoPockets.paymentStart();
@@ -128149,15 +128479,18 @@ function createWalletTools({
128149
128479
  } catch {
128150
128480
  paidStore = void 0;
128151
128481
  }
128482
+ mark("mcp-result-open");
128152
128483
  let float;
128153
128484
  try {
128154
128485
  float = paidStore ? floatRecordOf(paidStore, requestId) : void 0;
128155
128486
  } catch {
128156
128487
  float = void 0;
128157
128488
  }
128489
+ mark("mcp-result-float");
128158
128490
  const floatPaid = float?.state === "receipt";
128159
128491
  const amounts = floatPaid ? { priceAtomic: float.priceAtomic, feeAtomic: float.feeAtomic, amountAtomic: float.paidAtomic } : { priceAtomic: receipt.amountAtomic ?? null, feeAtomic: "0", amountAtomic: receipt.amountAtomic ?? null };
128160
- const one = paidStore ? localBalanceOf(paidStore) : null;
128492
+ const one = paidStore ? localBalanceOf(paidStore, (phase, outcome) => mark(`result:${phase}`, void 0, outcome)) : null;
128493
+ mark("mcp-result-balance");
128161
128494
  if (receipt.replayed !== true) refreshAtFinality(floatPaid ? leg1SettleSlot(paidStore, float, requestId) : receipt.extra?.settleSlot);
128162
128495
  mark("mcp-result");
128163
128496
  return answerResult(paidAnswerContent({