shinjuku-shielded 0.3.42 → 0.3.44

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": "f55f1fb8f1b63bf4caf94b552f06f6c3126ed8fd598d6d8fe8fc9abd7377b509",
5
- "bytes": 11232354,
6
- "sourceCommit": "602ba18e9b8035f26155973016e9d4df9beaa718",
4
+ "sha256": "99e5ce600a930373051d72e16b2fe75bec451cfbdd509439e58546d0e77058d2",
5
+ "bytes": 11247206,
6
+ "sourceCommit": "5a8c47eba8d07d89334e63f6467f17692e009d30",
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.42",
3
+ "version": "0.3.44",
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": "f55f1fb8",
7
- "shinjukuSha256": "f55f1fb8f1b63bf4caf94b552f06f6c3126ed8fd598d6d8fe8fc9abd7377b509",
6
+ "shinjukuRelease": "99e5ce60",
7
+ "shinjukuSha256": "99e5ce600a930373051d72e16b2fe75bec451cfbdd509439e58546d0e77058d2",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -96641,6 +96641,312 @@ var init_config = __esm({
96641
96641
  }
96642
96642
  });
96643
96643
 
96644
+ // wallet/src/seller/memoEcdhWorker.mjs
96645
+ import { Worker as Worker3 } from "node:worker_threads";
96646
+ function createMemoEcdhWorker(options) {
96647
+ const threads = Array.from({ length: WORKER_THREADS }, () => createThread(options));
96648
+ const compute = (memoBundle) => {
96649
+ const records = Math.floor(memoBundle.length / MEMO_RECORD_BYTES2);
96650
+ const share = Math.ceil(records / threads.length);
96651
+ const jobs = [];
96652
+ for (let index = 0; index < threads.length; index += 1) {
96653
+ const from = index * share;
96654
+ const to = Math.min(records, from + share);
96655
+ if (from >= to) continue;
96656
+ const job = threads[index].compute(memoBundle.subarray(from * MEMO_RECORD_BYTES2, to * MEMO_RECORD_BYTES2));
96657
+ if (job !== void 0) jobs.push(job);
96658
+ }
96659
+ 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: () => {
96662
+ for (const job of jobs) job.cancel();
96663
+ } };
96664
+ };
96665
+ return {
96666
+ warm: () => {
96667
+ for (const thread of threads) thread.warm();
96668
+ },
96669
+ compute: (memoBundle) => {
96670
+ try {
96671
+ return compute(memoBundle);
96672
+ } catch {
96673
+ return void 0;
96674
+ }
96675
+ },
96676
+ close: () => {
96677
+ for (const thread of threads) thread.close();
96678
+ }
96679
+ };
96680
+ }
96681
+ function createThread({ scalar, curvePointFromX, sharedXOf, log }) {
96682
+ let worker;
96683
+ let verified = false;
96684
+ let disabled = false;
96685
+ let closed = false;
96686
+ let lastStartAt = -Infinity;
96687
+ let nextId = 1;
96688
+ const pending = /* @__PURE__ */ new Map();
96689
+ const say6 = (line) => {
96690
+ try {
96691
+ log(line);
96692
+ } catch {
96693
+ }
96694
+ };
96695
+ const settleAll = () => {
96696
+ for (const resolve38 of pending.values()) resolve38(void 0);
96697
+ pending.clear();
96698
+ };
96699
+ const drop = (current) => {
96700
+ if (worker !== current) return;
96701
+ worker = void 0;
96702
+ verified = false;
96703
+ settleAll();
96704
+ current.terminate().catch(() => void 0);
96705
+ };
96706
+ const post = (current, message) => {
96707
+ try {
96708
+ current.postMessage(message);
96709
+ return true;
96710
+ } catch {
96711
+ drop(current);
96712
+ return false;
96713
+ }
96714
+ };
96715
+ const start = () => {
96716
+ if (worker !== void 0 || disabled || closed || performance.now() - lastStartAt < WORKER_RESTART_MS) return;
96717
+ lastStartAt = performance.now();
96718
+ let current;
96719
+ let expected;
96720
+ try {
96721
+ const point = curvePointFromX(CHECK_X);
96722
+ expected = [point.x.toString(16), point.y.toString(16), sharedXOf(point).toString(16)].join(":");
96723
+ current = new Worker3(WORKER_SOURCE2, { eval: true, execArgv: [], workerData: { scalar: scalar.toString() } });
96724
+ } catch (error) {
96725
+ say6(`SELLER_MEMO_ECDH_WORKER_START_FAILED ${error?.name ?? "Error"}`);
96726
+ return;
96727
+ }
96728
+ worker = current;
96729
+ const checkId = nextId++;
96730
+ pending.set(checkId, (out) => {
96731
+ if (worker !== current) return;
96732
+ if (Array.isArray(out) && out.length === 1 && Array.isArray(out[0]) && out[0].join(":") === expected) {
96733
+ verified = true;
96734
+ return;
96735
+ }
96736
+ disabled = true;
96737
+ say6("SELLER_MEMO_ECDH_WORKER_CHECK_FAILED the intake computes in the scan for this process");
96738
+ drop(current);
96739
+ });
96740
+ current.on("message", (message) => {
96741
+ try {
96742
+ const resolve38 = pending.get(message?.id);
96743
+ if (resolve38 === void 0) return;
96744
+ pending.delete(message.id);
96745
+ resolve38(message.failed === true || !Array.isArray(message.out) ? void 0 : message.out);
96746
+ } catch {
96747
+ drop(current);
96748
+ }
96749
+ });
96750
+ current.on("error", (error) => {
96751
+ if (worker === current) say6(`SELLER_MEMO_ECDH_WORKER_FAILED ${error?.name ?? "Error"}`);
96752
+ drop(current);
96753
+ });
96754
+ current.on("messageerror", () => {
96755
+ drop(current);
96756
+ });
96757
+ current.on("exit", (code) => {
96758
+ if (worker === current && !closed) say6(`SELLER_MEMO_ECDH_WORKER_EXIT ${Number.isInteger(code) ? code : "?"}`);
96759
+ drop(current);
96760
+ });
96761
+ current.unref();
96762
+ post(current, { id: checkId, check: CHECK_X.toString() });
96763
+ };
96764
+ const compute = (memoBundle) => {
96765
+ start();
96766
+ const current = worker;
96767
+ if (current === void 0) return void 0;
96768
+ const id = nextId++;
96769
+ const result = new Promise((resolve38) => {
96770
+ pending.set(id, (out) => {
96771
+ if (!verified || worker !== current || !Array.isArray(out)) {
96772
+ resolve38(void 0);
96773
+ return;
96774
+ }
96775
+ try {
96776
+ resolve38(out.map((row) => {
96777
+ if (!Array.isArray(row) || row.length !== 3 || !row.every((part) => /^[0-9a-f]{1,64}$/.test(part))) throw new Error("row");
96778
+ return [`${BigInt(`0x${row[0]}`)}:${BigInt(`0x${row[1]}`)}`, BigInt(`0x${row[2]}`)];
96779
+ }));
96780
+ } catch {
96781
+ resolve38(void 0);
96782
+ }
96783
+ });
96784
+ }).catch(() => void 0);
96785
+ if (!post(current, { id, bundle: Uint8Array.from(memoBundle) })) return void 0;
96786
+ const cancel = () => {
96787
+ const resolve38 = pending.get(id);
96788
+ if (resolve38 === void 0) return;
96789
+ pending.delete(id);
96790
+ resolve38(void 0);
96791
+ if (worker === current) post(current, { cancel: id });
96792
+ };
96793
+ return { result, cancel };
96794
+ };
96795
+ return {
96796
+ warm: () => {
96797
+ try {
96798
+ start();
96799
+ } catch {
96800
+ }
96801
+ },
96802
+ compute: (memoBundle) => {
96803
+ try {
96804
+ return compute(memoBundle);
96805
+ } catch {
96806
+ return void 0;
96807
+ }
96808
+ },
96809
+ close: () => {
96810
+ closed = true;
96811
+ const current = worker;
96812
+ worker = void 0;
96813
+ settleAll();
96814
+ current?.terminate().catch(() => void 0);
96815
+ }
96816
+ };
96817
+ }
96818
+ var MEMO_RECORD_BYTES2, WORKER_RESTART_MS, WORKER_THREADS, CHECK_X, WORKER_SOURCE2;
96819
+ var init_memoEcdhWorker = __esm({
96820
+ "wallet/src/seller/memoEcdhWorker.mjs"() {
96821
+ "use strict";
96822
+ MEMO_RECORD_BYTES2 = 200;
96823
+ WORKER_RESTART_MS = 6e4;
96824
+ WORKER_THREADS = 2;
96825
+ CHECK_X = 5n;
96826
+ WORKER_SOURCE2 = `"use strict";
96827
+ const { parentPort, workerData } = require("node:worker_threads");
96828
+ const P = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
96829
+ const RECORD_BYTES = ${MEMO_RECORD_BYTES2};
96830
+ const SLICE_MS = 8;
96831
+ const mod = (value) => { const result = value % P; return result >= 0n ? result : result + P; };
96832
+ function powMod(baseInput, exponentInput) {
96833
+ let base = mod(baseInput); let exponent = exponentInput; let result = 1n;
96834
+ while (exponent > 0n) { if ((exponent & 1n) === 1n) result = mod(result * base); base = mod(base * base); exponent >>= 1n; }
96835
+ return result;
96836
+ }
96837
+ function inverse(value) {
96838
+ const normalized = mod(value);
96839
+ if (normalized === 0n) throw new Error();
96840
+ return powMod(normalized, P - 2n);
96841
+ }
96842
+ function inversePublic(value) {
96843
+ let x = mod(value);
96844
+ if (x === 0n) throw new Error();
96845
+ let y = P; let u = 1n; let v = 0n;
96846
+ while (x !== 0n) { const q = y / x; const r = y - q * x; y = x; x = r; const next = v - q * u; v = u; u = next; }
96847
+ return mod(v);
96848
+ }
96849
+ const D = mod(-168696n * inverse(168700n));
96850
+ const LEGENDRE = (P - 1n) / 2n;
96851
+ let SQ = P - 1n; let SS = 0n;
96852
+ while ((SQ & 1n) === 0n) { SQ >>= 1n; SS += 1n; }
96853
+ const NON_RESIDUE_POWER = (() => { let z = 2n; while (powMod(z, LEGENDRE) !== P - 1n) z += 1n; return powMod(z, SQ); })();
96854
+ function sqrt(value) {
96855
+ const normalized = mod(value);
96856
+ if (normalized === 0n) return 0n;
96857
+ const w = powMod(normalized, (SQ - 1n) / 2n);
96858
+ let t = mod(w * w * normalized);
96859
+ let legendre = t;
96860
+ for (let square = 1n; square < SS; square += 1n) legendre = mod(legendre * legendre);
96861
+ if (legendre !== 1n) return undefined;
96862
+ let m = SS; let c = NON_RESIDUE_POWER; let root = mod(w * normalized);
96863
+ while (t !== 1n) {
96864
+ let i = 1n; let squared = mod(t * t);
96865
+ while (squared !== 1n) { squared = mod(squared * squared); i += 1n; if (i >= m) throw new Error(); }
96866
+ const b = powMod(c, 1n << (m - i - 1n));
96867
+ root = mod(root * b); c = mod(b * b); t = mod(t * c); m = i;
96868
+ }
96869
+ return root;
96870
+ }
96871
+ function pointFromX(x) {
96872
+ if (x >= P) throw new Error();
96873
+ const x2 = mod(x * x);
96874
+ const denominator = mod(1n - D * x2);
96875
+ if (denominator === 0n) throw new Error();
96876
+ const y = sqrt(mod((x2 + 1n) * inversePublic(denominator)));
96877
+ if (y === undefined) throw new Error();
96878
+ return { x, y };
96879
+ }
96880
+ const toExtended = (point) => ({ x: point.x, y: point.y, t: mod(point.x * point.y), z: 1n });
96881
+ const toTable = (point) => ({ x: point.x, y: point.y, t: point.t, z: point.z, dt: mod(D * point.t) });
96882
+ function addTable(left, right) {
96883
+ const a = mod(left.x * right.x); const b = mod(left.y * right.y);
96884
+ const c = mod(left.t * right.dt); const d = mod(left.z * right.z);
96885
+ const h = b + a; const e = mod((left.x + left.y) * (right.x + right.y) - h);
96886
+ const f = d - c; const g = d + c;
96887
+ return { x: mod(e * f), y: mod(g * h), t: mod(e * h), z: mod(f * g) };
96888
+ }
96889
+ function double(point, withT) {
96890
+ const a = mod(point.x * point.x); const b = mod(point.y * point.y);
96891
+ const c = mod(2n * point.z * point.z); const sum = point.x + point.y;
96892
+ const e = mod(sum * sum - a - b); const g = b - a; const f = g - c; const h = -a - b;
96893
+ return { x: mod(e * f), y: mod(g * h), t: withT ? mod(e * h) : 0n, z: mod(f * g) };
96894
+ }
96895
+ function sharedX(point, scalar) {
96896
+ const table = [toTable(toExtended({ x: 0n, y: 1n })), toTable(toExtended(point))];
96897
+ for (let index = 2; index < 16; index += 1) table.push(toTable(addTable(table[index - 1], table[1])));
96898
+ const windows = scalar === 0n ? 1 : Math.ceil(scalar.toString(2).length / 4);
96899
+ let result = table[Number((scalar >> BigInt((windows - 1) * 4)) & 15n)];
96900
+ for (let window = windows - 2; window >= 0; window -= 1) {
96901
+ for (let bit = 0; bit < 4; bit += 1) result = double(result, bit === 3);
96902
+ result = addTable(result, table[Number((scalar >> BigInt(window * 4)) & 15n)]);
96903
+ }
96904
+ return mod(result.x * inverse(result.z));
96905
+ }
96906
+ const scalar = BigInt(workerData.scalar);
96907
+ const cancelled = new Set();
96908
+ const queue = [];
96909
+ let running = false;
96910
+ function entry(x) { const point = pointFromX(x); return [point.x.toString(16), point.y.toString(16), sharedX(point, scalar).toString(16)]; }
96911
+ async function run() {
96912
+ running = true;
96913
+ while (queue.length > 0) {
96914
+ const job = queue.shift();
96915
+ for (const id of cancelled) if (id < job.id) cancelled.delete(id);
96916
+ // A job cancelled while it waited in the queue is not started.
96917
+ if (cancelled.has(job.id)) { cancelled.delete(job.id); parentPort.postMessage({ id: job.id, out: [] }); continue; }
96918
+ const out = [];
96919
+ try {
96920
+ if (job.check !== undefined) out.push(entry(BigInt(job.check)));
96921
+ else {
96922
+ const bundle = job.bundle;
96923
+ let sliceStart = performance.now();
96924
+ for (let offset = 0; offset + RECORD_BYTES <= bundle.length; offset += RECORD_BYTES) {
96925
+ if (performance.now() - sliceStart >= SLICE_MS) {
96926
+ await new Promise((resolveTurn) => { setImmediate(resolveTurn); });
96927
+ sliceStart = performance.now();
96928
+ if (cancelled.has(job.id)) break;
96929
+ }
96930
+ try { out.push(entry(BigInt("0x" + Buffer.from(bundle.subarray(offset, offset + 32)).toString("hex")))); }
96931
+ catch { /* no point: the scan refuses or skips it as before */ }
96932
+ }
96933
+ }
96934
+ parentPort.postMessage({ id: job.id, out: cancelled.delete(job.id) ? [] : out });
96935
+ } catch {
96936
+ parentPort.postMessage({ id: job.id, failed: true });
96937
+ }
96938
+ }
96939
+ running = false;
96940
+ }
96941
+ parentPort.on("message", (message) => {
96942
+ if (message.cancel !== undefined) { cancelled.add(message.cancel); return; }
96943
+ queue.push(message);
96944
+ if (!running) run();
96945
+ });
96946
+ `;
96947
+ }
96948
+ });
96949
+
96644
96950
  // wallet/src/seller/service.mjs
96645
96951
  import { createServer } from "node:http";
96646
96952
  import { randomBytes as randomBytes17 } from "node:crypto";
@@ -96770,12 +97076,19 @@ async function createSellerAdapter({
96770
97076
  const signingBytes = Buffer.from(config.signingKey.slice(2), "hex");
96771
97077
  const signerPublicKey = `0x${Buffer.from(secp256k1.getPublicKey(signingBytes, true)).toString("hex")}`;
96772
97078
  deriveShieldedSolanaP03Recipient({ eta: config.eta, resourceNonce: randomBytes17(32), poolDomain: BigInt(profile.poolDomain) });
97079
+ const ecdhScalar = config.eta % SHIELDED_SOLANA_P03_JUBJUB_SCALAR_MODULUS;
97080
+ const sharedXOf = (point) => shieldedSolanaP03ScalarMultiply(point, ecdhScalar).x;
97081
+ const sharedXByPoint = /* @__PURE__ */ new Map();
97082
+ let precomputesRunning = 0;
96773
97083
  const scanner = new ShieldedSolanaP03MemoScanner({ ecdh: {
96774
- deriveSharedX: (point) => shieldedSolanaP03ScalarMultiply(
96775
- point,
96776
- config.eta % SHIELDED_SOLANA_P03_JUBJUB_SCALAR_MODULUS
96777
- ).x
97084
+ deriveSharedX: (point) => sharedXByPoint.get(`${point.x}:${point.y}`) ?? sharedXOf(point)
96778
97085
  } });
97086
+ const memoEcdh = createMemoEcdhWorker({
97087
+ scalar: ecdhScalar,
97088
+ curvePointFromX: shieldedSolanaP03CurvePointFromX,
97089
+ sharedXOf,
97090
+ log: (line) => console.error(line)
97091
+ });
96779
97092
  const readChainAnchor = createAnchorReader({ connection: memoizeFinalizedReads(connection), profile });
96780
97093
  let anchorRequest;
96781
97094
  const requestFacilitatorAnchor = () => anchorRequest ??= (async () => {
@@ -97178,15 +97491,48 @@ async function createSellerAdapter({
97178
97491
  try {
97179
97492
  if (!offer.outboundJson) {
97180
97493
  const parsed = parseSolanaP03HttpPaymentPayload(payment.payload);
97181
- const auth = await issuer(offer.resource, payment.accepted.amount).authenticate({
97182
- requirements: payment.accepted,
97183
- resource: payment.resource,
97184
- publicInput7: parsed.publicInputs[7]
97185
- });
97186
- mark("intake-authenticated");
97187
- const intakeRead = readAnchor();
97188
- intakeRead.catch(() => void 0);
97189
- const recoveredNote = await scanner.recoverMerchantNoteYielding({ parsed, authenticatedQuote: auth });
97494
+ const quoteIssuer = issuer(offer.resource, payment.accepted.amount);
97495
+ const authInput = { requirements: payment.accepted, resource: payment.resource, publicInput7: parsed.publicInputs[7] };
97496
+ await quoteIssuer.authenticateForClaim(authInput);
97497
+ const authenticated = quoteIssuer.authenticate(authInput);
97498
+ authenticated.catch(() => void 0);
97499
+ const owned = { keys: [], done: false, cancel: void 0 };
97500
+ let precomputed;
97501
+ const job = precomputesRunning < MEMO_PRECOMPUTES_MAX ? memoEcdh.compute(parsed.memoBundle) : void 0;
97502
+ if (job !== void 0) {
97503
+ precomputesRunning += 1;
97504
+ owned.cancel = job.cancel;
97505
+ precomputed = job.result.then((entries) => {
97506
+ if (entries === void 0 || owned.done) return;
97507
+ for (const [key, sharedX] of entries) {
97508
+ if (sharedXByPoint.has(key)) continue;
97509
+ sharedXByPoint.set(key, sharedX);
97510
+ owned.keys.push(key);
97511
+ }
97512
+ }).catch(() => void 0).finally(() => {
97513
+ precomputesRunning -= 1;
97514
+ });
97515
+ }
97516
+ let recoveredNote;
97517
+ let intakeRead;
97518
+ try {
97519
+ const auth = await authenticated;
97520
+ mark("intake-authenticated");
97521
+ intakeRead = readAnchor();
97522
+ intakeRead.catch(() => void 0);
97523
+ if (precomputed !== void 0) {
97524
+ let timer;
97525
+ await Promise.race([precomputed, new Promise((resolveWait) => {
97526
+ timer = setTimeout(resolveWait, MEMO_PRECOMPUTE_WAIT_MS);
97527
+ })]);
97528
+ clearTimeout(timer);
97529
+ }
97530
+ recoveredNote = await scanner.recoverMerchantNoteYielding({ parsed, authenticatedQuote: auth });
97531
+ } finally {
97532
+ owned.done = true;
97533
+ owned.cancel?.();
97534
+ for (const key of owned.keys) sharedXByPoint.delete(key);
97535
+ }
97190
97536
  mark("intake-note-recovered");
97191
97537
  const chain = await intakeRead;
97192
97538
  intakeChain = chain;
@@ -97344,6 +97690,7 @@ async function createSellerAdapter({
97344
97690
  };
97345
97691
  await put(nonce, offer);
97346
97692
  mark("challenge");
97693
+ memoEcdh.warm();
97347
97694
  return { status: 402, paymentRequired: issued.paymentRequired };
97348
97695
  }
97349
97696
  const server = createServer({ maxHeaderSize: 192 * 1024 }, async (request, response) => {
@@ -97398,6 +97745,7 @@ async function createSellerAdapter({
97398
97745
  }
97399
97746
  }
97400
97747
  closed = true;
97748
+ memoEcdh.close();
97401
97749
  for (const timer of followUps.values()) clearTimeout(timer);
97402
97750
  followUps.clear();
97403
97751
  };
@@ -97415,7 +97763,7 @@ async function createSellerAdapter({
97415
97763
  }));
97416
97764
  return { server, handle, close, signerPublicKey, settledTransactions, offerSummaries };
97417
97765
  }
97418
- 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, 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;
97766
+ 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;
97419
97767
  var init_service = __esm({
97420
97768
  "wallet/src/seller/service.mjs"() {
97421
97769
  "use strict";
@@ -97432,6 +97780,7 @@ var init_service = __esm({
97432
97780
  init_config();
97433
97781
  init_receiptTransaction();
97434
97782
  init_timing();
97783
+ init_memoEcdhWorker();
97435
97784
  BINDING = "carbon-shielded-exact/svm-v3";
97436
97785
  SCHEMA2 = "carbon-independent-seller-offers/v1";
97437
97786
  OFFERS_LAYOUT = "per-offer-v1";
@@ -97466,6 +97815,8 @@ var init_service = __esm({
97466
97815
  ANCHOR_REQUEST_TIMEOUT_MS2 = 9e4;
97467
97816
  ANCHOR_POLL_ATTEMPTS = 15;
97468
97817
  ANCHOR_POLL_MS = 2e3;
97818
+ MEMO_PRECOMPUTES_MAX = 2;
97819
+ MEMO_PRECOMPUTE_WAIT_MS = 1e3;
97469
97820
  PRE_SETTLE_REUSE_MARGIN_S = 60;
97470
97821
  PRE_SETTLE_REUSE_MAX_AGE_MS = 2e4;
97471
97822
  FINALIZED_MEMO_MAX_AGE_MS = 1e3;
@@ -126800,7 +127151,18 @@ function createWalletTools({
126800
127151
  ...share ? { share } : {}
126801
127152
  });
126802
127153
  let lastWriterEndedAt = 0;
126803
- const refreshWalk = ops.refreshWalk ?? (ops.refresh ? void 0 : (store) => walkWalletHistory(session, store));
127154
+ let paysInFlight = 0;
127155
+ let refreshDeferred = false;
127156
+ let refreshForeground = false;
127157
+ let refreshRunDeferred = false;
127158
+ const REFRESH_DEFERRED = /* @__PURE__ */ Symbol("deferred refresh");
127159
+ const runDeferredRefresh = () => {
127160
+ if (!refreshDeferred || paysInFlight !== 0 || finalityWait || refreshRun || finalityClosed) return;
127161
+ refreshDeferred = false;
127162
+ refreshShared({ background: true }).catch(() => {
127163
+ });
127164
+ };
127165
+ const refreshWalk = ops.refreshWalk ?? (ops.refresh ? void 0 : (store, share) => walkWalletHistory(session, store, share));
126804
127166
  const errorCode2 = (error, fallback) => describeError(error, { fallback, safeText: SAFE_TEXT }).split(/[\s:;(]/, 1)[0];
126805
127167
  const underLease = (task) => session.serial(async () => {
126806
127168
  let release;
@@ -126899,10 +127261,16 @@ function createWalletTools({
126899
127261
  };
126900
127262
  const withPoolSwitch = (tool) => ({ ...tool, run: async (...args) => {
126901
127263
  let output2;
127264
+ const paying = tool.name === "x402_pay";
127265
+ if (paying) paysInFlight += 1;
126902
127266
  try {
126903
127267
  output2 = await tool.run(...args);
126904
127268
  } finally {
126905
127269
  if (tool.annotations?.readOnlyHint !== true) lastWriterEndedAt = Date.now();
127270
+ if (paying) {
127271
+ paysInFlight -= 1;
127272
+ runDeferredRefresh();
127273
+ }
126906
127274
  }
126907
127275
  if (!succession || !output2 || output2.isError || typeof output2.text !== "string") return output2;
126908
127276
  const read = readSwitch();
@@ -126951,9 +127319,20 @@ function createWalletTools({
126951
127319
  });
126952
127320
  if (ops.oneTimeAdopt !== false) adopter.start();
126953
127321
  function refreshShared({ background = false } = {}) {
127322
+ if (refreshRun && !background && refreshRunDeferred) return refreshRun.then(() => refreshShared(), () => refreshShared());
127323
+ if (refreshRun && !background) refreshForeground = true;
126954
127324
  if (!refreshRun) {
126955
127325
  refreshInBackground = background;
127326
+ refreshForeground = !background;
127327
+ refreshRunDeferred = false;
126956
127328
  const calledAt = Date.now();
127329
+ const deferNow = () => {
127330
+ if (!background || refreshForeground || paysInFlight === 0) return false;
127331
+ refreshRunDeferred = true;
127332
+ refreshDeferred = true;
127333
+ log("MCP_REFRESH_DEFERRED");
127334
+ return true;
127335
+ };
126957
127336
  refreshRun = (async () => {
126958
127337
  let early;
126959
127338
  if (background && refreshWalk) {
@@ -126961,18 +127340,21 @@ function createWalletTools({
126961
127340
  const store = session.openStore();
126962
127341
  const records = JSON.stringify(captureWalStates(store));
126963
127342
  const pool2 = store.state.pool;
126964
- early = { records, pool: pool2, history: await refreshWalk(store) };
127343
+ early = { records, pool: pool2, history: await refreshWalk(store, { notBeforeMs: Math.max(calledAt, lastWriterEndedAt) }) };
126965
127344
  } catch {
126966
127345
  early = void 0;
126967
127346
  }
126968
127347
  }
126969
127348
  return underLease((store) => {
127349
+ if (deferNow()) return REFRESH_DEFERRED;
127350
+ refreshDeferred = false;
126970
127351
  const same2 = early !== void 0 && early.pool === store.state.pool && early.records === JSON.stringify(captureWalStates(store));
126971
127352
  if (early !== void 0 && !same2) log("MCP_REFRESH_WALK_AGAIN");
126972
127353
  const share = early !== void 0 && !same2 ? { notBeforeMs: Math.max(calledAt, lastWriterEndedAt) } : void 0;
126973
127354
  return refreshStep(store, same2 ? early.history : void 0, share);
126974
127355
  });
126975
- })().then(() => {
127356
+ })().then((result) => {
127357
+ if (result === REFRESH_DEFERRED) return;
126976
127358
  refreshFailedAt = 0;
126977
127359
  log("MCP_REFRESH_DONE");
126978
127360
  }, (error) => {
@@ -126981,8 +127363,12 @@ function createWalletTools({
126981
127363
  log(`MCP_REFRESH_FAILED ${refreshFailedCode}`);
126982
127364
  throw error;
126983
127365
  }).finally(() => {
127366
+ const deferred = refreshRunDeferred;
126984
127367
  refreshRun = void 0;
126985
127368
  refreshInBackground = false;
127369
+ refreshForeground = false;
127370
+ refreshRunDeferred = false;
127371
+ if (deferred || refreshDeferred) runDeferredRefresh();
126986
127372
  });
126987
127373
  }
126988
127374
  return refreshRun;
@@ -127053,6 +127439,7 @@ function createWalletTools({
127053
127439
  finalityWait = void 0;
127054
127440
  if (finalityClosed || finalityTarget === watched) finalityTarget = void 0;
127055
127441
  else startFinalityWait();
127442
+ runDeferredRefresh();
127056
127443
  });
127057
127444
  }
127058
127445
  async function refreshIfStale() {
@@ -127473,7 +127860,7 @@ function createWalletTools({
127473
127860
  let refresh = {};
127474
127861
  const recentlyFailed = refreshFailedAt && Date.now() - refreshFailedAt < REFRESH_RETRY_MS && !refreshRun;
127475
127862
  if (report.split?.shieldedAtomic != null && report.status === "stale") {
127476
- if (!recentlyFailed && !finalityWait) refreshShared().catch(() => {
127863
+ if (!recentlyFailed && (!finalityWait || refreshDeferred)) refreshShared().catch(() => {
127477
127864
  });
127478
127865
  refresh = { refreshing: true };
127479
127866
  } else if (report.split?.shieldedAtomic == null && recentlyFailed) {