shinjuku-shield 0.3.112 → 0.3.113
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/README.md +5 -5
- package/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +153 -55
package/README.md
CHANGED
|
@@ -6,19 +6,19 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
|
|
|
6
6
|
command runs a local MCP server (stdio) for your agent. Your keys never
|
|
7
7
|
leave your machine.
|
|
8
8
|
|
|
9
|
-
This is version 0.3.
|
|
9
|
+
This is version 0.3.113. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files. The command is `shinjuku`.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm install -g shinjuku@0.3.
|
|
15
|
+
npm install -g shinjuku@0.3.113
|
|
16
16
|
shinjuku setup
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Type the two lines as they are. `npx install shinjuku` does not work: npx
|
|
20
20
|
reads `install` as the name of another npm package. To set up without
|
|
21
|
-
installing, type `npx shinjuku@0.3.
|
|
21
|
+
installing, type `npx shinjuku@0.3.113 setup`.
|
|
22
22
|
|
|
23
23
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
24
24
|
checked proof tools (about 191 MB), and writes `config.json`. It also writes
|
|
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
|
|
|
36
36
|
Claude Code:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
39
|
+
claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.113 mcp
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
|
-
{ "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.
|
|
45
|
+
{ "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.113", "mcp"] } } }
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
|
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": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "bfaedd12d120b4b5421cdf6c9c06b07b7e338fd6d4e74b7225f2a0d3aa150cf4",
|
|
5
|
+
"bytes": 8339853,
|
|
6
|
+
"sourceCommit": "0c37c0dea055d3c28bab9939cd5527fc290668f8",
|
|
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",
|
|
@@ -1037,5 +1037,5 @@
|
|
|
1037
1037
|
"version": "1.8.0"
|
|
1038
1038
|
}
|
|
1039
1039
|
],
|
|
1040
|
-
"publishedAt": "2026-10-
|
|
1040
|
+
"publishedAt": "2026-10-27T16:17:32.089Z"
|
|
1041
1041
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.113",
|
|
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": "
|
|
7
|
-
"shinjukuSha256": "
|
|
6
|
+
"shinjukuRelease": "bfaedd12",
|
|
7
|
+
"shinjukuSha256": "bfaedd12d120b4b5421cdf6c9c06b07b7e338fd6d4e74b7225f2a0d3aa150cf4",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -67087,6 +67087,7 @@ var init_errorCodes = __esm({
|
|
|
67087
67087
|
"p03_float_pool_unreadable_retry_same_request",
|
|
67088
67088
|
"p03_float_body_too_large",
|
|
67089
67089
|
"p03_float_busy_retry_later",
|
|
67090
|
+
"p03_float_fee_account_low",
|
|
67090
67091
|
"p03_float_not_ready_retry_later",
|
|
67091
67092
|
"p03_float_payment_in_flight_retry_later",
|
|
67092
67093
|
"p03_float_already_paid",
|
|
@@ -81130,7 +81131,7 @@ function privateSendHold(store, { accounts, notes, selfProofWalName } = {}) {
|
|
|
81130
81131
|
const self2 = typeof selfProofWalName === "string" ? (part) => selfProofWalName === `resource-proof-${sha256Hex2(Buffer.from(selfPayRequestId(part.unshieldId), "utf8"))}` : void 0;
|
|
81131
81132
|
const unsent = unsentParts(store, self2);
|
|
81132
81133
|
if (unsent === null) return null;
|
|
81133
|
-
const hold = { accounts: /* @__PURE__ */ new
|
|
81134
|
+
const hold = { accounts: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Set(), sends: [], unpacked: [] };
|
|
81134
81135
|
if (unsent.length === 0) return hold;
|
|
81135
81136
|
try {
|
|
81136
81137
|
unsent.sort(bySendPart);
|
|
@@ -81148,22 +81149,27 @@ function privateSendHold(store, { accounts, notes, selfProofWalName } = {}) {
|
|
|
81148
81149
|
const { bins } = packed;
|
|
81149
81150
|
const unpacked = unsent.filter(({ plan }) => short.has(plan.sendId));
|
|
81150
81151
|
const holding = /* @__PURE__ */ new Set();
|
|
81151
|
-
|
|
81152
|
+
const owed = /* @__PURE__ */ new Map();
|
|
81153
|
+
for (const bin of bins) for (const entry of bin.parts) owed.set(entry.plan.sendId, (owed.get(entry.plan.sendId) ?? 0n) + BigInt(entry.part.amountAtomic));
|
|
81152
81154
|
for (const bin of bins) {
|
|
81153
81155
|
if (bin.parts.length === 0 || bin.parts.some((entry) => entry.self)) continue;
|
|
81154
|
-
|
|
81156
|
+
const need = [...new Set(bin.parts.map((entry) => entry.plan.sendId))].reduce((sum2, sendId) => sum2 + owed.get(sendId), 0n);
|
|
81157
|
+
const account = BigInt(bin.entry.account.b);
|
|
81158
|
+
hold.accounts.set(BigInt(bin.entry.commitment).toString(), (bin.notes.length > 0 || need > account ? account : need).toString());
|
|
81155
81159
|
for (const note of bin.notes) hold.notes.add(BigInt(note.commitment).toString());
|
|
81156
81160
|
for (const entry of bin.parts) holding.add(entry.plan.sendId);
|
|
81157
|
-
spare += bin.value - bin.used;
|
|
81158
81161
|
}
|
|
81159
81162
|
for (const { plan } of unsent) if (holding.delete(plan.sendId)) hold.sends.push(namedSend(plan));
|
|
81160
81163
|
hold.unpacked = unpacked.map(({ plan, part }) => ({ sendId: plan.sendId, index: part.index, amountAtomic: String(part.amountAtomic) }));
|
|
81161
|
-
hold.spareAtomic = spare.toString();
|
|
81162
81164
|
} catch {
|
|
81163
81165
|
return null;
|
|
81164
81166
|
}
|
|
81165
81167
|
return hold;
|
|
81166
81168
|
}
|
|
81169
|
+
function heldSpareAtomic(hold, entry) {
|
|
81170
|
+
const need = hold.accounts.get(BigInt(entry.commitment).toString());
|
|
81171
|
+
return need === void 0 ? void 0 : BigInt(entry.account.b) - BigInt(need);
|
|
81172
|
+
}
|
|
81167
81173
|
function privateSendPartsFit(store, { accounts, notes, partAmounts: partAmounts2 }) {
|
|
81168
81174
|
const unsent = unsentParts(store);
|
|
81169
81175
|
if (unsent === null) return false;
|
|
@@ -81373,7 +81379,11 @@ var init_privateSend = __esm({
|
|
|
81373
81379
|
DIRECT_EXIT_MODE = "direct-exit";
|
|
81374
81380
|
noteFitsAccount = (account, note) => account.account?.i === void 0 || note.leafIndex === void 0 || note.leafIndex === null || BigInt(note.leafIndex) >= BigInt(account.account.i);
|
|
81375
81381
|
bySendPart = (left, right) => left.plan.sendId < right.plan.sendId ? -1 : left.plan.sendId > right.plan.sendId ? 1 : left.part.index - right.part.index;
|
|
81376
|
-
namedSend = (plan) =>
|
|
81382
|
+
namedSend = (plan) => ({
|
|
81383
|
+
...typeof plan.transferTokenId === "string" ? { sendId: plan.sendId, requestId: plan.transferTokenId, tool: "wallet_transfer_token" } : typeof plan.mcpTo !== "string" ? { sendId: plan.sendId, requestId: plan.sendId, tool: "cli" } : { sendId: plan.sendId, requestId: typeof plan.mcpRequestId === "string" ? plan.mcpRequestId : String(plan.sendId).replace(/^mcp-/, ""), tool: "wallet_unshield" },
|
|
81384
|
+
to: typeof plan.mcpTo === "string" ? plan.mcpTo : plan.to,
|
|
81385
|
+
amountAtomic: String(plan.amountAtomic)
|
|
81386
|
+
});
|
|
81377
81387
|
cancelledPart = (store, plan, part) => plan.state === "cancelled" && !partMayHaveSigned(store, part);
|
|
81378
81388
|
partCancelled = (store, sendId, part) => {
|
|
81379
81389
|
const plan = store.readWal(privateSendPlanName(sendId));
|
|
@@ -81714,7 +81724,9 @@ async function everyAccountHeld({ store, connection, programId, serviceUrl: serv
|
|
|
81714
81724
|
if (freeAccounts.length === 0) return anyHeld;
|
|
81715
81725
|
const largest = freeAccounts.reduce((max, entry) => BigInt(entry.account.b) > BigInt(max.account.b) ? entry : max);
|
|
81716
81726
|
if (!anyHeld) {
|
|
81717
|
-
|
|
81727
|
+
if (!unheldAccounts.some((entry) => (heldSpareAtomic(sendHold, entry) ?? 0n) >= BigInt(amountAtomic))) {
|
|
81728
|
+
assertAccountsNotSplit({ accounts: freeAccounts, account: largest, notes: freeNotes.filter(free), amountAtomic });
|
|
81729
|
+
}
|
|
81718
81730
|
return false;
|
|
81719
81731
|
}
|
|
81720
81732
|
const notesValue = freeNotes.reduce((sum2, entry) => sum2 + BigInt(entry.note.b), 0n);
|
|
@@ -81872,10 +81884,15 @@ async function prepareRecoveredPayment({
|
|
|
81872
81884
|
};
|
|
81873
81885
|
const unheldNotes = unspentNotes.filter((entry) => !heldByPending(entry) && !exitReserved.has(BigInt(entry.commitment).toString()) && !keptNote(entry));
|
|
81874
81886
|
const held = unheldAccounts.length !== unspentAccounts.length || unspentNotes.filter((entry) => !exitReserved.has(BigInt(entry.commitment).toString()) && !keptNote(entry)).length !== unheldNotes.length;
|
|
81875
|
-
const sendHold = deps.poolMove === true ? { accounts: /* @__PURE__ */ new
|
|
81887
|
+
const sendHold = deps.poolMove === true ? { accounts: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Set(), sends: [], unpacked: [] } : privateSendHold(store, { accounts: unheldAccounts, notes: unheldNotes, selfProofWalName: requestedWalName });
|
|
81876
81888
|
if (sendHold === null) heldByPrivateSend([]);
|
|
81877
81889
|
const sendHeld = (entry) => (entry.kind === "account" ? sendHold.accounts : sendHold.notes).has(BigInt(entry.commitment).toString());
|
|
81878
81890
|
const accounts = sendHold.accounts.size === 0 ? unheldAccounts : unheldAccounts.filter((entry) => !sendHeld(entry));
|
|
81891
|
+
const heldAccounts = sendHold.accounts.size === 0 ? [] : unheldAccounts.filter(sendHeld);
|
|
81892
|
+
const spareSpend = (outputIndex) => {
|
|
81893
|
+
const fits = heldAccounts.filter((entry) => heldSpareAtomic(sendHold, entry) >= BigInt(witnessQuote.amountAtomic));
|
|
81894
|
+
return fits.length === 0 ? void 0 : selectSpendAccount({ accounts: fits, notes: [], outputIndex, amountAtomic: witnessQuote.amountAtomic }).account;
|
|
81895
|
+
};
|
|
81879
81896
|
const freeNotes = sendHold.notes.size === 0 ? unheldNotes : unheldNotes.filter((entry) => !sendHeld(entry));
|
|
81880
81897
|
const notes = sendHold.accounts.size === 0 && sendHold.notes.size === 0 ? unheldNotes : freeNotes.filter((entry) => accounts.some((account2) => noteFitsAccount(account2, entry)));
|
|
81881
81898
|
let refusedValues;
|
|
@@ -81887,7 +81904,7 @@ async function prepareRecoveredPayment({
|
|
|
81887
81904
|
return false;
|
|
81888
81905
|
}
|
|
81889
81906
|
};
|
|
81890
|
-
|
|
81907
|
+
let wantedNotes = selection?.noteCommitments !== void 0 ? selection.noteCommitments.map((commitment) => {
|
|
81891
81908
|
const wanted = BigInt(commitment);
|
|
81892
81909
|
const found = notes.find((entry) => BigInt(entry.commitment) === wanted);
|
|
81893
81910
|
if (!found && exitReserved.has(wanted.toString())) fail20("requested_note_reserved_by_exit");
|
|
@@ -81982,14 +81999,21 @@ async function prepareRecoveredPayment({
|
|
|
81982
81999
|
if (largest && finalizedLargest !== void 0 && (underAnchor === void 0 || BigInt(finalizedLargest.account.b) > BigInt(underAnchor.account.b))) {
|
|
81983
82000
|
throw new Error("p03_quote_anchor_older_than_note_wait_next_epoch");
|
|
81984
82001
|
}
|
|
81985
|
-
|
|
81986
|
-
|
|
82002
|
+
const spareAllowed = !pays(underAnchor) && !largest && selection?.noteCommitments === void 0;
|
|
82003
|
+
const spare = spareAllowed ? spareSpend(anchor.index) : void 0;
|
|
82004
|
+
if (spareAllowed && spare === void 0 && spareSpend(history.finalizedPoolSnapshot.currentIndex) !== void 0) {
|
|
82005
|
+
throw new Error("p03_quote_anchor_older_than_note_wait_next_epoch");
|
|
82006
|
+
}
|
|
82007
|
+
if (spare !== void 0) wantedNotes = [];
|
|
82008
|
+
account = spare ?? underAnchor ?? accounts[0];
|
|
82009
|
+
sendShort = spare === void 0 && (sendHold.accounts.size > 0 || sendHold.notes.size > 0) && !pays(underAnchor);
|
|
81987
82010
|
}
|
|
81988
82011
|
if (account) assertAccountsNotSplit({ accounts, account, notes: wantedNotes, allNotes: notes, amountAtomic: witnessQuote.amountAtomic });
|
|
81989
|
-
if (sendShort && (accounts.length === 0 || [...accounts.map((entry) => entry.account.b), ...freeNotes.map((entry) => entry.note.b)].reduce((sum2, value2) => sum2 + BigInt(value2),
|
|
82012
|
+
if (sendShort && (accounts.length === 0 || [...accounts.map((entry) => entry.account.b), ...freeNotes.map((entry) => entry.note.b)].reduce((sum2, value2) => sum2 + BigInt(value2), heldAccounts.reduce((sum2, entry) => sum2 + heldSpareAtomic(sendHold, entry), 0n)) >= BigInt(witnessQuote.amountAtomic))) {
|
|
81990
82013
|
heldByPrivateSend(sendHold.sends);
|
|
81991
82014
|
}
|
|
81992
82015
|
if (!account) fail20("no_spendable_account");
|
|
82016
|
+
if (sendHeld(account) && heldSpareAtomic(sendHold, account) + wantedNotes.reduce((sum2, note) => sum2 + BigInt(note.note.b), 0n) < BigInt(witnessQuote.amountAtomic)) heldByPrivateSend(sendHold.sends);
|
|
81993
82017
|
await prepareFold(deps.buildRecoveryPath);
|
|
81994
82018
|
accountPath = buildRecoveryPath({
|
|
81995
82019
|
history,
|
|
@@ -100854,6 +100878,14 @@ function floatOutcomeWords(code2, error, t) {
|
|
|
100854
100878
|
return [code2, "Shinjuku's shared float is busy right now; nothing was paid", t.againIn(error?.retryAfterSeconds ?? 30)];
|
|
100855
100879
|
case "p03_float_not_ready_retry_later":
|
|
100856
100880
|
return [code2, "Shinjuku's shared float is not ready yet (it is being filled); nothing was paid", t.againIn(error?.retryAfterSeconds ?? 60)];
|
|
100881
|
+
// The fee payer of Shinjuku's shared pockets is low on SOL (floatPay.mjs floatRefusalError, 0.3.113): only its operator
|
|
100882
|
+
// refills it, so the words name no time and ask for no retry soon (mcp6 0.3.112 gate: "retry in a minute" failed again).
|
|
100883
|
+
case "p03_float_fee_account_low":
|
|
100884
|
+
return [
|
|
100885
|
+
code2,
|
|
100886
|
+
"the Shinjuku account that pays the network fee of this payment is low on SOL, and its operator was alerted; nothing was paid and the balance did not change",
|
|
100887
|
+
`This is not a fault of the wallet: the payment can go after the operator adds SOL to that account, and no time is known. ${t.rerun} later`
|
|
100888
|
+
];
|
|
100857
100889
|
case "p03_float_payment_in_flight_retry_later":
|
|
100858
100890
|
return [code2, "an earlier quote for this payment is still open at Shinjuku; nothing was paid", t.againIn(error?.retryAfterSeconds ?? 60)];
|
|
100859
100891
|
case "p03_float_price_above_capacity":
|
|
@@ -101870,6 +101902,8 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
101870
101902
|
let spendInputs;
|
|
101871
101903
|
let sendHold;
|
|
101872
101904
|
let heldAtomic;
|
|
101905
|
+
let heldWholeAtomic;
|
|
101906
|
+
let spareMost = 0n;
|
|
101873
101907
|
const report = (status, gross, next2, cause, largest2, change) => {
|
|
101874
101908
|
const atomic4 = gross === null || privateSendPending === null ? null : gross > privateSendPending ? gross - privateSendPending : 0n;
|
|
101875
101909
|
const built = {
|
|
@@ -101899,7 +101933,11 @@ function computeBalance({ store, snapshotRead, source = "local", now = Date.now(
|
|
|
101899
101933
|
if (spendInputs !== void 0) SPEND_INPUTS.set(built, spendInputs);
|
|
101900
101934
|
if (atomic4 !== null && sendHold && heldAtomic !== void 0) {
|
|
101901
101935
|
const aside = heldAtomic > privateSendPending ? heldAtomic : privateSendPending;
|
|
101902
|
-
|
|
101936
|
+
const whole = heldWholeAtomic > privateSendPending ? heldWholeAtomic : privateSendPending;
|
|
101937
|
+
const outside = gross > whole ? gross - whole : 0n;
|
|
101938
|
+
const most = outside > spareMost ? outside : spareMost;
|
|
101939
|
+
const cap = gross > aside ? gross - aside : 0n;
|
|
101940
|
+
SEND_HOLDS.set(built, { ...sendHold, freeAtomic: (most < cap ? most : cap).toString(), heldAtomic: aside.toString() });
|
|
101903
101941
|
}
|
|
101904
101942
|
if (largest2 !== void 0 && atomic4 !== null) {
|
|
101905
101943
|
const cap = atomic4 - BigInt(detail.successionMovableAtomic ?? "0");
|
|
@@ -102158,14 +102196,18 @@ It asks the amount, then gives a one-time address and its QR code: send USDC to
|
|
|
102158
102196
|
const entries = free.map(spendEntry);
|
|
102159
102197
|
const freeInputs = { accounts: entries.filter((entry) => entry.kind === "account"), notes: entries.filter((entry) => entry.kind === "note") };
|
|
102160
102198
|
if (!unknownInputs) spendInputs = freeInputs;
|
|
102161
|
-
sendHold = privateSendPending === 0n ? { accounts: /* @__PURE__ */ new
|
|
102199
|
+
sendHold = privateSendPending === 0n ? { accounts: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Set(), sends: [], unpacked: [] } : privateSendPending === null ? null : privateSendHold(store, freeInputs);
|
|
102162
102200
|
const isHeld = (output2) => sendHold.accounts.has(output2.commitment) || sendHold.notes.has(output2.commitment);
|
|
102163
102201
|
const notHeld = sendHold === null ? [] : free.filter((output2) => !isHeld(output2));
|
|
102164
102202
|
const open4 = sendHold === null || sendHold.accounts.size === 0 && sendHold.notes.size === 0 ? notHeld : notHeld.filter((output2) => output2.kind !== "note" || notHeld.some((other) => other.kind === "account" && noteFitsAccount(spendEntry(other), spendEntry(output2))));
|
|
102203
|
+
const spares = sendHold === null ? [] : free.filter((output2) => output2.kind === "account" && sendHold.accounts.has(output2.commitment)).map((output2) => ({ output: output2, spareAtomic: heldSpareAtomic(sendHold, spendEntry(output2)) }));
|
|
102165
102204
|
if (sendHold !== null) {
|
|
102166
|
-
|
|
102205
|
+
heldWholeAtomic = sum2(free.filter(isHeld).map((output2) => output2.valueAtomic)) + sum2(sendHold.unpacked.map((part) => part.amountAtomic));
|
|
102206
|
+
heldAtomic = heldWholeAtomic - sum2(spares.map((spare) => spare.spareAtomic));
|
|
102207
|
+
spareMost = spares.reduce((most, spare) => spare.spareAtomic > most ? spare.spareAtomic : most, 0n);
|
|
102167
102208
|
}
|
|
102168
|
-
const
|
|
102209
|
+
const openLargest = sendHold === null ? void 0 : largestOneSpend(open4);
|
|
102210
|
+
const largest = openLargest === void 0 || openLargest >= spareMost ? openLargest : spareMost;
|
|
102169
102211
|
if (settling.some((payment) => payment.inputs.some((commitment) => reserved.has(commitment) || joining.has(commitment))) || unknownInputs && settling.length) {
|
|
102170
102212
|
reasons.push(...settlingReasons);
|
|
102171
102213
|
return report("stale", null, refreshCommand(state, snapshot.programId));
|
|
@@ -102176,7 +102218,10 @@ It asks the amount, then gives a one-time address and its QR code: send USDC to
|
|
|
102176
102218
|
return report("stale", null, refreshCommand(state, snapshot.programId));
|
|
102177
102219
|
}
|
|
102178
102220
|
const anchorIndex = canonicalAtomic(snapshot.anchorIndex) ? BigInt(snapshot.anchorIndex) : void 0;
|
|
102179
|
-
detail.fundedAccounts = unknownInputs ? 0 : sendHold === null ? null :
|
|
102221
|
+
detail.fundedAccounts = unknownInputs ? 0 : sendHold === null ? null : [
|
|
102222
|
+
...open4.filter((output2) => output2.kind === "account" && BigInt(output2.valueAtomic) > 0n),
|
|
102223
|
+
...spares.filter((spare) => spare.spareAtomic > 0n).map((spare) => spare.output)
|
|
102224
|
+
].filter((output2) => anchorIndex === void 0 || BigInt(output2.leafIndex) < anchorIndex).length;
|
|
102180
102225
|
const answeredOnly = detail.inFlight.length > 0 && detail.inFlight.every((item) => item.answered === true);
|
|
102181
102226
|
const next = answeredOnly ? detail.inFlight.find((item) => item.next.startsWith("rerun"))?.next ?? "nothing to do: an answered unshield finishes its check by itself" : detail.inFlight.length ? "finish or cancel the work in detail.inFlight; the wallet runs one payment at a time" : pendingDeposits.length ? byAddFunds(pendingDeposits[0].depositId) ? `deposit ${pendingDeposits[0].depositId} of add-funds is not finished. ${continueAddFunds}` : `deposit ${pendingDeposits[0].depositId} is not finished: rerun the same deposit command with --submit --service <facilitator URL>` : pocketsUnscanned ? scanPockets2 : unspentAtomic === 0n && successionMovableAtomic > 0n ? "this pool was succeeded by a new pool: its value moves there (one move per funded deposit, the facilitator pays the fee) and counts in this balance until then" : unspentAtomic === 0n ? `nothing to spend. To add money, run:
|
|
102182
102227
|
${commandLine("add-funds")}
|
|
@@ -102188,9 +102233,11 @@ If a payment to this wallet settled, read the chain again with:
|
|
|
102188
102233
|
if (settling.length || movedInAtomic > 0n) {
|
|
102189
102234
|
reasons.push(...settlingReasons);
|
|
102190
102235
|
const [only] = settling;
|
|
102191
|
-
const sendHeldAtomic = sendHold === null || sendHold.
|
|
102236
|
+
const sendHeldAtomic = sendHold === null || sendHold.notes.size > 0 ? null : sum2(free.filter(isHeld).map((output2) => output2.valueAtomic));
|
|
102192
102237
|
const inputsAtomic = settling.length === 1 ? sum2(only.inputs.map((commitment) => unspent.get(commitment).valueAtomic)) : 0n;
|
|
102193
|
-
const
|
|
102238
|
+
const changeAtomic = inputsAtomic - (settling.length === 1 ? only.amountAtomic : 0n);
|
|
102239
|
+
const changeFreeAtomic = sendHold === null || sendHold.unpacked.length === 0 ? changeAtomic : changeAtomic > privateSendPending ? changeAtomic - privateSendPending : 0n;
|
|
102240
|
+
const changeOnly = settling.length === 1 && only.join !== true && only.exit !== true && reservedAtomic === 0n && detail.joiningAtomic === "0" && successionMovableAtomic === 0n && sendHeldAtomic !== null && unspentAtomic - sendHeldAtomic === inputsAtomic && inputsAtomic > only.amountAtomic && changeFreeAtomic > 0n;
|
|
102194
102241
|
return report(
|
|
102195
102242
|
"stale",
|
|
102196
102243
|
spendable + successionMovableAtomic,
|
|
@@ -102199,7 +102246,7 @@ If a payment to this wallet settled, read the chain again with:
|
|
|
102199
102246
|
// still settling" while the only answered item was a join).
|
|
102200
102247
|
settlingRecent ? movedInAtomic === 0n && settling.length > 0 && settling.every((payment) => payment.join) ? "account_join" : "payment_settling" : movedInAtomic > 0n ? "pool_move" : void 0,
|
|
102201
102248
|
largest,
|
|
102202
|
-
changeOnly ?
|
|
102249
|
+
changeOnly ? changeFreeAtomic : void 0
|
|
102203
102250
|
);
|
|
102204
102251
|
}
|
|
102205
102252
|
return report("current", spendable + successionMovableAtomic, next, void 0, largest);
|
|
@@ -102214,7 +102261,7 @@ function savedSpendInputs({ store, snapshotRead }) {
|
|
|
102214
102261
|
}
|
|
102215
102262
|
function savedSendHold({ store, snapshotRead }) {
|
|
102216
102263
|
try {
|
|
102217
|
-
if (privateSendPendingAtomic(store) === 0n) return { accounts: /* @__PURE__ */ new
|
|
102264
|
+
if (privateSendPendingAtomic(store) === 0n) return { accounts: /* @__PURE__ */ new Map(), notes: /* @__PURE__ */ new Set(), sends: [], unpacked: [] };
|
|
102218
102265
|
const report = computeBalance({ store, snapshotRead: snapshotRead ?? readBalanceSnapshot(store) });
|
|
102219
102266
|
return report.status === "current" && SPEND_INPUTS.has(report) ? sendHoldOf(report) ?? null : null;
|
|
102220
102267
|
} catch {
|
|
@@ -103214,6 +103261,7 @@ function floatFetch(base, seen) {
|
|
|
103214
103261
|
code: code2,
|
|
103215
103262
|
...Number.isFinite(retryAfter) && retryAfter > 0 ? { retryAfterSeconds: Math.min(Math.ceil(retryAfter), 3600) } : {},
|
|
103216
103263
|
...DECIMAL3.test(String(answer.largestAtomic ?? "")) ? { largestAtomic: String(answer.largestAtomic) } : {},
|
|
103264
|
+
...typeof answer.reason === "string" && /^[a-z_]{1,60}$/.test(answer.reason) ? { reason: answer.reason } : {},
|
|
103217
103265
|
...typeof answer.message === "string" ? { message: plainText(answer.message) } : {}
|
|
103218
103266
|
};
|
|
103219
103267
|
return new Response(null, { status: 400 });
|
|
@@ -103232,8 +103280,9 @@ function floatRefusalError(refusal3, record) {
|
|
|
103232
103280
|
return Object.assign(new Error("p03_float_busy_retry_later"), { retryAfterSeconds: 30, ...extra });
|
|
103233
103281
|
case "float_price_above_capacity":
|
|
103234
103282
|
return Object.assign(new Error("p03_float_price_above_capacity"), extra);
|
|
103283
|
+
// fee_payer_underfunded (0.3.113): the fee payer of the shared pockets needs the operator's SOL, so no retry soon helps.
|
|
103235
103284
|
case "float_not_ready":
|
|
103236
|
-
return Object.assign(new Error("p03_float_not_ready_retry_later"), { retryAfterSeconds: 60, ...extra });
|
|
103285
|
+
return refusal3.reason === "fee_payer_underfunded" ? Object.assign(new Error("p03_float_fee_account_low"), extra) : Object.assign(new Error("p03_float_not_ready_retry_later"), { retryAfterSeconds: 60, ...extra });
|
|
103237
103286
|
case "float_payment_in_flight":
|
|
103238
103287
|
return Object.assign(new Error("p03_float_payment_in_flight_retry_later"), { retryAfterSeconds: 60, ...extra });
|
|
103239
103288
|
case "float_already_paid":
|
|
@@ -103523,7 +103572,7 @@ async function payViaFloat({
|
|
|
103523
103572
|
};
|
|
103524
103573
|
store.writeWal(walName2, record);
|
|
103525
103574
|
mark("seller-sent");
|
|
103526
|
-
const
|
|
103575
|
+
const sentAtMs2 = Date.now();
|
|
103527
103576
|
const stopWaiting = new AbortController();
|
|
103528
103577
|
const watch = watchFloatTransfer({ record, fetchImpl, sleep: deps.floatStatusSleep, abort: () => stopWaiting.abort() });
|
|
103529
103578
|
const resendDispatchers = [];
|
|
@@ -103538,7 +103587,7 @@ async function payViaFloat({
|
|
|
103538
103587
|
if (wasKept) keptAgain();
|
|
103539
103588
|
const verdict = watch.verdict();
|
|
103540
103589
|
if (verdict?.state === "dead") {
|
|
103541
|
-
const sellerUnansweredSeconds = Math.round((Date.now() -
|
|
103590
|
+
const sellerUnansweredSeconds = Math.round((Date.now() - sentAtMs2) / 1e3);
|
|
103542
103591
|
const { ambiguous: _settled, ...rest } = record;
|
|
103543
103592
|
record = {
|
|
103544
103593
|
...rest,
|
|
@@ -103680,7 +103729,7 @@ async function payViaFloat({
|
|
|
103680
103729
|
...state?.state === "landed" ? { transferLanded: true } : {}
|
|
103681
103730
|
});
|
|
103682
103731
|
}
|
|
103683
|
-
const late2 = x402Header(response, "payment-response")?.success === false ? { sellerChargeFailed: true, sellerAnswerSeconds: Math.round((answeredAtMs -
|
|
103732
|
+
const late2 = x402Header(response, "payment-response")?.success === false ? { sellerChargeFailed: true, sellerAnswerSeconds: Math.round((answeredAtMs - sentAtMs2) / 1e3) } : {};
|
|
103684
103733
|
const fixable = floatSellerCanBeFixed({ httpStatus: response.status, ...sellerReason ? { sellerReason } : {}, ...late2 }) ? { sellerFixable: true } : {};
|
|
103685
103734
|
byVerdict(
|
|
103686
103735
|
await floatVerdict(record, fetchImpl, statusSleep, verdictUntil(answeredAtMs), watch.verdict()),
|
|
@@ -106348,28 +106397,31 @@ function promisedShortfall(store, amountAtomic) {
|
|
|
106348
106397
|
}
|
|
106349
106398
|
return void 0;
|
|
106350
106399
|
}
|
|
106351
|
-
function heldByPrivateSendText(sends) {
|
|
106400
|
+
function heldByPrivateSendText(sends, freeAtomic) {
|
|
106352
106401
|
const named = Array.isArray(sends) ? sends.filter((send3) => typeof send3?.requestId === "string") : [];
|
|
106402
|
+
const most = /^\d+$/.test(String(freeAtomic ?? "")) ? `One payment can use at most ${usdcWords(freeAtomic)} now, and this payment needs more. ` : "One payment cannot use this much now. ";
|
|
106403
|
+
const frees = "keeps nothing after its last part goes; an earlier part may free some money, and wallet_balance shows the most one payment can use (largestPaymentAtomic).";
|
|
106353
106404
|
if (named.length === 0) {
|
|
106354
|
-
return
|
|
106405
|
+
return `${most}A private send in progress keeps part of this money for its unsent parts; wallet_balance names it and its cancel call. The send ${frees} To pay now, stop the send, or add money with wallet_add_funds.`;
|
|
106355
106406
|
}
|
|
106356
106407
|
if (named.length === 1) {
|
|
106357
|
-
|
|
106408
|
+
const send3 = sendWords(named[0]);
|
|
106409
|
+
return `${most}${send3[0].toUpperCase()}${send3.slice(1)} keeps part of this money for its unsent parts. It ${frees} To pay now, stop the send with ${cancelCall(named[0])}, or add money with wallet_add_funds.`;
|
|
106358
106410
|
}
|
|
106359
|
-
return
|
|
106411
|
+
return `${most}${named.map(sendWords).join(" and ").replace(/^t/, "T")} keep part of this money for their unsent parts. Each ${frees} To pay now, stop a send with ${named.map(cancelCall).join(", or ")}, or add money with wallet_add_funds.`;
|
|
106360
106412
|
}
|
|
106361
106413
|
function promisedShortfallText(shortfall, amountAtomic) {
|
|
106362
106414
|
if (shortfall.error === "spend_private_send_unknown") {
|
|
106363
106415
|
return "spend_private_send_unknown: a private send of this wallet cannot be read, so the value it still owes is unknown; nothing was sent";
|
|
106364
106416
|
}
|
|
106365
|
-
if (shortfall.error === HELD_BY_PRIVATE_SEND) return `${HELD_BY_PRIVATE_SEND}: ${heldByPrivateSendText(shortfall.privateSends)} Nothing was sent.`;
|
|
106417
|
+
if (shortfall.error === HELD_BY_PRIVATE_SEND) return `${HELD_BY_PRIVATE_SEND}: ${heldByPrivateSendText(shortfall.privateSends, shortfall.freeAtomic)} Nothing was sent.`;
|
|
106366
106418
|
return `spend_private_send_reserved: ${usdcWords(shortfall.pendingAtomic)} of the private balance is promised to the unsent smaller payments of a private send; ${usdcWords(shortfall.freeAtomic)} is free and this unshield needs ${usdcWords(amountAtomic)}; nothing was sent`;
|
|
106367
106419
|
}
|
|
106368
106420
|
function assertUnshieldNotPromised(store, amountAtomic) {
|
|
106369
106421
|
const shortfall = promisedShortfall(store, amountAtomic);
|
|
106370
106422
|
if (shortfall) throw Object.assign(new Error(promisedShortfallText(shortfall, amountAtomic)), shortfall.privateSends ? { privateSends: shortfall.privateSends } : {});
|
|
106371
106423
|
}
|
|
106372
|
-
var HELD_BY_PRIVATE_SEND, cancelCall;
|
|
106424
|
+
var HELD_BY_PRIVATE_SEND, cancelCall, sendWords;
|
|
106373
106425
|
var init_promised = __esm({
|
|
106374
106426
|
"wallet/src/unshield/promised.mjs"() {
|
|
106375
106427
|
"use strict";
|
|
@@ -106378,6 +106430,11 @@ var init_promised = __esm({
|
|
|
106378
106430
|
init_usdcWords();
|
|
106379
106431
|
HELD_BY_PRIVATE_SEND = "p03_merchant_respend_value_held_by_private_send";
|
|
106380
106432
|
cancelCall = (send3) => send3.tool === "wallet_transfer_token" ? `wallet_transfer_token_status with request_id "${send3.requestId}" and action "cancel"` : send3.tool === "cli" ? `the command line: unshield-cancel --unshield-id ${send3.sendId}` : `wallet_cancel with request_id "${send3.requestId}"`;
|
|
106433
|
+
sendWords = (send3) => {
|
|
106434
|
+
const amount = /^[1-9][0-9]*$/.test(String(send3?.amountAtomic ?? "")) ? ` of ${usdcWords(send3.amountAtomic)}` : "";
|
|
106435
|
+
const to = typeof send3?.to === "string" && send3.to.length > 10 ? ` to ${send3.to.slice(0, 4)}...${send3.to.slice(-4)}` : "";
|
|
106436
|
+
return `the private send${amount}${to}`;
|
|
106437
|
+
};
|
|
106381
106438
|
}
|
|
106382
106439
|
});
|
|
106383
106440
|
|
|
@@ -106767,7 +106824,7 @@ async function assertNotPromised({ session, store, amountAtomic, leasedAt, mark,
|
|
|
106767
106824
|
ok: false,
|
|
106768
106825
|
error: "spend_private_send_reserved",
|
|
106769
106826
|
detail: `${usdcWords(pending)} of the private balance is promised to the unsent smaller payments of a private send; ${usdcWords(free)} is free and this payment needs ${usdcWords(amountAtomic)}; nothing was paid`,
|
|
106770
|
-
next:
|
|
106827
|
+
next: "Tell the user why nothing was paid and what they can do. This payment needs more than the money the private send does not keep, and the money it keeps leaves the wallet as its parts go, so a wait frees nothing. Stop its unsent parts with the cancel call wallet_balance names for it (that money stays in the wallet), or add money with wallet_add_funds, then pay again with the same request_id"
|
|
106771
106828
|
});
|
|
106772
106829
|
}
|
|
106773
106830
|
const hold = sendHoldOf(report);
|
|
@@ -106775,8 +106832,8 @@ async function assertNotPromised({ session, store, amountAtomic, leasedAt, mark,
|
|
|
106775
106832
|
throw Object.assign(new SpendRefusalError({
|
|
106776
106833
|
ok: false,
|
|
106777
106834
|
error: HELD_BY_PRIVATE_SEND,
|
|
106778
|
-
detail: `${heldByPrivateSendText(hold.sends)} Nothing was paid.`,
|
|
106779
|
-
next: "Tell the user why nothing was paid and what they can do.
|
|
106835
|
+
detail: `${heldByPrivateSendText(hold.sends, hold.freeAtomic)} Nothing was paid.`,
|
|
106836
|
+
next: "Tell the user why nothing was paid and what they can do. One payment cannot use this much now beside what the private send keeps for its unsent parts. The send keeps nothing after its last part goes, and an earlier part may free some money: pay again with the same request_id when wallet_balance largestPaymentAtomic covers this payment, after a stop of the send, or after new money is private",
|
|
106780
106837
|
privateSends: hold.sends
|
|
106781
106838
|
}), { privateSends: hold.sends });
|
|
106782
106839
|
}
|
|
@@ -108801,12 +108858,14 @@ function heldBySendLine(error) {
|
|
|
108801
108858
|
for (let link2 = error, depth = 0; link2 instanceof Error && depth < 8; link2 = link2.cause, depth += 1) {
|
|
108802
108859
|
if (!String(link2.message).startsWith(HELD_BY_PRIVATE_SEND)) continue;
|
|
108803
108860
|
const sends = Array.isArray(link2.privateSends) ? link2.privateSends.filter((one) => typeof one?.requestId === "string" && typeof one.sendId === "string") : [];
|
|
108861
|
+
const frees = "It keeps nothing after its last part goes; an earlier part may free some money (shinjuku balance shows it).";
|
|
108804
108862
|
if (sends.length === 0) {
|
|
108805
|
-
return
|
|
108863
|
+
return `Nothing was sent. One payment cannot use this much now. A private send in progress keeps part of this money for its unsent parts. ${frees} To send now, stop that send (shinjuku unshield-cancel --unshield-id <its id>; a token transfer: shinjuku transfer-token --id <its id> --cancel), or add money with shinjuku add-funds.`;
|
|
108806
108864
|
}
|
|
108807
108865
|
const many = sends.length > 1;
|
|
108808
|
-
const stops = sends.map((one) => one.tool === "wallet_transfer_token" ? `shinjuku transfer-token --id ${one.requestId} --cancel` : `shinjuku unshield-cancel --unshield-id ${one.sendId}`);
|
|
108809
|
-
|
|
108866
|
+
const stops = sends.map((one) => `${one.tool === "wallet_transfer_token" ? `shinjuku transfer-token --id ${one.requestId} --cancel` : `shinjuku unshield-cancel --unshield-id ${one.sendId}`} (${sendWords(one)})`);
|
|
108867
|
+
const named = sends.map(sendWords).join(" and ");
|
|
108868
|
+
return `Nothing was sent. One payment cannot use this much now. ${named[0].toUpperCase()}${named.slice(1)} ${many ? "keep" : "keeps"} part of this money for ${many ? "their" : "its"} unsent parts. ${many ? frees.replace(/^It keeps/, "Each keeps") : frees} To send now, stop the send with ${stops.join(", or ")}, or add money with shinjuku add-funds.`;
|
|
108810
108869
|
}
|
|
108811
108870
|
return void 0;
|
|
108812
108871
|
}
|
|
@@ -119528,6 +119587,7 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
119528
119587
|
if (/_retry_same_request$/.test(code2)) {
|
|
119529
119588
|
return a.paid === true ? `Paid, but the seller has not answered yet. ${again}` : `The result is not known yet. ${again}`;
|
|
119530
119589
|
}
|
|
119590
|
+
if (code2 === "p03_float_fee_account_low") return "Nothing was paid. The payment service's network fee account is low; its operator was alerted. Try again later.";
|
|
119531
119591
|
if (BUSY.test(code2)) {
|
|
119532
119592
|
const said = /in about ([0-9]{1,4}) s\b/.exec(next);
|
|
119533
119593
|
const seconds2 = Number.isFinite(a.readyInSeconds) && a.readyInSeconds > 0 ? Math.ceil(a.readyInSeconds) : said ? Number(said[1]) : 30;
|
|
@@ -119987,6 +120047,7 @@ function previewReason(a, npmVersion) {
|
|
|
119987
120047
|
return raiseLine("--max-session", npmVersion, `over your 24-hour limit of ${usdcText2(a.capAtomic)} USDC.`, SAY_MAX_WORDS - 3);
|
|
119988
120048
|
}
|
|
119989
120049
|
if (OWNER_LIMIT_CODES.has(code2)) return "it is above a spending limit set for this wallet.";
|
|
120050
|
+
if (code2 === "p03_float_fee_account_low") return "the payment service's network fee account is low; try again later.";
|
|
119990
120051
|
if (BUSY.test(code2)) return "the payment service is busy; try again in a minute.";
|
|
119991
120052
|
if (code2 === "mcp_wallet_unreadable" || code2 === "p03_float_config_unreadable") return "the price could not be checked just now; try again in a minute.";
|
|
119992
120053
|
const sentence2 = plainSentence(a.detail, SAY_MAX_WORDS - 4);
|
|
@@ -120208,11 +120269,20 @@ function sayFor(answer, { tool, npmVersion } = {}) {
|
|
|
120208
120269
|
const parts = line.trim().split(/\s+/);
|
|
120209
120270
|
return parts.length <= SAY_MAX_WORDS ? line : `${parts.slice(0, SAY_MAX_WORDS).join(" ").replace(/[.;:,]+$/, "")}.`;
|
|
120210
120271
|
}
|
|
120211
|
-
function
|
|
120212
|
-
if (!output2 || typeof output2 !== "object" || output2.isError) return output2;
|
|
120272
|
+
function firstText(output2) {
|
|
120213
120273
|
const blocks = Array.isArray(output2.content) && output2.content.length ? output2.content : void 0;
|
|
120214
120274
|
const first = blocks?.[0];
|
|
120215
120275
|
const text3 = blocks ? first?.type === "text" && typeof first.text === "string" ? first.text : void 0 : typeof output2.text === "string" ? output2.text : void 0;
|
|
120276
|
+
return { blocks, first, text: text3 };
|
|
120277
|
+
}
|
|
120278
|
+
function withFirstText(output2, { blocks, first, text: text3 }, value2) {
|
|
120279
|
+
const out = JSON.stringify(value2, null, /^\s*\{\s*\n/.test(text3) ? 2 : void 0);
|
|
120280
|
+
return { ...output2, text: out, ...blocks ? { content: [{ ...first, text: out }, ...blocks.slice(1)] } : {} };
|
|
120281
|
+
}
|
|
120282
|
+
function addSay(output2, toolName, { news, usdcFields: fields = usdcFields, npmVersion } = {}) {
|
|
120283
|
+
if (!output2 || typeof output2 !== "object" || output2.isError) return output2;
|
|
120284
|
+
const block = firstText(output2);
|
|
120285
|
+
const { text: text3 } = block;
|
|
120216
120286
|
if (text3 === void 0 || SAY_FIRST.test(text3.slice(0, 64)) || !/^\s*\{/.test(text3)) return output2;
|
|
120217
120287
|
let parsed2;
|
|
120218
120288
|
try {
|
|
@@ -120243,8 +120313,22 @@ function addSay(output2, toolName, { news, usdcFields: fields = usdcFields, npmV
|
|
|
120243
120313
|
if (!Array.isArray(items)) items = [];
|
|
120244
120314
|
}
|
|
120245
120315
|
const value2 = { say: say3, ...plainFields(parsed2, toolName), ...usdc6 ? { usdc: usdc6 } : {}, ...items.length ? { news: items } : {} };
|
|
120246
|
-
|
|
120247
|
-
|
|
120316
|
+
return withFirstText(output2, block, value2);
|
|
120317
|
+
}
|
|
120318
|
+
function withKeepIdNote(output2) {
|
|
120319
|
+
if (!output2 || typeof output2 !== "object" || output2.isError) return output2;
|
|
120320
|
+
const block = firstText(output2);
|
|
120321
|
+
if (block.text === void 0 || !/^\s*\{/.test(block.text)) return output2;
|
|
120322
|
+
let parsed2;
|
|
120323
|
+
try {
|
|
120324
|
+
parsed2 = JSON.parse(block.text);
|
|
120325
|
+
} catch {
|
|
120326
|
+
return output2;
|
|
120327
|
+
}
|
|
120328
|
+
if (!parsed2 || typeof parsed2 !== "object" || Array.isArray(parsed2) || typeof parsed2.next !== "string" || parsed2.next.includes(KEEP_ID_NOTE)) return output2;
|
|
120329
|
+
const ids = [parsed2.requestId, parsed2.newRequestId, ...Array.isArray(parsed2.privateSends) ? parsed2.privateSends.map((send3) => send3?.requestId) : []].filter((id) => typeof id === "string" && id.length >= 4);
|
|
120330
|
+
if (!ids.some((id) => parsed2.next.includes(id)) && !/request_id "[^"]+"/.test(parsed2.next)) return output2;
|
|
120331
|
+
return withFirstText(output2, block, { ...parsed2, next: `${parsed2.next.replace(/[.\s]+$/, "")}. ${KEEP_ID_NOTE}` });
|
|
120248
120332
|
}
|
|
120249
120333
|
function plainFields(parsed2, toolName) {
|
|
120250
120334
|
const a = { ...parsed2 };
|
|
@@ -120269,9 +120353,9 @@ function plainFields(parsed2, toolName) {
|
|
|
120269
120353
|
return a;
|
|
120270
120354
|
}
|
|
120271
120355
|
function withSay(tool, options = {}) {
|
|
120272
|
-
return { ...tool, run: async (args, ctx) => addSay(await tool.run(args, ctx), tool.name, options) };
|
|
120356
|
+
return { ...tool, run: async (args, ctx) => withKeepIdNote(addSay(await tool.run(args, ctx), tool.name, options)) };
|
|
120273
120357
|
}
|
|
120274
|
-
var SAY_MAX_WORDS, DECIMALS2, ATOMIC4, SAY_FIRST, SAY_BANNED, CODE_TOKEN, LONG_NUMBER, MOVE_LINE, minutesText, ageWords, MOVING_ROLES, CLOSE_LATER, PAY_CAP_CODES, raiseLine, MOVE_CAP_CODES, OWNER_LIMIT_CODES, INSUFFICIENT, BUSY, SHIELD_TOOLS, words, positive, str, OWN_WORK_WORDS, DISCOVER_LIST_NAMES, TRANSFER_TOOLS, CONFIRMED_SEND_TOOLS;
|
|
120358
|
+
var SAY_MAX_WORDS, DECIMALS2, ATOMIC4, SAY_FIRST, SAY_BANNED, CODE_TOKEN, LONG_NUMBER, MOVE_LINE, minutesText, ageWords, MOVING_ROLES, CLOSE_LATER, PAY_CAP_CODES, raiseLine, MOVE_CAP_CODES, OWNER_LIMIT_CODES, INSUFFICIENT, BUSY, SHIELD_TOOLS, words, positive, str, OWN_WORK_WORDS, DISCOVER_LIST_NAMES, TRANSFER_TOOLS, CONFIRMED_SEND_TOOLS, KEEP_ID_NOTE;
|
|
120275
120359
|
var init_say = __esm({
|
|
120276
120360
|
"wallet/src/mcp/say.mjs"() {
|
|
120277
120361
|
"use strict";
|
|
@@ -120343,6 +120427,7 @@ var init_say = __esm({
|
|
|
120343
120427
|
});
|
|
120344
120428
|
TRANSFER_TOOLS = /* @__PURE__ */ new Set(["wallet_transfer_token", "wallet_transfer_token_status"]);
|
|
120345
120429
|
CONFIRMED_SEND_TOOLS = /* @__PURE__ */ new Set(["wallet_unshield", "wallet_transfer_token", "wallet_transfer_token_status"]);
|
|
120430
|
+
KEEP_ID_NOTE = "Keep request_id values for your own calls; never show one to the user.";
|
|
120346
120431
|
}
|
|
120347
120432
|
});
|
|
120348
120433
|
|
|
@@ -122546,6 +122631,9 @@ function paidAnswerContent({
|
|
|
122546
122631
|
}
|
|
122547
122632
|
if (text3.length > maxTextChars) {
|
|
122548
122633
|
const saved2 = save(data, OTHER_EXT[declared] ?? "txt", saveDir, now, sha25610);
|
|
122634
|
+
if (typeof meta.say === "string") {
|
|
122635
|
+
meta.say = `${meta.say} The answer is long: these are its first ${maxTextChars.toLocaleString("en-US")} of ${text3.length.toLocaleString("en-US")} characters${saved2.savedPath ? `; the whole answer is in ${saved2.savedPath}` : ""}.`;
|
|
122636
|
+
}
|
|
122549
122637
|
Object.assign(meta, {
|
|
122550
122638
|
body: text3.slice(0, maxTextChars),
|
|
122551
122639
|
bodyTruncated: true,
|
|
@@ -122578,7 +122666,7 @@ var init_answer = __esm({
|
|
|
122578
122666
|
"use strict";
|
|
122579
122667
|
init_fs();
|
|
122580
122668
|
DEFAULT_MAX_INLINE_BYTES = 4e6;
|
|
122581
|
-
DEFAULT_MAX_TEXT_CHARS =
|
|
122669
|
+
DEFAULT_MAX_TEXT_CHARS = 2e4;
|
|
122582
122670
|
MAX_IMAGE_URLS = 20;
|
|
122583
122671
|
MAX_JSON_DEPTH = 8;
|
|
122584
122672
|
RASTER = Object.freeze({
|
|
@@ -125407,7 +125495,13 @@ function refusedReason(record) {
|
|
|
125407
125495
|
function heldSendsOf(error) {
|
|
125408
125496
|
for (let link2 = error, depth = 0; link2 && typeof link2 === "object" && depth < 8; link2 = link2.cause, depth += 1) {
|
|
125409
125497
|
if (!Array.isArray(link2.privateSends)) continue;
|
|
125410
|
-
return link2.privateSends.filter((send3) => typeof send3?.requestId === "string" && REQUEST_ID4.test(send3.requestId) && ["wallet_unshield", "wallet_transfer_token", "cli"].includes(send3.tool) && (send3.tool !== "cli" || REQUEST_ID4.test(String(send3.sendId ?? "")))).map((send3) => ({
|
|
125498
|
+
return link2.privateSends.filter((send3) => typeof send3?.requestId === "string" && REQUEST_ID4.test(send3.requestId) && ["wallet_unshield", "wallet_transfer_token", "cli"].includes(send3.tool) && (send3.tool !== "cli" || REQUEST_ID4.test(String(send3.sendId ?? "")))).map((send3) => ({
|
|
125499
|
+
requestId: send3.requestId,
|
|
125500
|
+
tool: send3.tool,
|
|
125501
|
+
...send3.tool === "cli" ? { sendId: send3.sendId } : {},
|
|
125502
|
+
...typeof send3.to === "string" && send3.to.length > 10 ? { to: send3.to } : {},
|
|
125503
|
+
.../^[1-9][0-9]*$/.test(String(send3.amountAtomic ?? "")) ? { amountAtomic: String(send3.amountAtomic) } : {}
|
|
125504
|
+
}));
|
|
125411
125505
|
}
|
|
125412
125506
|
return [];
|
|
125413
125507
|
}
|
|
@@ -125863,9 +125957,12 @@ async function runUnshield({
|
|
|
125863
125957
|
if (exit.settled === false && !await finishAnsweredExit({ session, store, name, exit, answer, onAnswered, onCheckPending, mark, scoped })) return answer;
|
|
125864
125958
|
mark("unshield-exited");
|
|
125865
125959
|
const exited = store.readWal(`self-pay-${unshieldId}`);
|
|
125866
|
-
store.writeWal(`self-pay-${unshieldId}`, { ...exited, state: "exited", exitTransaction: exit.signature, exitedAtMs: exited?.exitedAtMs ?? Date.now() });
|
|
125960
|
+
store.writeWal(`self-pay-${unshieldId}`, { ...exited, state: "exited", exitTransaction: exit.signature, exitedAtMs: exited?.exitedAtMs ?? exited?.exitAnsweredAtMs ?? Date.now() });
|
|
125867
125961
|
return answer;
|
|
125868
125962
|
}
|
|
125963
|
+
function sentAtMs(record) {
|
|
125964
|
+
return Number.isSafeInteger(record?.exitAnsweredAtMs) ? record.exitAnsweredAtMs : record?.exitedAtMs;
|
|
125965
|
+
}
|
|
125869
125966
|
async function finishAnsweredExit({ session, store, name, exit, answer, changeAtomic, onAnswered, onCheckPending, mark, scoped }) {
|
|
125870
125967
|
if (typeof onAnswered !== "function") {
|
|
125871
125968
|
await scoped("unshield-exit", () => exit.finish());
|
|
@@ -125970,7 +126067,7 @@ async function runDirectExit({
|
|
|
125970
126067
|
if (exit.settled === false && !await finishAnsweredExit({ session, store, name, exit, answer, changeAtomic, onAnswered, onCheckPending, mark, scoped })) return answer;
|
|
125971
126068
|
mark("unshield-exited");
|
|
125972
126069
|
const exited = store.readWal(name);
|
|
125973
|
-
store.writeWal(name, { ...exited, state: "exited", exitTransaction: exit.signature, exitedAtMs: exited?.exitedAtMs ?? Date.now() });
|
|
126070
|
+
store.writeWal(name, { ...exited, state: "exited", exitTransaction: exit.signature, exitedAtMs: exited?.exitedAtMs ?? exited?.exitAnsweredAtMs ?? Date.now() });
|
|
125974
126071
|
return answer;
|
|
125975
126072
|
}
|
|
125976
126073
|
function balanceFields(parts) {
|
|
@@ -128400,19 +128497,20 @@ ${canonical5}`;
|
|
|
128400
128497
|
})
|
|
128401
128498
|
}));
|
|
128402
128499
|
if (sendWaiting) {
|
|
128403
|
-
next = `${next}. Tell the user: the send of ${usdcText3(sendWaiting.amountAtomic)} USDC to ${sendWaiting.to.slice(0, 4)}...${sendWaiting.to.slice(-4)}
|
|
128500
|
+
next = `${next}. Tell the user: the send of ${usdcText3(sendWaiting.amountAtomic)} USDC to ${sendWaiting.to.slice(0, 4)}...${sendWaiting.to.slice(-4)} ${sendWaiting.state === "sending" ? "is being sent now" : sendWaiting.state === "retrying" ? retryWords(sendWaiting) : "waits until the wallet has the balance ready to send; each wallet request goes on with it"}; it cannot be cancelled`;
|
|
128404
128501
|
}
|
|
128405
128502
|
const goingSends = privateSends.filter((send3) => send3.failedTries === void 0);
|
|
128406
128503
|
if (goingSends.length) {
|
|
128407
|
-
next = `${next}. Tell the user: ${goingSends.map((send3) =>
|
|
128504
|
+
next = `${next}. Tell the user: ${goingSends.map((send3) => `${sendWords(send3)} sent ${usdcText3(send3.sentAtomic)} USDC so far; payment ${send3.nextPayment} of ${send3.payments} ${send3.nextPaymentInMinutes > 0 ? `goes in about ${minutesText2(send3.nextPaymentInMinutes)} (random times, for privacy)` : "is past its planned time and not sent yet; the wallet tries it again by itself"}`).join("; ")}. ${SEND_RUNS_ON} The user needs to do nothing for it. To stop the unsent payments if the user asks: ${goingSends.map((send3) => `${cancelCall(send3)} (${sendWords(send3)})`).join("; ")}`;
|
|
128408
128505
|
}
|
|
128409
128506
|
const failingSends = privateSends.filter((send3) => send3.failedTries > 0);
|
|
128410
128507
|
if (failingSends.length) {
|
|
128411
|
-
next = `${next}. Tell the user: ${failingSends.map((send3) => `payment ${send3.nextPayment} of ${send3.payments} of
|
|
128508
|
+
next = `${next}. Tell the user: ${failingSends.map((send3) => `payment ${send3.nextPayment} of ${send3.payments} of ${sendWords(send3)} did not go through in ${send3.failedTries} ${send3.failedTries === 1 ? "try" : "tries"}${send3.lastTryMinutesAgo !== void 0 ? ` (the last ${send3.lastTryMinutesAgo > 0 ? `${ageWords2(send3.lastTryMinutesAgo)} ago` : "under a minute ago"})` : ""}: ${send3.lastReason}. It sent ${usdcText3(send3.sentAtomic)} USDC so far. The wallet tries that payment again by itself at its next start`).join(". ")}. ` + failingSends.map((send3) => `To try it now: ${send3.tool === "wallet_transfer_token" ? `wallet_transfer_token_status with request_id "${send3.requestId}"` : `wallet_unshield with request_id "${send3.requestId}" and the same arguments`}; to stop the send and return the USDC not sent yet to the private balance: ${cancelCall(send3)} (${sendWords(send3)})`).join(". ");
|
|
128412
128509
|
}
|
|
128413
128510
|
if (privateSends.length && one.largestPaymentAtomic === "0" && (one.changeSettling !== true || one.changeUpToAtomic !== void 0) && /^[1-9][0-9]*$/.test(String(one.balanceAtomic ?? ""))) {
|
|
128414
128511
|
const soon = one.changeUpToAtomic === void 0 ? "" : `after the last payment settles${Number.isSafeInteger(one.changeReadyInSeconds) ? ` (about ${one.changeReadyInSeconds} s)` : ""}, one payment can use up to ${usdcText3(one.changeUpToAtomic)} USDC; the rest waits, `;
|
|
128415
|
-
|
|
128512
|
+
const many = privateSends.length > 1;
|
|
128513
|
+
next = `${next}. Tell the user: ${soon || `no payment can use the ${usdcText3(one.balanceAtomic)} USDC yet, `}because ${privateSends.map(sendWords).join(" and ")} ${many ? "keep" : "keeps"} money aside for ${many ? "their" : "its"} unsent payments. A send keeps nothing after its last payment goes, and an earlier payment may free some (wallet_balance shows it). To pay now if the user asks: ${privateSends.map((send3) => `${cancelCall(send3)} (${sendWords(send3)})`).join(" or ")} stops the send and frees its money now`;
|
|
128416
128514
|
}
|
|
128417
128515
|
const balanceParts = parts?.parts > 1 && ATOMIC_TEXT.test(String(one.balanceAtomic ?? "")) ? parts.parts : void 0;
|
|
128418
128516
|
if (balanceParts && !sendWaiting) {
|
|
@@ -128852,7 +128950,7 @@ ${canonical5}`;
|
|
|
128852
128950
|
live = "unreadable";
|
|
128853
128951
|
}
|
|
128854
128952
|
const started = Number.isSafeInteger(record.createdAtMs) ? record.createdAtMs : Number.isSafeInteger(joining?.createdAtMs) ? joining.createdAtMs : void 0;
|
|
128855
|
-
const at = Number.isSafeInteger(record
|
|
128953
|
+
const at = Number.isSafeInteger(sentAtMs(record)) ? sentAtMs(record) : record.state === "exited" ? walTimeMs(store, name) : started ?? walTimeMs(store, name);
|
|
128856
128954
|
const shown = shownId(record.mcpRequestId, idAfter(name, "self-pay-mcp-"));
|
|
128857
128955
|
if (live !== "joining") joining = void 0;
|
|
128858
128956
|
const retry = joining ? retryFields(joining) : void 0;
|
|
@@ -130371,7 +130469,7 @@ ${canonical5}`;
|
|
|
130371
130469
|
if (!record) continue;
|
|
130372
130470
|
const finished = kind !== "unshield" ? ["published", "foreign_funded", "reclaimed"].includes(record.state) : record.schema === PRIVATE_SEND_WAL_SCHEMA ? record.state === "done" || record.state === "cancelled" && privateSendStatus(store, record).done : ["exited", "released", "abandoned"].includes(record.state);
|
|
130373
130471
|
if (!finished) return void 0;
|
|
130374
|
-
const at = Date.parse(String(record.doneAt ?? "")) || record
|
|
130472
|
+
const at = Date.parse(String(record.doneAt ?? "")) || sentAtMs(record);
|
|
130375
130473
|
if (Number.isSafeInteger(at)) return at;
|
|
130376
130474
|
try {
|
|
130377
130475
|
return Math.floor(statSync(join32(store.walDirectory, `${name}.json`)).mtimeMs);
|
|
@@ -130558,7 +130656,7 @@ ${canonical5}`;
|
|
|
130558
130656
|
const finished = kind === "unshield" ? split4 ? record.state === "done" || record.state === "cancelled" && privateSendStatus(store, record).done : record.state === "exited" : ["published", "foreign_funded"].includes(record.state);
|
|
130559
130657
|
if (finished) {
|
|
130560
130658
|
const send3 = split4 ? privateSendStatus(store, record) : void 0;
|
|
130561
|
-
const endedAtMs = Date.parse(String(record.doneAt ?? record.cancelledAt ?? "")) || record
|
|
130659
|
+
const endedAtMs = Date.parse(String(record.doneAt ?? record.cancelledAt ?? "")) || sentAtMs(record);
|
|
130562
130660
|
const earlier = kind !== "elsewhere" ? { replayed: true, newRequestId: freshId, ...Number.isSafeInteger(endedAtMs) ? { finishedMinutesAgo: Math.max(0, Math.round((Date.now() - endedAtMs) / 6e4)) } : {} } : {};
|
|
130563
130661
|
const earlierWords = earlier.finishedMinutesAgo !== void 0 ? ` about ${minutesText2(earlier.finishedMinutesAgo)} ago` : " earlier";
|
|
130564
130662
|
return json3({
|
|
@@ -134753,7 +134851,7 @@ var init_tools = __esm({
|
|
|
134753
134851
|
shownId = (agentId, rid) => typeof agentId === "string" && REQUEST_ID4.test(agentId) && toRecordId(agentId) === rid ? agentId : rid;
|
|
134754
134852
|
isSplitSend = (request) => Boolean(request) && !isSingleSend(request.parts ?? 1, request.maxDelayMinutes ?? 0);
|
|
134755
134853
|
sendPartId = (requestId) => (index) => `mp${index}-${toRecordId(requestId)}`;
|
|
134756
|
-
PROMISED_NEXT = "Nothing was sent. Some of the private balance is promised to the unsent payments of a private send (wallet_balance privateSends names it, and its next names the call that stops it).
|
|
134854
|
+
PROMISED_NEXT = "Nothing was sent. Some of the private balance is promised to the unsent payments of a private send (wallet_balance privateSends names it, and its next names the call that stops it). A wait frees nothing, because that money leaves the wallet as its parts go: to send this amount, stop its unsent payments with that call, then call wallet_unshield again with the same arguments; or send at most freeAtomic now with a NEW request_id";
|
|
134757
134855
|
partFailReason = (code2) => INSUFFICIENT_CODE.test(String(code2 ?? "")) ? "the wallet could not pay that amount in one payment from the private balance as it is" : reasonOf(code2) ?? "the payment did not finish";
|
|
134758
134856
|
sendAnswerOf = (status) => {
|
|
134759
134857
|
const { nextPartLastTryAt: _clock, ...shown } = status;
|