shinjuku-shielded 0.3.26 → 0.3.27

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": "f2dc55fb5d552bef98fe2d530d37c301045501d0f750a2c9a17ddf63b1a934f3",
5
- "bytes": 11150739,
6
- "sourceCommit": "b9639dffcfdad92b73571e89117761c8f716ef83",
4
+ "sha256": "adb0f68b23e192445ecb391a89f3e05dba89f05d0177aacdb092fbea3539fa85",
5
+ "bytes": 11154518,
6
+ "sourceCommit": "e8d63cd7fd58f3f334eea244fa5dc0e7b1c5c6be",
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.26",
3
+ "version": "0.3.27",
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": "f2dc55fb",
7
- "shinjukuSha256": "f2dc55fb5d552bef98fe2d530d37c301045501d0f750a2c9a17ddf63b1a934f3",
6
+ "shinjukuRelease": "adb0f68b",
7
+ "shinjukuSha256": "adb0f68b23e192445ecb391a89f3e05dba89f05d0177aacdb092fbea3539fa85",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -119132,7 +119132,7 @@ function publicUrl(value) {
119132
119132
  return null;
119133
119133
  }
119134
119134
  }
119135
- function computeBalance({ store, snapshotRead, source = "local", now = Date.now() }) {
119135
+ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(), firstDepositEstimate = false }) {
119136
119136
  const state = store.state;
119137
119137
  const decimals = Number(state.decimals);
119138
119138
  const records = store.listWal().sort().map((name) => {
@@ -119217,6 +119217,12 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
119217
119217
  }
119218
119218
  return report("empty", 0n, proved ? `deposit ${proved.depositId} is proved but not sent: back up (shinjuku-wallet help backup-export), then rerun the same deposit command with --submit --service <facilitator URL>` : "no deposit yet: deposit one of two ways (shinjuku-wallet help deposit). 1) The more private path, shinjuku-wallet deposit --relay: no SOL is needed; its first run prints a one-time address to fund with USDC from an exchange withdrawal or an outside privacy pool. 2) Send USDC and about 0.01 SOL to your solanaFeePayer address (printed by init), then run shinjuku-wallet deposit without --relay; that deposit edge is public. If this wallet only holds restored keys or receives payments, run balance --refresh");
119219
119219
  }
119220
+ const valueRecords = records.filter((entry) => !["payment-proof", "privacy-cash", "add-funds"].includes(entry.type) && !(entry.type === "deposit" && (entry.phase === "pre-chain" || entry.phase === "void")));
119221
+ const landedDeposits = valueRecords.filter((entry) => entry.type === "deposit" && entry.phase === "done" && typeof entry.record?.receipt?.signature === "string" && entry.record.receipt.signature.length > 0 && canonicalAtomic(entry.record.amountAtomic));
119222
+ if (firstDepositEstimate && !snapshotRead?.unreadable && !state.restoredFromRecoveryText && landedDeposits.length > 0 && landedDeposits.length === valueRecords.length) {
119223
+ reasons.push("the first check of the pool history runs now; this number is your own deposit");
119224
+ return report("stale", sum2(landedDeposits.map((entry) => entry.record.amountAtomic)), refreshCommand(state));
119225
+ }
119220
119226
  reasons.push(snapshotRead?.unreadable ? `the saved balance walk is unreadable (${snapshotRead.unreadable}); it is only a cache` : state.restoredFromRecoveryText && !couldHoldValue ? "this wallet was rebuilt from the recovery text (restore) and has no balance walk yet: its value is on chain, not in this file" : "this wallet has deposit or payment records but no balance walk yet");
119221
119227
  return report("unknown", null, refreshCommand(state));
119222
119228
  }
@@ -125228,6 +125234,7 @@ async function runUnshield({
125228
125234
  return { selfPayTransaction: paid.transaction ?? null, exitTransaction: exit.signature ?? null };
125229
125235
  }
125230
125236
  var BALANCE_REFRESH_WAIT_MS = 2e4;
125237
+ var BALANCE_REFRESH_GRACE_MS = 2e3;
125231
125238
  function movingAtomic(store) {
125232
125239
  let moving = 0n;
125233
125240
  try {
@@ -125282,6 +125289,9 @@ function localBalanceOf(store) {
125282
125289
  var CAP_BALANCE_WAIT_MS = 35e3;
125283
125290
  var CAP_BALANCE_RETRY_MS = 5e3;
125284
125291
  var REFRESH_RETRY_MS = 6e4;
125292
+ var FINALITY_POLL_MS = 2e3;
125293
+ var FINALITY_WAIT_MS = 6e4;
125294
+ var PUBLIC_READ_ANSWER_MS = 3e3;
125285
125295
  var SWITCH_WAIT_MS = 4e4;
125286
125296
  var ELICIT_TIMEOUT_MS = 5 * 6e4;
125287
125297
  var POLL_SECONDS2 = 30;
@@ -125478,6 +125488,51 @@ function createWalletTools({
125478
125488
  }
125479
125489
  return refreshRun;
125480
125490
  }
125491
+ let finalityWait;
125492
+ let finalityTarget;
125493
+ let finalityDeadline = 0;
125494
+ let finalityClosed = false;
125495
+ const finalityPollMs = ops.finalityPollMs ?? FINALITY_POLL_MS;
125496
+ const finalityWaitMs = ops.finalityWaitMs ?? FINALITY_WAIT_MS;
125497
+ function refreshAtFinality(signature) {
125498
+ if (typeof signature !== "string" || !signature || finalityClosed) return;
125499
+ finalityTarget = signature;
125500
+ finalityDeadline = Date.now() + finalityWaitMs;
125501
+ if (finalityWait) return;
125502
+ const statuses = ops.signatureStatuses ?? ((signatures) => session.connection.getSignatureStatuses(signatures));
125503
+ finalityWait = (async () => {
125504
+ for (; ; ) {
125505
+ const watched = finalityTarget;
125506
+ let status;
125507
+ try {
125508
+ status = (await statuses([watched]))?.value?.[0] ?? void 0;
125509
+ } catch {
125510
+ status = void 0;
125511
+ }
125512
+ if (finalityClosed) return;
125513
+ if (watched === finalityTarget && status?.err) {
125514
+ log("MCP_FINALITY_WAIT_FAILED_TRANSACTION");
125515
+ return;
125516
+ }
125517
+ if (watched === finalityTarget && status?.confirmationStatus === "finalized") {
125518
+ log("MCP_FINALITY_REFRESH");
125519
+ await refreshShared().catch(() => {
125520
+ });
125521
+ return;
125522
+ }
125523
+ if (Date.now() + finalityPollMs > finalityDeadline) {
125524
+ log("MCP_FINALITY_WAIT_EXPIRED");
125525
+ return;
125526
+ }
125527
+ await new Promise((resolve38) => {
125528
+ const timer = setTimeout(resolve38, finalityPollMs);
125529
+ timer.unref?.();
125530
+ });
125531
+ }
125532
+ })().finally(() => {
125533
+ finalityWait = void 0;
125534
+ });
125535
+ }
125481
125536
  async function refreshIfStale() {
125482
125537
  let stale;
125483
125538
  try {
@@ -125760,6 +125815,7 @@ function createWalletTools({
125760
125815
  const floatPaid = float?.state === "receipt";
125761
125816
  const amounts = floatPaid ? { priceAtomic: float.priceAtomic, feeAtomic: float.feeAtomic, amountAtomic: float.paidAtomic } : { priceAtomic: receipt.amountAtomic ?? null, feeAtomic: "0", amountAtomic: receipt.amountAtomic ?? null };
125762
125817
  const one = paidStore ? localBalanceOf(paidStore) : null;
125818
+ if (receipt.replayed !== true) refreshAtFinality(floatPaid ? float.floatSettleTransaction : transaction);
125763
125819
  mark("mcp-result");
125764
125820
  return answerResult(paidAnswerContent({
125765
125821
  status: response.status,
@@ -125886,21 +125942,23 @@ function createWalletTools({
125886
125942
  );
125887
125943
  }
125888
125944
  const publicRead = withTimeout((ops.readPublicBalance ?? readOwnPublicBalance)({ session, store }), PUBLIC_READ_TIMEOUT_MS).then((read2) => ({ read: read2 }), (error2) => ({ error: error2 }));
125889
- let report = computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local" });
125945
+ let report = computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local", firstDepositEstimate: true });
125890
125946
  let refresh = {};
125891
125947
  const recentlyFailed = refreshFailedAt && Date.now() - refreshFailedAt < REFRESH_RETRY_MS && !refreshRun;
125892
125948
  if (report.split?.shieldedAtomic != null && report.status === "stale") {
125893
- if (!recentlyFailed) refreshShared().catch(() => {
125949
+ if (!recentlyFailed && !finalityWait) refreshShared().catch(() => {
125894
125950
  });
125895
125951
  refresh = { refreshing: true };
125896
125952
  } else if (report.split?.shieldedAtomic == null && recentlyFailed) {
125897
125953
  refresh = { refreshed: false, refreshError: refreshFailedCode ?? "mcp_refresh_failed" };
125898
125954
  } else if (report.split?.shieldedAtomic == null) {
125899
125955
  const run5 = refreshShared().then(() => "done", (error2) => ({ failed: errorCode2(error2, "mcp_refresh_failed") }));
125900
- const outcome = await Promise.race([run5, new Promise((resolve38) => {
125901
- const timer = setTimeout(() => resolve38("waiting"), balanceRefreshWaitMs);
125956
+ const waitFor = (ms) => Promise.race([run5, new Promise((resolve38) => {
125957
+ const timer = setTimeout(() => resolve38("waiting"), ms);
125902
125958
  timer.unref?.();
125903
125959
  })]);
125960
+ let outcome = await waitFor(balanceRefreshWaitMs);
125961
+ if (outcome === "waiting") outcome = await waitFor(BALANCE_REFRESH_GRACE_MS);
125904
125962
  if (outcome === "done") {
125905
125963
  try {
125906
125964
  store = session.openStore();
@@ -125914,9 +125972,28 @@ function createWalletTools({
125914
125972
  refresh = { refreshed: false, refreshError: outcome.failed };
125915
125973
  }
125916
125974
  }
125917
- const { read, error } = await publicRead;
125975
+ const answered = await Promise.race([
125976
+ publicRead,
125977
+ new Promise((resolve38) => {
125978
+ const timer = setTimeout(() => resolve38({ reading: true }), PUBLIC_READ_ANSWER_MS);
125979
+ timer.unref?.();
125980
+ })
125981
+ ]);
125982
+ if (answered.reading) {
125983
+ publicRead.then(({ error: late2 }) => {
125984
+ if (late2) log(`MCP_PUBLIC_READ_FAILED_LATE ${late2?.name ?? "Error"}`);
125985
+ });
125986
+ }
125987
+ const { read, error } = answered;
125918
125988
  let unshielded;
125919
- if (read) {
125989
+ if (answered.reading) {
125990
+ unshielded = {
125991
+ unshieldedAtomic: null,
125992
+ unshielded: null,
125993
+ unshieldedSolLamports: null,
125994
+ unshieldedReason: "reading: the RPC read of the wallet's own USDC account did not answer in 3 s; the shielded balance above does not wait for it. Call wallet_balance again later"
125995
+ };
125996
+ } else if (read) {
125920
125997
  unshielded = {
125921
125998
  unshieldedAtomic: read.unshieldedAtomic,
125922
125999
  unshielded: formatAtomic(BigInt(read.unshieldedAtomic), Number(store.state.decimals)),
@@ -126620,6 +126697,7 @@ function createWalletTools({
126620
126697
  job.result = result;
126621
126698
  log(`MCP_${kind.toUpperCase()}_DONE requestId=${job.requestId}`);
126622
126699
  if (kind !== "unshield") afterShield(job);
126700
+ else refreshAtFinality(result?.exitTransaction ?? result?.selfPayTransaction);
126623
126701
  }, (error) => {
126624
126702
  job.failedStage = job.stage;
126625
126703
  job.state = "failed";
@@ -126881,6 +126959,7 @@ function createWalletTools({
126881
126959
  };
126882
126960
  Object.defineProperties(tools, {
126883
126961
  close: { value: () => {
126962
+ finalityClosed = true;
126884
126963
  autoPockets.close();
126885
126964
  mover.close();
126886
126965
  adopter.close();