shinjuku-shielded 0.3.26 → 0.3.28

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": "dd6ce54a50e0e58be863f647620b767cb760d1278ee089b74c10c98068383047",
5
+ "bytes": 11159107,
6
+ "sourceCommit": "b5316573de1f09bb207ce09a78d5ec4d02fc8035",
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.28",
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": "dd6ce54a",
7
+ "shinjukuSha256": "dd6ce54a50e0e58be863f647620b767cb760d1278ee089b74c10c98068383047",
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
  }
@@ -121947,7 +121953,8 @@ var CHAIN_RECHECK_MS = 6 * 60 * 6e4;
121947
121953
  var MCP_POLL_LIMIT_MS = 3 * 6e4;
121948
121954
  var firstCode5 = (error) => String(error?.message ?? error ?? "").split(/[\s:;(]/, 1)[0];
121949
121955
  function createMoveScheduler({ session, underLease, log = () => {
121950
- }, env = process.env, deps = {} }) {
121956
+ }, env = process.env, onSettled = () => {
121957
+ }, deps = {} }) {
121951
121958
  const now = deps.now ?? Date.now;
121952
121959
  const home = deps.home ?? setupHome(env);
121953
121960
  const readConfig = deps.readConfig ?? (() => readSetupConfig(home));
@@ -121981,6 +121988,7 @@ function createMoveScheduler({ session, underLease, log = () => {
121981
121988
  let interval;
121982
121989
  let closed = false;
121983
121990
  const failedAt = /* @__PURE__ */ new Map();
121991
+ const lastCredit = /* @__PURE__ */ new Map();
121984
121992
  const leaseFor = (pool) => async (task) => {
121985
121993
  if (resolve21(homeWalletPath(home, pool)) === sessionPath) return underLease(() => task());
121986
121994
  let free;
@@ -122064,6 +122072,14 @@ function createMoveScheduler({ session, underLease, log = () => {
122064
122072
  withTargetLease: leaseFor(move.to.pool)
122065
122073
  });
122066
122074
  log(`MCP_MOVE ${move.from.pool.slice(0, 8)} ${result.state}${result.code ? ` ${result.code}` : ""}`);
122075
+ const credit = (result.legs ?? []).map((leg) => leg?.creditTransaction).filter((signature) => typeof signature === "string" && signature).at(-1);
122076
+ if (credit && credit !== lastCredit.get(move.from.pool)) {
122077
+ lastCredit.set(move.from.pool, credit);
122078
+ try {
122079
+ onSettled(credit);
122080
+ } catch {
122081
+ }
122082
+ }
122067
122083
  } catch (error) {
122068
122084
  const code = firstCode5(error) || "wallet_move_leg_failed";
122069
122085
  result = { state: code === "wallet_locked" ? "waiting" : "failed", code, fromPool: move.from.pool, toPool: move.to.pool };
@@ -122903,10 +122919,16 @@ var CARRY_WAIT_CODES = /* @__PURE__ */ new Set([
122903
122919
  "wallet_locked"
122904
122920
  ]);
122905
122921
  var carryRefusedForGood = (carry) => carry?.state === "refused" && !CARRY_WAIT_CODES.has(carry.code);
122906
- function pocketCarryText(carry) {
122907
- if (carry?.state !== "refused") return "";
122922
+ function pocketCarryReason(carry) {
122923
+ if (carry && CARRY_DONE.has(carry.state)) return { done: true, waits: false, code: null, reason: "" };
122924
+ if (carry?.state !== "refused") return { done: false, waits: true, code: null, reason: "the wallet has not finished its check of the pool switch" };
122908
122925
  const code = String(carry.code ?? "");
122909
122926
  const reason = code === "p03_pocket_carry_source_fill_pending" || code === "p03_pocket_carry_source_payment_pending" ? "a pocket top-up or a pocket payment is not final yet" : code === "wallet_locked" ? "another wallet command uses the old pool's wallet now" : CARRY_WAIT_CODES.has(code) ? "the wallet has not finished its check of the pool switch" : code === "p03_pocket_carry_target_not_empty" ? "the new pool's wallet already has pocket accounts of its own" : "the pocket records of the two wallets do not match";
122927
+ return { done: false, waits: CARRY_WAIT_CODES.has(code), code, reason };
122928
+ }
122929
+ function pocketCarryText(carry) {
122930
+ if (carry?.state !== "refused") return "";
122931
+ const { code, reason } = pocketCarryReason(carry);
122910
122932
  if (CARRY_WAIT_CODES.has(code)) {
122911
122933
  return ` Your pocket accounts stay in the old pool's records for now (${reason}). The money in them is safe. The wallet tries again by itself in a minute.`;
122912
122934
  }
@@ -123136,7 +123158,9 @@ function createSuccessionScheduler(options) {
123136
123158
  },
123137
123159
  log = () => {
123138
123160
  },
123139
- carry = carryPocketBook
123161
+ carry = carryPocketBook,
123162
+ onSettled = () => {
123163
+ }
123140
123164
  } = options;
123141
123165
  const now = options.now ?? Date.now;
123142
123166
  const randomInt9 = options.randomInt ?? cryptoRandomInt;
@@ -123331,6 +123355,12 @@ function createSuccessionScheduler(options) {
123331
123355
  } catch {
123332
123356
  }
123333
123357
  }
123358
+ if (counts.legsDone > (job.legsDone ?? 0) && counts.transactions.length) {
123359
+ try {
123360
+ onSettled(counts.transactions.at(-1));
123361
+ } catch {
123362
+ }
123363
+ }
123334
123364
  if (result.state === "moved") {
123335
123365
  if ((prepared.extraAccounts ?? 0) > 0) return save2(store, job, { ...counts, attempts: 0, lastCode: void 0, nextTryAtMs: now() });
123336
123366
  return save2(store, job, { ...counts, state: "moved", attempts: 0, lastCode: void 0, nextTryAtMs: void 0 });
@@ -123533,11 +123563,30 @@ function createSuccessionScheduler(options) {
123533
123563
  }
123534
123564
  return views;
123535
123565
  }
123566
+ function pocketCarries() {
123567
+ const carries = [];
123568
+ for (const entry of listEntries()) {
123569
+ let job;
123570
+ try {
123571
+ job = readSuccessionJob(storeOf(entry.from), entry.from);
123572
+ } catch {
123573
+ job = void 0;
123574
+ }
123575
+ if (typeof job?.to !== "string") continue;
123576
+ carries.push({
123577
+ from: job.from,
123578
+ to: job.to,
123579
+ pocketCarry: job.pocketCarry ? { state: job.pocketCarry.state, code: job.pocketCarry.code ?? null } : null
123580
+ });
123581
+ }
123582
+ return carries;
123583
+ }
123536
123584
  return Object.freeze({
123537
123585
  tick,
123538
123586
  beforePay,
123539
123587
  status,
123540
123588
  openJobs,
123589
+ pocketCarries,
123541
123590
  running: () => Boolean(active),
123542
123591
  acknowledge(from, state) {
123543
123592
  try {
@@ -123572,6 +123621,7 @@ function startSuccessionScheduler({ store, openStore, session, underLease, log =
123572
123621
  status: () => [],
123573
123622
  acknowledge: () => false,
123574
123623
  openJobs: () => [],
123624
+ pocketCarries: () => [],
123575
123625
  running: () => false
123576
123626
  });
123577
123627
  }
@@ -125228,6 +125278,7 @@ async function runUnshield({
125228
125278
  return { selfPayTransaction: paid.transaction ?? null, exitTransaction: exit.signature ?? null };
125229
125279
  }
125230
125280
  var BALANCE_REFRESH_WAIT_MS = 2e4;
125281
+ var BALANCE_REFRESH_GRACE_MS = 2e3;
125231
125282
  function movingAtomic(store) {
125232
125283
  let moving = 0n;
125233
125284
  try {
@@ -125282,6 +125333,9 @@ function localBalanceOf(store) {
125282
125333
  var CAP_BALANCE_WAIT_MS = 35e3;
125283
125334
  var CAP_BALANCE_RETRY_MS = 5e3;
125284
125335
  var REFRESH_RETRY_MS = 6e4;
125336
+ var FINALITY_POLL_MS = 2e3;
125337
+ var FINALITY_WAIT_MS = 6e4;
125338
+ var PUBLIC_READ_ANSWER_MS = 3e3;
125285
125339
  var SWITCH_WAIT_MS = 4e4;
125286
125340
  var ELICIT_TIMEOUT_MS = 5 * 6e4;
125287
125341
  var POLL_SECONDS2 = 30;
@@ -125346,7 +125400,7 @@ function createWalletTools({
125346
125400
  deps: ops.autoPockets ?? {}
125347
125401
  });
125348
125402
  if (money.autoPockets === true) autoPockets.start();
125349
- const mover = createMoveScheduler({ session, underLease, log, deps: ops.move && typeof ops.move === "object" ? ops.move : {} });
125403
+ const mover = createMoveScheduler({ session, underLease, log, onSettled: refreshAtFinality, deps: ops.move && typeof ops.move === "object" ? ops.move : {} });
125350
125404
  if (ops.move !== false) mover.start();
125351
125405
  const succession = ops.succession === false ? void 0 : {
125352
125406
  successionStatus,
@@ -125452,7 +125506,9 @@ function createWalletTools({
125452
125506
  ...eta === void 0 ? {} : { etaSeconds: eta },
125453
125507
  ...Number.isInteger(item.legsTotal) ? { legsDone: Number.isInteger(item.legsDone) ? item.legsDone : 0, legsTotal: item.legsTotal } : {},
125454
125508
  ...typeof item.lastCode === "string" && item.lastCode ? { code: item.lastCode } : {},
125455
- ...Number.isFinite(item.updatedAtMs) ? { updatedAt: new Date(item.updatedAtMs).toISOString() } : {}
125509
+ ...Number.isFinite(item.updatedAtMs) ? { updatedAt: new Date(item.updatedAtMs).toISOString() } : {},
125510
+ // The pocket book carry (scheduler.mjs carryPockets): a refused carry keeps the pockets in the old pool's records.
125511
+ ...item.pocketCarry && typeof item.pocketCarry.state === "string" ? { pocketCarry: { state: item.pocketCarry.state, code: typeof item.pocketCarry.code === "string" ? item.pocketCarry.code : null } } : {}
125456
125512
  };
125457
125513
  });
125458
125514
  };
@@ -125478,6 +125534,51 @@ function createWalletTools({
125478
125534
  }
125479
125535
  return refreshRun;
125480
125536
  }
125537
+ let finalityWait;
125538
+ let finalityTarget;
125539
+ let finalityDeadline = 0;
125540
+ let finalityClosed = false;
125541
+ const finalityPollMs = ops.finalityPollMs ?? FINALITY_POLL_MS;
125542
+ const finalityWaitMs = ops.finalityWaitMs ?? FINALITY_WAIT_MS;
125543
+ function refreshAtFinality(signature) {
125544
+ if (typeof signature !== "string" || !signature || finalityClosed) return;
125545
+ finalityTarget = signature;
125546
+ finalityDeadline = Date.now() + finalityWaitMs;
125547
+ if (finalityWait) return;
125548
+ const statuses = ops.signatureStatuses ?? ((signatures) => session.connection.getSignatureStatuses(signatures));
125549
+ finalityWait = (async () => {
125550
+ for (; ; ) {
125551
+ const watched = finalityTarget;
125552
+ let status;
125553
+ try {
125554
+ status = (await statuses([watched]))?.value?.[0] ?? void 0;
125555
+ } catch {
125556
+ status = void 0;
125557
+ }
125558
+ if (finalityClosed) return;
125559
+ if (watched === finalityTarget && status?.err) {
125560
+ log("MCP_FINALITY_WAIT_FAILED_TRANSACTION");
125561
+ return;
125562
+ }
125563
+ if (watched === finalityTarget && status?.confirmationStatus === "finalized") {
125564
+ log("MCP_FINALITY_REFRESH");
125565
+ await refreshShared().catch(() => {
125566
+ });
125567
+ return;
125568
+ }
125569
+ if (Date.now() + finalityPollMs > finalityDeadline) {
125570
+ log("MCP_FINALITY_WAIT_EXPIRED");
125571
+ return;
125572
+ }
125573
+ await new Promise((resolve38) => {
125574
+ const timer = setTimeout(resolve38, finalityPollMs);
125575
+ timer.unref?.();
125576
+ });
125577
+ }
125578
+ })().finally(() => {
125579
+ finalityWait = void 0;
125580
+ });
125581
+ }
125481
125582
  async function refreshIfStale() {
125482
125583
  let stale;
125483
125584
  try {
@@ -125760,6 +125861,7 @@ function createWalletTools({
125760
125861
  const floatPaid = float?.state === "receipt";
125761
125862
  const amounts = floatPaid ? { priceAtomic: float.priceAtomic, feeAtomic: float.feeAtomic, amountAtomic: float.paidAtomic } : { priceAtomic: receipt.amountAtomic ?? null, feeAtomic: "0", amountAtomic: receipt.amountAtomic ?? null };
125762
125863
  const one = paidStore ? localBalanceOf(paidStore) : null;
125864
+ if (receipt.replayed !== true) refreshAtFinality(floatPaid ? float.floatSettleTransaction : transaction);
125763
125865
  mark("mcp-result");
125764
125866
  return answerResult(paidAnswerContent({
125765
125867
  status: response.status,
@@ -125886,21 +125988,23 @@ function createWalletTools({
125886
125988
  );
125887
125989
  }
125888
125990
  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" });
125991
+ let report = computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "local", firstDepositEstimate: true });
125890
125992
  let refresh = {};
125891
125993
  const recentlyFailed = refreshFailedAt && Date.now() - refreshFailedAt < REFRESH_RETRY_MS && !refreshRun;
125892
125994
  if (report.split?.shieldedAtomic != null && report.status === "stale") {
125893
- if (!recentlyFailed) refreshShared().catch(() => {
125995
+ if (!recentlyFailed && !finalityWait) refreshShared().catch(() => {
125894
125996
  });
125895
125997
  refresh = { refreshing: true };
125896
125998
  } else if (report.split?.shieldedAtomic == null && recentlyFailed) {
125897
125999
  refresh = { refreshed: false, refreshError: refreshFailedCode ?? "mcp_refresh_failed" };
125898
126000
  } else if (report.split?.shieldedAtomic == null) {
125899
126001
  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);
126002
+ const waitFor = (ms) => Promise.race([run5, new Promise((resolve38) => {
126003
+ const timer = setTimeout(() => resolve38("waiting"), ms);
125902
126004
  timer.unref?.();
125903
126005
  })]);
126006
+ let outcome = await waitFor(balanceRefreshWaitMs);
126007
+ if (outcome === "waiting") outcome = await waitFor(BALANCE_REFRESH_GRACE_MS);
125904
126008
  if (outcome === "done") {
125905
126009
  try {
125906
126010
  store = session.openStore();
@@ -125914,9 +126018,28 @@ function createWalletTools({
125914
126018
  refresh = { refreshed: false, refreshError: outcome.failed };
125915
126019
  }
125916
126020
  }
125917
- const { read, error } = await publicRead;
126021
+ const answered = await Promise.race([
126022
+ publicRead,
126023
+ new Promise((resolve38) => {
126024
+ const timer = setTimeout(() => resolve38({ reading: true }), PUBLIC_READ_ANSWER_MS);
126025
+ timer.unref?.();
126026
+ })
126027
+ ]);
126028
+ if (answered.reading) {
126029
+ publicRead.then(({ error: late2 }) => {
126030
+ if (late2) log(`MCP_PUBLIC_READ_FAILED_LATE ${late2?.name ?? "Error"}`);
126031
+ });
126032
+ }
126033
+ const { read, error } = answered;
125918
126034
  let unshielded;
125919
- if (read) {
126035
+ if (answered.reading) {
126036
+ unshielded = {
126037
+ unshieldedAtomic: null,
126038
+ unshielded: null,
126039
+ unshieldedSolLamports: null,
126040
+ 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"
126041
+ };
126042
+ } else if (read) {
125920
126043
  unshielded = {
125921
126044
  unshieldedAtomic: read.unshieldedAtomic,
125922
126045
  unshielded: formatAtomic(BigInt(read.unshieldedAtomic), Number(store.state.decimals)),
@@ -126620,6 +126743,7 @@ function createWalletTools({
126620
126743
  job.result = result;
126621
126744
  log(`MCP_${kind.toUpperCase()}_DONE requestId=${job.requestId}`);
126622
126745
  if (kind !== "unshield") afterShield(job);
126746
+ else refreshAtFinality(result?.exitTransaction ?? result?.selfPayTransaction);
126623
126747
  }, (error) => {
126624
126748
  job.failedStage = job.stage;
126625
126749
  job.state = "failed";
@@ -126853,7 +126977,7 @@ function createWalletTools({
126853
126977
  const moveStatus = {
126854
126978
  name: "wallet_move_status",
126855
126979
  title: "Pool switch status",
126856
- description: "Use this when the user asks why their balance moved, whether the pool switch is done, or when an answer shows poolSwitch, or when wallet_balance shows movingAtomic or pools. When the facilitator switches to a new pool, this wallet moves the whole balance there by itself (no fee, no step by the user); poolSwitches lists each switch with its state (pending, scheduled, running, done, failed) and a plain message to tell the user. Also called wallet_pool_switch_status. When the facilitator retires a pool, this wallet moves its whole balance from the old pool to the new one by itself (no fee, no step by the user): each leg pays one account of the old pool to the facilitator, which credits the same amount to a one-time address of this wallet in the new pool. This tool reads the move's state and every leg (amountAtomic, state planned|paid|credited|done|failed, moveId); it pays nothing and signs nothing. state: none (no move announced), waiting or running (it continues by itself), done, failed (code, detail, and next say why and what to do).",
126980
+ description: "Use this when the user asks why their balance moved, whether the pool switch is done, or when an answer shows poolSwitch, or when wallet_balance shows movingAtomic or pools. When the facilitator switches to a new pool, this wallet moves the whole balance there by itself (no fee, no step by the user); poolSwitches lists each switch with its state (pending, scheduled, running, done, failed) and a plain message to tell the user, plus pocketCarry when the wallet tried to move the old pool's pocket records to the new pool (state carried, completed, already, none, or refused with a code; the message says what a refusal means). Also called wallet_pool_switch_status. When the facilitator retires a pool, this wallet moves its whole balance from the old pool to the new one by itself (no fee, no step by the user): each leg pays one account of the old pool to the facilitator, which credits the same amount to a one-time address of this wallet in the new pool. This tool reads the move's state and every leg (amountAtomic, state planned|paid|credited|done|failed, moveId); it pays nothing and signs nothing. state: none (no move announced), waiting or running (it continues by itself), done, failed (code, detail, and next say why and what to do).",
126857
126981
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
126858
126982
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
126859
126983
  async run() {
@@ -126881,6 +127005,7 @@ function createWalletTools({
126881
127005
  };
126882
127006
  Object.defineProperties(tools, {
126883
127007
  close: { value: () => {
127008
+ finalityClosed = true;
126884
127009
  autoPockets.close();
126885
127010
  mover.close();
126886
127011
  adopter.close();
@@ -126891,7 +127016,14 @@ function createWalletTools({
126891
127016
  startSuccession: { value: () => {
126892
127017
  if (!succession || successionHandle) return;
126893
127018
  try {
126894
- successionHandle = succession.startSuccessionScheduler({ store: session.openStore(), openStore: () => session.openStore(), session, underLease, log });
127019
+ successionHandle = succession.startSuccessionScheduler({
127020
+ store: session.openStore(),
127021
+ openStore: () => session.openStore(),
127022
+ session,
127023
+ underLease,
127024
+ log,
127025
+ deps: { onSettled: refreshAtFinality }
127026
+ });
126895
127027
  } catch (error) {
126896
127028
  log(`MCP_POOL_SWITCH_SCHEDULER_NOT_STARTED: ${error?.name ?? "Error"}`);
126897
127029
  }
@@ -132516,6 +132648,55 @@ async function spendGate(args, values, deps, io, { amountAtomic, again }) {
132516
132648
  if (!followed || index < 0 || resolve37(followed) === walletFile) return args;
132517
132649
  return [...args.slice(0, index + 1), followed, ...args.slice(index + 2)];
132518
132650
  }
132651
+ async function pocketFillGate(args, values, deps, io) {
132652
+ if (!values.has("--wallet") || values.has("--dwell-check")) return args;
132653
+ const walletFile = resolve37(values.get("--wallet"));
132654
+ const session = lazySpendSession(walletFile, values, deps);
132655
+ let handle;
132656
+ try {
132657
+ handle = (deps.startSuccessionScheduler ?? startSuccessionScheduler)({
132658
+ session,
132659
+ openStore: () => session.openStore(),
132660
+ underLease: sessionLease(session),
132661
+ log: () => {
132662
+ },
132663
+ env: deps.env
132664
+ });
132665
+ } catch {
132666
+ return args;
132667
+ }
132668
+ let carries;
132669
+ try {
132670
+ await Promise.resolve(handle.tick?.()).catch(() => {
132671
+ });
132672
+ carries = handle.pocketCarries?.() ?? [];
132673
+ } catch {
132674
+ carries = [];
132675
+ } finally {
132676
+ handle.stop?.();
132677
+ }
132678
+ if (!carries.length) return args;
132679
+ const home = setupHome(deps.env);
132680
+ const pathOf = (pool) => resolve37(homeWalletPath(home, pool));
132681
+ let target = walletFile;
132682
+ for (let hop = 0; hop < carries.length; hop += 1) {
132683
+ const next = carries.find((item) => pathOf(item.from) === target && existsSync(pathOf(item.to)));
132684
+ if (!next) break;
132685
+ target = pathOf(next.to);
132686
+ }
132687
+ for (const item of carries.filter((entry) => pathOf(entry.to) === target)) {
132688
+ const carry = pocketCarryReason(item.pocketCarry);
132689
+ if (carry.done) continue;
132690
+ if (carry.waits) {
132691
+ throw new PublicFailure(`wallet_pool_switch_wait_retry_same_request: Your facilitator switched to a new pool, and your pocket records are not in the new pool's wallet yet (${carry.reason}). Your pockets and the money in them are safe; nothing was filled or signed. Run the same pocket fill command again in 60 s`);
132692
+ }
132693
+ throw new PublicFailure(`wallet_pool_switch_failed: Your facilitator switched to a new pool, and the wallet could not move your pocket records to the new pool's wallet (${carry.reason}). Your pockets and the money in them are safe; nothing was filled or signed. Tell the operator this code. lastCode: ${carry.code}`);
132694
+ }
132695
+ if (target === walletFile) return args;
132696
+ io.err("pool switch: pocket fill uses your wallet of the facilitator's new pool\n");
132697
+ const index = args.indexOf("--wallet");
132698
+ return index < 0 ? args : [...args.slice(0, index + 1), target, ...args.slice(index + 2)];
132699
+ }
132519
132700
  async function runCurl(values, deps) {
132520
132701
  const io = deps.io;
132521
132702
  const policy = createSpendPolicy({
@@ -133864,7 +134045,7 @@ var COMMANDS = [
133864
134045
  }
133865
134046
  }
133866
134047
  },
133867
- run: (args, values, deps) => deps.pocketMain(["fill", ...args])
134048
+ run: async (args, values, deps, io) => deps.pocketMain(["fill", ...await pocketFillGate(args, values, deps, io)])
133868
134049
  },
133869
134050
  {
133870
134051
  name: "pocket release",