shinjuku-shield 0.3.90 → 0.3.91
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 +278 -112
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ 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.91. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files; `shinjuku` is the short command.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
15
|
+
npx -y --no-audit --no-fund shinjuku-shield@0.3.91 setup
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
@@ -24,7 +24,7 @@ server to that host's config.
|
|
|
24
24
|
## The `shinjuku` command
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npm install -g shinjuku@0.3.
|
|
27
|
+
npm install -g shinjuku@0.3.91
|
|
28
28
|
shinjuku help
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -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-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
39
|
+
claude mcp add --scope user shinjuku-shielded -- npx -y --no-audit --no-fund shinjuku-shield@0.3.91 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-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.
|
|
45
|
+
{ "mcpServers": { "shinjuku-shielded": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.91", "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": "1d7842469a3a56390eae2b339649cb42551a19ef63c2f9b1d5716f875ce11b52",
|
|
5
|
+
"bytes": 12694423,
|
|
6
|
+
"sourceCommit": "49f574ac0d496bfe5fda2fff09ed900810a54eed",
|
|
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",
|
|
@@ -1297,5 +1297,5 @@
|
|
|
1297
1297
|
"version": "1.8.0"
|
|
1298
1298
|
}
|
|
1299
1299
|
],
|
|
1300
|
-
"publishedAt": "2026-10-
|
|
1300
|
+
"publishedAt": "2026-10-24T01:44:56.272Z"
|
|
1301
1301
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shield",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.91",
|
|
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": "1d784246",
|
|
7
|
+
"shinjukuSha256": "1d7842469a3a56390eae2b339649cb42551a19ef63c2f9b1d5716f875ce11b52",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -30309,7 +30309,7 @@ Message: ${transactionMessage2}.
|
|
|
30309
30309
|
await this._unsubscribeClientSubscription(clientSubscriptionId, "root change");
|
|
30310
30310
|
}
|
|
30311
30311
|
};
|
|
30312
|
-
var
|
|
30312
|
+
var Keypair17 = class _Keypair {
|
|
30313
30313
|
/**
|
|
30314
30314
|
* Create a new keypair instance.
|
|
30315
30315
|
* Generate random keypair if no {@link Ed25519Keypair} is provided.
|
|
@@ -30853,7 +30853,7 @@ Message: ${transactionMessage2}.
|
|
|
30853
30853
|
} = params;
|
|
30854
30854
|
assert(privateKey.length === PRIVATE_KEY_BYTES$1, `Private key must be ${PRIVATE_KEY_BYTES$1} bytes but received ${privateKey.length} bytes`);
|
|
30855
30855
|
try {
|
|
30856
|
-
const keypair =
|
|
30856
|
+
const keypair = Keypair17.fromSecretKey(privateKey);
|
|
30857
30857
|
const publicKey4 = keypair.publicKey.toBytes();
|
|
30858
30858
|
const signature3 = sign3(message, keypair.secretKey);
|
|
30859
30859
|
return this.createInstructionWithPublicKey({
|
|
@@ -32293,7 +32293,7 @@ Message: ${transactionMessage2}.
|
|
|
32293
32293
|
exports.Enum = Enum;
|
|
32294
32294
|
exports.EpochSchedule = EpochSchedule;
|
|
32295
32295
|
exports.FeeCalculatorLayout = FeeCalculatorLayout;
|
|
32296
|
-
exports.Keypair =
|
|
32296
|
+
exports.Keypair = Keypair17;
|
|
32297
32297
|
exports.LAMPORTS_PER_SOL = LAMPORTS_PER_SOL;
|
|
32298
32298
|
exports.LOOKUP_TABLE_INSTRUCTION_LAYOUTS = LOOKUP_TABLE_INSTRUCTION_LAYOUTS;
|
|
32299
32299
|
exports.Loader = Loader;
|
|
@@ -104690,6 +104690,9 @@ function checkConfig(value) {
|
|
|
104690
104690
|
}
|
|
104691
104691
|
if (BigInt(caps.maxSession) < BigInt(caps.maxPayment)) throw invalid3("caps.maxSession is below caps.maxPayment");
|
|
104692
104692
|
if (value.tor !== void 0 && typeof value.tor !== "boolean") throw invalid3("tor is not true or false");
|
|
104693
|
+
if (value.unshieldTo !== void 0 && (!Array.isArray(value.unshieldTo) || value.unshieldTo.length < 1 || value.unshieldTo.length > MAX_OWN_ADDRESSES || !value.unshieldTo.every(isPubkey))) {
|
|
104694
|
+
throw invalid3(`unshieldTo is not a list of 1 to ${MAX_OWN_ADDRESSES} base58 Solana addresses`);
|
|
104695
|
+
}
|
|
104693
104696
|
if (value.torTunnel !== void 0) {
|
|
104694
104697
|
let tunnel;
|
|
104695
104698
|
try {
|
|
@@ -104714,9 +104717,17 @@ function checkConfig(value) {
|
|
|
104714
104717
|
return Object.freeze({
|
|
104715
104718
|
...value,
|
|
104716
104719
|
caps: Object.freeze({ ...caps }),
|
|
104720
|
+
...value.unshieldTo ? { unshieldTo: Object.freeze([...value.unshieldTo]) } : {},
|
|
104717
104721
|
...value.previousPools ? { previousPools: Object.freeze(value.previousPools.map((entry) => Object.freeze({ ...entry }))) } : {}
|
|
104718
104722
|
});
|
|
104719
104723
|
}
|
|
104724
|
+
function ownAddressesNow(home) {
|
|
104725
|
+
try {
|
|
104726
|
+
return [...readSetupConfig(home)?.unshieldTo ?? []];
|
|
104727
|
+
} catch {
|
|
104728
|
+
return [];
|
|
104729
|
+
}
|
|
104730
|
+
}
|
|
104720
104731
|
function readSetupConfig(home) {
|
|
104721
104732
|
const path = configPath(home);
|
|
104722
104733
|
if (!existsSync(path)) return null;
|
|
@@ -104760,7 +104771,8 @@ function mcpFlagsFromConfig(home, config) {
|
|
|
104760
104771
|
["--max-payment", config.caps.maxPayment],
|
|
104761
104772
|
["--max-session", config.caps.maxSession],
|
|
104762
104773
|
["--max-shield", config.caps.maxShield],
|
|
104763
|
-
["--max-unshield", config.caps.maxUnshield]
|
|
104774
|
+
["--max-unshield", config.caps.maxUnshield],
|
|
104775
|
+
["--unshield-to", config.unshieldTo ? [...config.unshieldTo] : void 0]
|
|
104764
104776
|
].filter(([, value]) => value !== void 0);
|
|
104765
104777
|
}
|
|
104766
104778
|
function npxPackageWord(npmVersion) {
|
|
@@ -104931,7 +104943,7 @@ function addToJsonHost(file, entry, { now = /* @__PURE__ */ new Date(), force =
|
|
|
104931
104943
|
}
|
|
104932
104944
|
return { file, changed: true, ...backup ? { backup } : {} };
|
|
104933
104945
|
}
|
|
104934
|
-
var import_web3118, CONFIG_SCHEMA, CONFIG_FILE, NPM_PACKAGE_NAMES, NPX_PACKAGE, COMMAND_PACKAGE, NPX_INSTALL_FLAGS, MCP_SERVER_NAME, P03_BINDING2, PRODUCTION, RETIRED_POOLS, NO_LIMIT_ATOMIC2, DEFAULT_CAPS, OLD_DEFAULT_SETUP_CAPS, OLD_DEFAULT_WALLET_BUDGETS, capText, POSITIVE_ATOMIC2, configPath, homeWalletPath, invalid3, isPubkey, HOST_TARGETS, PINNED_PACKAGE, NPM_VERSION, knownNpmVersion, WINDOWS_SHELL_CODE, isPlainObject3, sameJson2;
|
|
104946
|
+
var import_web3118, CONFIG_SCHEMA, CONFIG_FILE, NPM_PACKAGE_NAMES, NPX_PACKAGE, COMMAND_PACKAGE, NPX_INSTALL_FLAGS, MCP_SERVER_NAME, P03_BINDING2, PRODUCTION, RETIRED_POOLS, NO_LIMIT_ATOMIC2, DEFAULT_CAPS, OLD_DEFAULT_SETUP_CAPS, OLD_DEFAULT_WALLET_BUDGETS, capText, POSITIVE_ATOMIC2, configPath, homeWalletPath, invalid3, isPubkey, MAX_OWN_ADDRESSES, isOwnAddressText, HOST_TARGETS, PINNED_PACKAGE, NPM_VERSION, knownNpmVersion, WINDOWS_SHELL_CODE, isPlainObject3, sameJson2;
|
|
104935
104947
|
var init_config2 = __esm({
|
|
104936
104948
|
"wallet/src/setup/config.mjs"() {
|
|
104937
104949
|
"use strict";
|
|
@@ -104981,6 +104993,8 @@ var init_config2 = __esm({
|
|
|
104981
104993
|
return false;
|
|
104982
104994
|
}
|
|
104983
104995
|
};
|
|
104996
|
+
MAX_OWN_ADDRESSES = 8;
|
|
104997
|
+
isOwnAddressText = (value) => isPubkey(value);
|
|
104984
104998
|
HOST_TARGETS = Object.freeze(["claude-code", "claude-desktop", "cursor"]);
|
|
104985
104999
|
PINNED_PACKAGE = /^shinjuku-shield(?:ed)?@(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
104986
105000
|
NPM_VERSION = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
|
|
@@ -110043,9 +110057,12 @@ function refusalSay(a, tool, again, npmVersion) {
|
|
|
110043
110057
|
return /\bover Tor\b/.test(detail) ? "Nothing was paid. The seller gave no answer over Tor; some block Tor exits. Try later, or ask the user whether to pay without --tor." : "Nothing was paid. The seller did not answer.";
|
|
110044
110058
|
}
|
|
110045
110059
|
const unshown = /without showing it|could not show the confirmation/.test(detail);
|
|
110046
|
-
if (code2 === "mcp_unshield_declined") {
|
|
110047
|
-
|
|
110060
|
+
if (code2 === "mcp_unshield_declined" && unshown || code2 === "mcp_unshield_to_not_allowed") {
|
|
110061
|
+
const head = "Not sent: this app could not show you the address to confirm.";
|
|
110062
|
+
const own = `${head} If it is your wallet, run the setup command below in a terminal.`;
|
|
110063
|
+
return str(a.ownAddressCommand) && words(own) <= SAY_MAX_WORDS ? own : head;
|
|
110048
110064
|
}
|
|
110065
|
+
if (code2 === "mcp_unshield_declined") return "Not sent. The send was not confirmed.";
|
|
110049
110066
|
if (code2 === "mcp_setup_declined" && unshown) {
|
|
110050
110067
|
return `Not set up. This app cannot show the setup question. Run ${oneTimeCommandLine("setup", npmVersion)} in a terminal, then restart this app.`;
|
|
110051
110068
|
}
|
|
@@ -110248,15 +110265,16 @@ function balanceLine(a, room = SAY_MAX_WORDS) {
|
|
|
110248
110265
|
if (a.status === "reading") return "The first balance read of this wallet is not done yet. Ask again in 30 seconds.";
|
|
110249
110266
|
if (a.refreshing === true) {
|
|
110250
110267
|
const last = a.lastRead && usdcText(a.lastRead.privateAtomic) && Number.isSafeInteger(a.lastRead.ageMinutes) && a.lastRead.ageMinutes > 0 ? ` The last full read, ${ageWords(a.lastRead.ageMinutes)} ago, showed ${usdcText(a.lastRead.privateAtomic)} USDC private.` : "";
|
|
110251
|
-
const
|
|
110252
|
-
|
|
110268
|
+
const known = a.lastRead && usdcText(a.lastRead.privateAtomic) && Number.isSafeInteger(a.lastRead.ageMinutes) ? `Your last known balance is ${usdcText(a.lastRead.privateAtomic)} USDC private (${a.lastRead.ageMinutes > 0 ? `${ageWords(a.lastRead.ageMinutes)} ago` : "under a minute ago"}); the wallet is checking it now.` : "";
|
|
110269
|
+
const lines = Number(a.refreshingSeconds) >= 60 ? [known && `${known} Ask again in a minute.`, last && `Still reading the chain; it takes longer than usual.${last} Ask again in a minute.`, "The wallet is still reading the chain; this takes longer than usual. Ask again in a minute."] : [known && `${known} Ask again in about 30 seconds.`, last && `Still reading the chain.${last} Ask again in about 30 seconds.`, "The wallet is still reading the chain. Ask again in about 30 seconds."];
|
|
110270
|
+
return lines.find((text3) => text3 && words(text3) <= SAY_MAX_WORDS) ?? lines.at(-1);
|
|
110253
110271
|
}
|
|
110254
110272
|
const why = refreshErrorWords(str(a.refreshError), a.lockedBy);
|
|
110255
110273
|
return why ? `Your private balance is not known yet: ${why}. Ask again in a minute.` : "Your private balance is not known yet. Ask again in a minute.";
|
|
110256
110274
|
}
|
|
110257
110275
|
const refund = usdcText(a.breakdown?.refundsInFlightAtomic);
|
|
110258
110276
|
const have = (rest, shorter = rest) => {
|
|
110259
|
-
const named = positive(refund) ? [`(${refund} of it is a refund on its way)`, `(${refund} refund on its way)`, `(${refund} refunding)`]
|
|
110277
|
+
const named = !positive(refund) ? [] : a.refreshReason === "refund_check" ? [`(${refund} of it is a refund; the wallet is checking that it arrived)`, `(${refund} of it is a refund being checked)`, `(${refund} refund being checked)`] : [`(${refund} of it is a refund on its way)`, `(${refund} refund on its way)`, `(${refund} refunding)`];
|
|
110260
110278
|
const line = [rest, shorter].flatMap((tail) => named.map((part) => `You have ${balance} USDC private ${part}${tail}`)).find((text3) => words(text3) <= SAY_MAX_WORDS);
|
|
110261
110279
|
return line ?? `You have ${balance} USDC private${rest}`;
|
|
110262
110280
|
};
|
|
@@ -125682,6 +125700,14 @@ function oneBalance(report, store, walked) {
|
|
|
125682
125700
|
}
|
|
125683
125701
|
};
|
|
125684
125702
|
}
|
|
125703
|
+
function refundFromOldWalk(store, report) {
|
|
125704
|
+
try {
|
|
125705
|
+
if ((report?.detail?.lastRefresh?.ageSeconds ?? 0) * 1e3 < INBOUND_REFRESH_AGE_MS) return false;
|
|
125706
|
+
return floatRefundsInFlightAtomic(store, readBalanceSnapshot(store).snapshot) > 0n;
|
|
125707
|
+
} catch {
|
|
125708
|
+
return false;
|
|
125709
|
+
}
|
|
125710
|
+
}
|
|
125685
125711
|
function localBalance(session) {
|
|
125686
125712
|
try {
|
|
125687
125713
|
return localBalanceOf(session.openStore());
|
|
@@ -127565,7 +127591,7 @@ ${canonical5}`;
|
|
|
127565
127591
|
const balance = {
|
|
127566
127592
|
name: "wallet_balance",
|
|
127567
127593
|
title: "Balance",
|
|
127568
|
-
description: `Use this when the user asks "what is my balance" or "how much USDC do I have": it answers ONE balance (balanceAtomic, what x402_pay can spend) and the public (unshielded) USDC. Pays nothing and signs nothing. When the user asks to see the wallet ("show my wallet"), print \`card\` as it is: at most 8 lines with the private balance, the public USDC, Tor on or off, the last 3 payments (time UTC, seller host, USDC), and example requests. balanceParts (only above 1): a send of all of it first gets the balance ready to send (next says the minutes; never say parts or join to the user). balanceAtomic is one number; breakdown names its parts (breakdown.shieldedAtomic is what wallet_unshield can send; privateSendPendingAtomic is the part of a running private send (wallet_unshield with parts or max_delay_minutes) not sent yet, already taken off shieldedAtomic; refundsInFlightAtomic is a Shinjuku refund on its way back; setAsideAtomic (only when not 0) is value an older version of this wallet set aside to pay sellers; during a pool move, pools lists each pool's part and movingAtomic is value on its way from the old pool to the new one; the move field shows the move, poolSwitches each switch). UNSHIELDED (unshieldedAtomic) is the plain public USDC on the wallet's own Solana key (ownAddress), the USDC wallet_shield makes private; unshieldedSolLamports is that key's SOL, information only: wallet_shield needs none (the facilitator's relayer pays every fee and rent). When the local balance is stale (a new deposit, a received payment), it reads the chain by itself first; when that takes longer than about 20 s it answers the last balance with refreshing: true and finishes in the background (call wallet_balance again in 30 s). A balance with refreshing: true and refreshReason is exact (payment_settling: a payment settles and the number counts it; account_join: the wallet gets its own balance ready to send and the number counts all of it; pool_move: value from the old pool arrives and the number counts it; first_check: a new wallet's first history check, the number is its own landed deposits). status reading (balanceAtomic null): the first balance read of a wallet that may hold money is not done; call wallet_balance again in 30 s. If the public read fails, unshieldedAtomic is null with unshieldedReason; the rest still answers. ownKeyTokens (only when there are any): the other tokens on ownAddress (not its USDC), each { mint, amountAtomic, decimals, amount }, at most 10 (ownKeyTokensMore counts the rest); a token is its mint, never a name or symbol; wallet_transfer_token with that mint as token_mint sells one and sends the USDC privately. earlierDeposits (only when there are any): USDC found at a one-time deposit address of an earlier pool, each with a notice line to tell the user; the wallet moves it into the current pool by itself. addFunds (only when there are any): each wallet_add_funds address still open, with its state and the USDC known to wait there (heldAtomic; null with heldNote when the address was not checked yet). startsAtNextRequest true (old name): its deposit is not sent yet; once the wallet has seen USDC there, it sends it by itself in about startsInMinutes + 1 minutes, in every host, with no ask. landingAtomic (only when not 0): USDC you added whose deposit landed on chain and that balanceAtomic does not count yet; this call finishes it and waits about 20 s for it, past that it is being counted: call wallet_balance again as next says (at once in the same turn when this call waited its 20 s, else in 30 s). session shows the spending limits (null or "none": no limit), what is left, where the limits come from, and how to change them (session.summary). verbose: true adds \`internal\` (accounts, notes, and other engineering numbers); the default answer leaves them out. To add money, use wallet_add_funds. Amounts are atomic units (USDC: 1000000 = 1 USDC); say and usdc give them in USDC.`,
|
|
127594
|
+
description: `Use this when the user asks "what is my balance" or "how much USDC do I have": it answers ONE balance (balanceAtomic, what x402_pay can spend) and the public (unshielded) USDC. Pays nothing and signs nothing. When the user asks to see the wallet ("show my wallet"), print \`card\` as it is: at most 8 lines with the private balance, the public USDC, Tor on or off, the last 3 payments (time UTC, seller host, USDC), and example requests. balanceParts (only above 1): a send of all of it first gets the balance ready to send (next says the minutes; never say parts or join to the user). balanceAtomic is one number; breakdown names its parts (breakdown.shieldedAtomic is what wallet_unshield can send; privateSendPendingAtomic is the part of a running private send (wallet_unshield with parts or max_delay_minutes) not sent yet, already taken off shieldedAtomic; refundsInFlightAtomic is a Shinjuku refund on its way back; setAsideAtomic (only when not 0) is value an older version of this wallet set aside to pay sellers; during a pool move, pools lists each pool's part and movingAtomic is value on its way from the old pool to the new one; the move field shows the move, poolSwitches each switch). UNSHIELDED (unshieldedAtomic) is the plain public USDC on the wallet's own Solana key (ownAddress), the USDC wallet_shield makes private; unshieldedSolLamports is that key's SOL, information only: wallet_shield needs none (the facilitator's relayer pays every fee and rent). When the local balance is stale (a new deposit, a received payment), it reads the chain by itself first; when that takes longer than about 20 s it answers the last balance with refreshing: true and finishes in the background (call wallet_balance again in 30 s). A balance with refreshing: true and refreshReason is exact (payment_settling: a payment settles and the number counts it; account_join: the wallet gets its own balance ready to send and the number counts all of it; pool_move: value from the old pool arrives and the number counts it; refund_check: a refund counted from an old read, which the wallet checks now (never tell the user it is still on its way); first_check: a new wallet's first history check, the number is its own landed deposits). status reading (balanceAtomic null): the first balance read of a wallet that may hold money is not done; call wallet_balance again in 30 s. If the public read fails, unshieldedAtomic is null with unshieldedReason; the rest still answers. ownKeyTokens (only when there are any): the other tokens on ownAddress (not its USDC), each { mint, amountAtomic, decimals, amount }, at most 10 (ownKeyTokensMore counts the rest); a token is its mint, never a name or symbol; wallet_transfer_token with that mint as token_mint sells one and sends the USDC privately. earlierDeposits (only when there are any): USDC found at a one-time deposit address of an earlier pool, each with a notice line to tell the user; the wallet moves it into the current pool by itself. addFunds (only when there are any): each wallet_add_funds address still open, with its state and the USDC known to wait there (heldAtomic; null with heldNote when the address was not checked yet). startsAtNextRequest true (old name): its deposit is not sent yet; once the wallet has seen USDC there, it sends it by itself in about startsInMinutes + 1 minutes, in every host, with no ask. landingAtomic (only when not 0): USDC you added whose deposit landed on chain and that balanceAtomic does not count yet; this call finishes it and waits about 20 s for it, past that it is being counted: call wallet_balance again as next says (at once in the same turn when this call waited its 20 s, else in 30 s). session shows the spending limits (null or "none": no limit), what is left, where the limits come from, and how to change them (session.summary, only when a limit is set; with none, say nothing about limits, and never tell the user the session counters (sessionSpentAtomic, sessionMovedAtomic): they are limit bookkeeping and may count earlier conversations). verbose: true adds \`internal\` (accounts, notes, and other engineering numbers); the default answer leaves them out. To add money, use wallet_add_funds. Amounts are atomic units (USDC: 1000000 = 1 USDC); say and usdc give them in USDC.`,
|
|
127569
127595
|
inputSchema: { type: "object", properties: {
|
|
127570
127596
|
verbose: { type: "boolean", description: "Optional. true adds `internal`: the engineering numbers (funded accounts, notes, payments without waiting, a 0 set-aside value). Default false." }
|
|
127571
127597
|
}, additionalProperties: false },
|
|
@@ -127640,6 +127666,17 @@ ${canonical5}`;
|
|
|
127640
127666
|
});
|
|
127641
127667
|
const cause = staleCauseOf(report);
|
|
127642
127668
|
refresh = { refreshing: true, ...cause === void 0 ? {} : { refreshReason: cause } };
|
|
127669
|
+
} else if (report.split?.shieldedAtomic != null && !recentlyFailed && !finalityWait && refundFromOldWalk(store, report)) {
|
|
127670
|
+
const outcome = await Promise.race([refreshShared().then(() => "done", () => "failed"), sleep2(balanceRefreshWaitMs).then(() => "waiting")]);
|
|
127671
|
+
if (outcome === "done") {
|
|
127672
|
+
try {
|
|
127673
|
+
store = session.openStore();
|
|
127674
|
+
} catch {
|
|
127675
|
+
}
|
|
127676
|
+
report = computeBalance({ store, snapshotRead: readBalanceSnapshot(store), source: "refresh" });
|
|
127677
|
+
walkedOne = void 0;
|
|
127678
|
+
refresh = { refreshed: true };
|
|
127679
|
+
} else refresh = { refreshing: true, refreshReason: "refund_check" };
|
|
127643
127680
|
} else if (report.split?.shieldedAtomic != null && !recentlyFailed && !finalityWait && !refreshRun && (report.detail?.lastRefresh?.ageSeconds ?? 0) * 1e3 >= INBOUND_REFRESH_AGE_MS) {
|
|
127644
127681
|
refreshShared({ background: true }).catch(() => {
|
|
127645
127682
|
});
|
|
@@ -127977,7 +128014,8 @@ ${canonical5}`;
|
|
|
127977
128014
|
const { setAsideAtomic, ...breakdownRest } = one.breakdown;
|
|
127978
128015
|
const breakdown = setAsideAtomic === "0" ? breakdownRest : one.breakdown;
|
|
127979
128016
|
if (setAsideAtomic === "0") internal.setAsideAtomic = "0";
|
|
127980
|
-
const
|
|
128017
|
+
const noLimit = (atomic4) => atomic4 === void 0 || atomic4 === null || String(atomic4) === NO_LIMIT_ATOMIC2;
|
|
128018
|
+
const capWords = (atomic4) => noLimit(atomic4) ? "no limit" : `${usdcText2(atomic4)} USDC`;
|
|
127981
128019
|
let countStore = store;
|
|
127982
128020
|
try {
|
|
127983
128021
|
countStore = session.openStore();
|
|
@@ -127988,7 +128026,7 @@ ${canonical5}`;
|
|
|
127988
128026
|
} catch {
|
|
127989
128027
|
}
|
|
127990
128028
|
const sessionLeft = sessionLeftShown(policy, countStore);
|
|
127991
|
-
const sessionSummary = `Spending limits: ${capWords(policy.limits.maxPaymentAtomic)} per payment and ${capWords(policy.limits.maxSessionAtomic)} in any 24 hours, for this wallet (every MCP process counts; a pool upgrade starts a new 24-hour count)${sessionLeft === null ? "" : ` (${usdcText2(sessionLeft)} USDC left now)`}; ${usdcText2(policy.sessionSpentAtomic) ?? "0"} USDC paid in the last 24 hours. --max-payment comes from ${capPlaceWords("--max-payment")}, and --max-session from ${capPlaceWords("--max-session")}. To change one from the host's entry, edit that flag (in USDC, like 0.05) in the host's entry for shinjuku-shielded; to change one from setup, run ${terminalCommand("setup --yes --max-payment <usdc> --max-session <usdc>")} in a terminal; then restart the host. The wallet file also holds its own limits (--max-payment, and --max-cumulative for all payments together): ${terminalCommand("limits")} shows and changes them`;
|
|
128029
|
+
const sessionSummary = noLimit(policy.limits.maxPaymentAtomic) && noLimit(policy.limits.maxSessionAtomic) ? void 0 : `Spending limits: ${capWords(policy.limits.maxPaymentAtomic)} per payment and ${capWords(policy.limits.maxSessionAtomic)} in any 24 hours, for this wallet (every MCP process counts; a pool upgrade starts a new 24-hour count)${sessionLeft === null ? "" : ` (${usdcText2(sessionLeft)} USDC left now)`}; ${usdcText2(policy.sessionSpentAtomic) ?? "0"} USDC paid in the last 24 hours. --max-payment comes from ${capPlaceWords("--max-payment")}, and --max-session from ${capPlaceWords("--max-session")}. To change one from the host's entry, edit that flag (in USDC, like 0.05) in the host's entry for shinjuku-shielded; to change one from setup, run ${terminalCommand("setup --yes --max-payment <usdc> --max-session <usdc>")} in a terminal; then restart the host. The wallet file also holds its own limits (--max-payment, and --max-cumulative for all payments together): ${terminalCommand("limits")} shows and changes them`;
|
|
127992
128030
|
return json3({
|
|
127993
128031
|
ok: true,
|
|
127994
128032
|
...reportPublic,
|
|
@@ -128016,7 +128054,7 @@ ${canonical5}`;
|
|
|
128016
128054
|
session: {
|
|
128017
128055
|
...shownCaps({ ...policy.limits, sessionLeftAtomic: sessionLeft }),
|
|
128018
128056
|
sessionSpentAtomic: policy.sessionSpentAtomic,
|
|
128019
|
-
summary: sessionSummary,
|
|
128057
|
+
...sessionSummary ? { summary: sessionSummary } : {},
|
|
128020
128058
|
shield: shieldEnabled ? { maxShieldAtomic: money.maxShieldAtomic ?? null, ...movedFields("shield", capOf2(money.maxShieldAtomic)) } : null,
|
|
128021
128059
|
unshield: unshieldEnabled ? {
|
|
128022
128060
|
maxUnshieldAtomic: money.maxUnshieldAtomic ?? null,
|
|
@@ -128903,7 +128941,13 @@ ${canonical5}`;
|
|
|
128903
128941
|
return Boolean(plan) && plan.parts.some((part) => selfPayMayHaveSigned(store, part.unshieldId));
|
|
128904
128942
|
}
|
|
128905
128943
|
const unboundNext = (requestId, amountAtomic) => `Nothing was signed. Do not retry this request_id. Tell your owner: the self-payment of this unshield has no recipient bound to it, so this server will not choose one. The owner finishes it with the CLI: shinjuku unshield (the same --wallet, proof tools, --profile, --program, --facilitator) --unshield-id ${moneyId(requestId)} --amount ${usdcFlagText(amountAtomic)} --to <recipient USDC account> --recipient-owner <recipient owner>`;
|
|
128906
|
-
const preApproved = () => [
|
|
128944
|
+
const preApproved = () => [.../* @__PURE__ */ new Set([...unshieldTo, ...typeof money.unshieldToNow === "function" ? money.unshieldToNow() : []])];
|
|
128945
|
+
const ownAddressCommand = () => {
|
|
128946
|
+
const line = terminalCommand("setup");
|
|
128947
|
+
const home = process.env.SHIELDED_WALLET_HOME;
|
|
128948
|
+
return home ? `${line} (with SHIELDED_WALLET_HOME set to ${home}, as in this app's entry)` : line;
|
|
128949
|
+
};
|
|
128950
|
+
const ownAddressNext = () => `Nothing was sent. Do not retry with another address, and do not run setup yourself. Tell the user: this app could not show you the address to confirm, so nothing was sent. If it is your own wallet, open a terminal and run ${ownAddressCommand()}; it asks for your wallet address (type or paste it there), then ask again here`;
|
|
128907
128951
|
async function anchorWaitAfterDeposit() {
|
|
128908
128952
|
try {
|
|
128909
128953
|
const read = await underLease((store) => readBalanceSnapshot(store));
|
|
@@ -128917,13 +128961,14 @@ ${canonical5}`;
|
|
|
128917
128961
|
return {};
|
|
128918
128962
|
}
|
|
128919
128963
|
}
|
|
128964
|
+
const BACKUP_SAVED_NEXT = ". Tell the user a backup of the wallet was saved (say only that; its folder is in backupPath if the user asks)";
|
|
128920
128965
|
function doneNext(kind, job) {
|
|
128921
128966
|
if (kind === "unshield" && job.result?.privateSend) {
|
|
128922
|
-
return sendDoneNext(job.to, job.result.privateSend) + `${job.result?.backupPath ?
|
|
128967
|
+
return sendDoneNext(job.to, job.result.privateSend) + `${job.result?.backupPath ? BACKUP_SAVED_NEXT : ""}`;
|
|
128923
128968
|
}
|
|
128924
128969
|
if (kind === "unshield") {
|
|
128925
128970
|
const tx = job.result?.exitTransaction;
|
|
128926
|
-
return `Sent ${usdcText2(job.amountAtomic)} USDC to ${job.to}${typeof tx === "string" ? ` (transaction ${tx})` : ""}. Tell the user; nothing to do: the private balance shows it in a few seconds (wallet_balance)${job.result?.backupPath ?
|
|
128971
|
+
return `Sent ${usdcText2(job.amountAtomic)} USDC to ${job.to}${typeof tx === "string" ? ` (transaction ${tx})` : ""}. Tell the user; nothing to do: the private balance shows it in a few seconds (wallet_balance)${job.result?.backupPath ? BACKUP_SAVED_NEXT : ""}`;
|
|
128927
128972
|
}
|
|
128928
128973
|
const post = job.post;
|
|
128929
128974
|
if (!post || post.state === "running") {
|
|
@@ -128931,9 +128976,9 @@ ${canonical5}`;
|
|
|
128931
128976
|
}
|
|
128932
128977
|
if (!post.refreshed) return `the deposit landed; reading it from the chain failed (${post.refreshError}): call wallet_balance in a minute, it retries by itself`;
|
|
128933
128978
|
if (post.spendableAtMs !== void 0 && post.spendableAtMs > Date.now()) {
|
|
128934
|
-
return `the deposit landed and is in the shielded balance. It is spendable in about ${Math.ceil((post.spendableAtMs - Date.now()) / 1e3)} s: x402_pay and wallet_unshield wait for it by themselves, so call them now if the user wants to${post.backupPath ?
|
|
128979
|
+
return `the deposit landed and is in the shielded balance. It is spendable in about ${Math.ceil((post.spendableAtMs - Date.now()) / 1e3)} s: x402_pay and wallet_unshield wait for it by themselves, so call them now if the user wants to${post.backupPath ? BACKUP_SAVED_NEXT : ""}`;
|
|
128935
128980
|
}
|
|
128936
|
-
return `the deposit landed and is in the shielded balance: x402_pay and wallet_unshield can spend it now${post.backupPath ?
|
|
128981
|
+
return `the deposit landed and is in the shielded balance: x402_pay and wallet_unshield can spend it now${post.backupPath ? BACKUP_SAVED_NEXT : ""}`;
|
|
128937
128982
|
}
|
|
128938
128983
|
const ELSEWHERE_PRIVACY = "the chain shows the other wallet paying this new one-time address, and that address depositing this amount into the pool (both public; the facilitator also sees the amount and time). Later payments from the shielded balance do not show which deposit paid them. With few depositors in the pool, an amount few other deposits share, or a payment soon after the deposit, is easier to pair";
|
|
128939
128984
|
const reclaimHow = (requestId) => `only the owner can take it back, with the CLI: shinjuku deposit-reclaim --deposit-id ${elsewhereId(requestId)} --to <a USDC token account> --fee-payer-key-file <a key with a little SOL> (with --pool, --program, --rpc); the chain then links that key and --to to the address`;
|
|
@@ -129068,6 +129113,7 @@ ${canonical5}`;
|
|
|
129068
129113
|
...refused ? { stage: "refused" } : { stage: "failed", failedStage: job.failedStage },
|
|
129069
129114
|
...job.error.largestReceivedAtomic ? { largestReceivedAtomic: job.error.largestReceivedAtomic } : {},
|
|
129070
129115
|
...job.error.libraryCode ? { libraryCode: job.error.libraryCode } : {},
|
|
129116
|
+
...job.error.ownAddressCommand ? { ownAddressCommand: job.error.ownAddressCommand } : {},
|
|
129071
129117
|
...job.error.heldAll ? { heldAll: true } : {},
|
|
129072
129118
|
...job.error.balanceAtomic === "0" ? {
|
|
129073
129119
|
balanceAtomic: "0",
|
|
@@ -130075,8 +130121,8 @@ ${canonical5}`;
|
|
|
130075
130121
|
"mcp_unshield_to_not_allowed",
|
|
130076
130122
|
"this address is not pre-approved, and this MCP client cannot ask the user to confirm a send (it did not declare MCP elicitation); nothing was sent",
|
|
130077
130123
|
// No launch-flag how-to here (fault 8b; mcp5 2026-10-21): an agent or a page it read could use it to have the user allow its own address.
|
|
130078
|
-
|
|
130079
|
-
{ requestId: request.requestId }
|
|
130124
|
+
`${ownAddressNext()}. Addresses allowed now: ${preApproved().join(", ") || "none"}`,
|
|
130125
|
+
{ requestId: request.requestId, ownAddressCommand: ownAddressCommand() }
|
|
130080
130126
|
);
|
|
130081
130127
|
}
|
|
130082
130128
|
if (kind === "unshield" && !record) {
|
|
@@ -130236,7 +130282,8 @@ ${canonical5}`;
|
|
|
130236
130282
|
job.error = {
|
|
130237
130283
|
code: "mcp_unshield_declined",
|
|
130238
130284
|
detail: `${confirmed.why}; nothing was signed or sent`,
|
|
130239
|
-
|
|
130285
|
+
...confirmed.unshown ? { ownAddressCommand: ownAddressCommand() } : {},
|
|
130286
|
+
next: confirmed.unshown ? `${ownAddressNext()}. Asking again in this app without it fails the same way` : "Nothing was sent. Tell the user it was not sent. Send it only if the user asks again: then call wallet_unshield again (it asks the user again)"
|
|
130240
130287
|
};
|
|
130241
130288
|
uncount(kind, key);
|
|
130242
130289
|
log(`MCP_UNSHIELD_DECLINED requestId=${job.requestId}${confirmed.unshown ? " unshown=true" : ""}`);
|
|
@@ -132119,6 +132166,7 @@ ${canonical5}`;
|
|
|
132119
132166
|
const usdcMin = usdcText2(BigInt(quote.minOutAtomic));
|
|
132120
132167
|
const amount = formatAtomic(BigInt(request.amountAtomic), decimals);
|
|
132121
132168
|
const message = `Sell ${amount} of token ${request.tokenMint} for about ${usdcOut} USDC (at least ${usdcMin}; price impact ${(Number(quote.priceImpactPct) * 100).toFixed(2)} %), shield it, and send it to ${request.to} as ${request.parts} parts, each after a random wait of up to ${request.maxDelayMinutes} min? The address receives USDC, not the token.`;
|
|
132169
|
+
const askedAt = Date.now();
|
|
132122
132170
|
try {
|
|
132123
132171
|
const answer = await client.elicit({ message, requestedSchema: {
|
|
132124
132172
|
type: "object",
|
|
@@ -132126,8 +132174,10 @@ ${canonical5}`;
|
|
|
132126
132174
|
required: ["confirm"]
|
|
132127
132175
|
} }, elicitTimeoutMs);
|
|
132128
132176
|
if (answer?.action === "accept" && answer?.content?.confirm !== false) return { ok: true };
|
|
132177
|
+
if (elicitUnshown(askedAt, answer)) return { ok: false, unshown: true, why: `this MCP client answered the confirmation in ${Date.now() - askedAt} ms without showing it to the user` };
|
|
132129
132178
|
return { ok: false, why: answer?.action === "accept" ? "the user did not tick Sell and send" : answer?.action === "cancel" ? "the user closed the confirmation" : "the user declined" };
|
|
132130
132179
|
} catch (error) {
|
|
132180
|
+
if (error?.timedOut !== true && elicitUnshown(askedAt)) return { ok: false, unshown: true, why: "this MCP client could not show the confirmation to the user" };
|
|
132131
132181
|
return { ok: false, why: error?.timedOut === true ? `no answer in ${Math.round(elicitTimeoutMs / 1e3)} s` : "the MCP client did not answer the confirmation" };
|
|
132132
132182
|
}
|
|
132133
132183
|
}
|
|
@@ -132188,8 +132238,8 @@ ${canonical5}`;
|
|
|
132188
132238
|
return refuse12(
|
|
132189
132239
|
"mcp_unshield_to_not_allowed",
|
|
132190
132240
|
"this address is not pre-approved, and this MCP client cannot ask the user to confirm (it did not declare MCP elicitation); nothing was signed",
|
|
132191
|
-
|
|
132192
|
-
{ requestId: id }
|
|
132241
|
+
ownAddressNext(),
|
|
132242
|
+
{ requestId: id, ownAddressCommand: ownAddressCommand() }
|
|
132193
132243
|
);
|
|
132194
132244
|
}
|
|
132195
132245
|
let blocker;
|
|
@@ -132339,8 +132389,8 @@ ${canonical5}`;
|
|
|
132339
132389
|
return refuse12(
|
|
132340
132390
|
"mcp_unshield_declined",
|
|
132341
132391
|
`${confirmed.why}; nothing was signed`,
|
|
132342
|
-
"Nothing was sold or sent. Tell the user it was not done. Do it only if the user asks again: then call wallet_transfer_token again (it asks the user again)",
|
|
132343
|
-
{ requestId: id }
|
|
132392
|
+
confirmed.unshown ? ownAddressNext() : "Nothing was sold or sent. Tell the user it was not done. Do it only if the user asks again: then call wallet_transfer_token again (it asks the user again)",
|
|
132393
|
+
{ requestId: id, ...confirmed.unshown ? { ownAddressCommand: ownAddressCommand() } : {} }
|
|
132344
132394
|
);
|
|
132345
132395
|
}
|
|
132346
132396
|
approval = { by: "elicitation", at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -134638,6 +134688,7 @@ async function openWalletServer({
|
|
|
134638
134688
|
noShield = false,
|
|
134639
134689
|
maxShieldAtomic,
|
|
134640
134690
|
unshieldTo,
|
|
134691
|
+
unshieldToNow,
|
|
134641
134692
|
maxUnshieldAtomic,
|
|
134642
134693
|
exitProofToolsPath,
|
|
134643
134694
|
profilePath,
|
|
@@ -134680,7 +134731,8 @@ async function openWalletServer({
|
|
|
134680
134731
|
{
|
|
134681
134732
|
...fixedMoney,
|
|
134682
134733
|
autoPockets: autoPockets !== false,
|
|
134683
|
-
readyPockets: readyText ? Number(readyText) : DEFAULT_READY_POCKETS
|
|
134734
|
+
readyPockets: readyText ? Number(readyText) : DEFAULT_READY_POCKETS,
|
|
134735
|
+
...typeof unshieldToNow === "function" ? { unshieldToNow } : {}
|
|
134684
134736
|
},
|
|
134685
134737
|
Object.fromEntries(Object.keys(live).map((key) => [key, { get: () => live[key], enumerable: true }]))
|
|
134686
134738
|
));
|
|
@@ -135416,7 +135468,7 @@ async function runChat({ io, values, deps = {} }) {
|
|
|
135416
135468
|
if (code2 === "inference_tor_required" || code2 === "ECONNREFUSED" || proxyRefusedConnection(error)) {
|
|
135417
135469
|
say6(`Your private connection (Tor) stopped answering, so the question could not go out. ${paidWords} Start Tor again, then ${again}.`);
|
|
135418
135470
|
} else if (INSUFFICIENT2.test(code2 ?? "")) {
|
|
135419
|
-
say6(`Your private balance is too low for this answer. ${paidWords} Add funds: ${FUND_COMMAND} (
|
|
135471
|
+
say6(`Your private balance is too low for this answer. ${paidWords} Add funds: ${FUND_COMMAND} (any amount from 0.01 USDC: change 2 to the amount you want), or ask your agent to add funds. Then ${again}.`);
|
|
135420
135472
|
} else if (CAP_CODES.test(code2 ?? "")) {
|
|
135421
135473
|
say6(`This answer would pass the chat's cap. ${paidWords} ${capsLine2()} End the chat (/exit) and start it again, with a higher --max-payment <usdc> or --max-session <usdc> when you want more.`);
|
|
135422
135474
|
} else if (code2 === "inference_no_provider") {
|
|
@@ -155910,7 +155962,7 @@ import { resolve as resolve40 } from "node:path";
|
|
|
155910
155962
|
|
|
155911
155963
|
// wallet/src/cli/shinjukuWallet.mjs
|
|
155912
155964
|
init_fs();
|
|
155913
|
-
var
|
|
155965
|
+
var import_web3139 = __toESM(require_index_cjs(), 1);
|
|
155914
155966
|
init_esm2();
|
|
155915
155967
|
init_shielded_wallet();
|
|
155916
155968
|
init_walk();
|
|
@@ -155936,6 +155988,7 @@ init_config2();
|
|
|
155936
155988
|
// wallet/src/setup/setup.mjs
|
|
155937
155989
|
init_processLease();
|
|
155938
155990
|
init_fs();
|
|
155991
|
+
var import_web3135 = __toESM(require_index_cjs(), 1);
|
|
155939
155992
|
init_secretFile();
|
|
155940
155993
|
init_recoveryFile();
|
|
155941
155994
|
init_config2();
|
|
@@ -156076,6 +156129,27 @@ function readPassphrase(path, access) {
|
|
|
156076
156129
|
if (text3.length < 8) throw fail40("setup_passphrase_too_short", "the passphrase in the passphrase file is shorter than 8 characters; nothing was created");
|
|
156077
156130
|
return text3;
|
|
156078
156131
|
}
|
|
156132
|
+
function addOwnAddress({ home, address: address5 }, deps) {
|
|
156133
|
+
const config = readSetupConfig(home);
|
|
156134
|
+
if (!config?.pool || !config.passphraseFile) throw fail40("setup_own_address_not_set_up", "this wallet home is not set up yet; config.json was not changed. Run setup first");
|
|
156135
|
+
const old = [...config.unshieldTo ?? []];
|
|
156136
|
+
if (old.includes(address5)) return { ownAddresses: old, dropped: [] };
|
|
156137
|
+
let own;
|
|
156138
|
+
try {
|
|
156139
|
+
const passphrase2 = readSecretText(config.passphraseFile, "the passphrase file");
|
|
156140
|
+
own = import_web3135.Keypair.fromSecretKey(Uint8Array.from(deps.openWalletStore(homeWalletPath(home, config.pool), passphrase2).state.solanaSecretKey)).publicKey.toBase58();
|
|
156141
|
+
} catch {
|
|
156142
|
+
own = void 0;
|
|
156143
|
+
}
|
|
156144
|
+
if (own === void 0) throw fail40("setup_own_address_unchecked", "setup could not open the wallet to check that the address is not this wallet's own; config.json was not changed. Run setup again");
|
|
156145
|
+
if (own === address5) {
|
|
156146
|
+
throw fail40("setup_own_address_is_wallet", `${own} is this wallet's own address. A send to it would link your sends to your deposits, so it is never approved. Give the address of another wallet you own (Phantom, Solflare, or an exchange's deposit address); config.json was not changed`);
|
|
156147
|
+
}
|
|
156148
|
+
const all = [...old, address5];
|
|
156149
|
+
const kept = all.slice(-MAX_OWN_ADDRESSES);
|
|
156150
|
+
writeSetupConfig(home, { ...config, unshieldTo: kept });
|
|
156151
|
+
return { ownAddresses: kept, dropped: all.slice(0, all.length - kept.length) };
|
|
156152
|
+
}
|
|
156079
156153
|
async function runSetup(options, deps = {}) {
|
|
156080
156154
|
const home = resolve28(options.home);
|
|
156081
156155
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -156267,6 +156341,7 @@ async function runSetup(options, deps = {}) {
|
|
|
156267
156341
|
const drainingHere = (releasePools?.migration?.from ?? []).filter((entry) => entry.pool !== identity.pool && existsSync(homeWalletPath(home, entry.pool)) && !(previousPools ?? []).some((known) => known.pool === entry.pool));
|
|
156268
156342
|
if (drainingHere.length) previousPools = [...previousPools ?? [], ...drainingHere.map((entry) => ({ pool: entry.pool, program: entry.programId }))].slice(-8);
|
|
156269
156343
|
const torTunnel = tor ? options.torTunnel ?? old?.torTunnel : void 0;
|
|
156344
|
+
const unshieldTo = old?.unshieldTo ? [...old.unshieldTo] : [];
|
|
156270
156345
|
const base = {
|
|
156271
156346
|
schema: CONFIG_SCHEMA,
|
|
156272
156347
|
...identity,
|
|
@@ -156275,6 +156350,7 @@ async function runSetup(options, deps = {}) {
|
|
|
156275
156350
|
caps,
|
|
156276
156351
|
tor,
|
|
156277
156352
|
...torTunnel ? { torTunnel } : {},
|
|
156353
|
+
...unshieldTo.length ? { unshieldTo } : {},
|
|
156278
156354
|
...wallet.recoveryFile ? { recoveryFile: wallet.recoveryFile } : {},
|
|
156279
156355
|
...previousPools?.length ? { previousPools } : {}
|
|
156280
156356
|
};
|
|
@@ -156362,6 +156438,7 @@ async function runSetup(options, deps = {}) {
|
|
|
156362
156438
|
wallet,
|
|
156363
156439
|
passphraseFile,
|
|
156364
156440
|
passphraseGenerated,
|
|
156441
|
+
ownAddresses: unshieldTo,
|
|
156365
156442
|
proofTools: { dir: tools.dir, downloaded: tools.downloaded, folder: tools.folder },
|
|
156366
156443
|
platform: platform.wsl ? "windows+wsl" : "linux",
|
|
156367
156444
|
warnings,
|
|
@@ -157333,7 +157410,7 @@ init_cli3();
|
|
|
157333
157410
|
|
|
157334
157411
|
// wallet/src/deposit/privacyCash.mjs
|
|
157335
157412
|
init_fs();
|
|
157336
|
-
var
|
|
157413
|
+
var import_web3138 = __toESM(require_index_cjs(), 1);
|
|
157337
157414
|
init_esm2();
|
|
157338
157415
|
init_balance();
|
|
157339
157416
|
init_chain2();
|
|
@@ -157347,7 +157424,7 @@ import { dirname as dirname30, join as join36, resolve as resolve32 } from "node
|
|
|
157347
157424
|
import { fileURLToPath as fileURLToPath20, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
157348
157425
|
|
|
157349
157426
|
// wallet/src/deposit/privacyCashLocal.mjs
|
|
157350
|
-
var
|
|
157427
|
+
var import_web3136 = __toESM(require_index_cjs(), 1);
|
|
157351
157428
|
init_esm2();
|
|
157352
157429
|
init_chain2();
|
|
157353
157430
|
import { randomInt as randomInt8 } from "node:crypto";
|
|
@@ -157425,7 +157502,7 @@ async function withoutPrivacyCashServer(operation) {
|
|
|
157425
157502
|
}
|
|
157426
157503
|
}
|
|
157427
157504
|
async function currentTreeState(connection, ids) {
|
|
157428
|
-
const info = await retryRpc2(() => connection.getAccountInfo(new
|
|
157505
|
+
const info = await retryRpc2(() => connection.getAccountInfo(new import_web3136.PublicKey(ids.tree), "confirmed"));
|
|
157429
157506
|
if (!info || info.owner.toBase58() !== ids.program || info.data.length < TREE_ROOT_OFFSET + 32) fail43("pool_unreadable");
|
|
157430
157507
|
const data = Buffer.from(info.data);
|
|
157431
157508
|
return {
|
|
@@ -157434,7 +157511,7 @@ async function currentTreeState(connection, ids) {
|
|
|
157434
157511
|
};
|
|
157435
157512
|
}
|
|
157436
157513
|
async function programFeeRule(connection, ids) {
|
|
157437
|
-
const info = await retryRpc2(() => connection.getAccountInfo(new
|
|
157514
|
+
const info = await retryRpc2(() => connection.getAccountInfo(new import_web3136.PublicKey(ids.globalConfig), "finalized"));
|
|
157438
157515
|
if (!info || info.owner.toBase58() !== ids.program || info.data.length < FEE_ERROR_MARGIN_OFFSET + 2) fail43("pool_unreadable");
|
|
157439
157516
|
const data = Buffer.from(info.data);
|
|
157440
157517
|
return { withdrawalFeeRate: BigInt(data.readUInt16LE(WITHDRAWAL_FEE_RATE_OFFSET)), feeErrorMargin: BigInt(data.readUInt16LE(FEE_ERROR_MARGIN_OFFSET)) };
|
|
@@ -157444,25 +157521,25 @@ function programMinimumFee(net2, rule) {
|
|
|
157444
157521
|
return expected === 0n ? 0n : expected * (10000n - rule.feeErrorMargin) / 10000n;
|
|
157445
157522
|
}
|
|
157446
157523
|
function transactAccounts({ ids, nullifiers, signer, signerTokenAccount, recipient, recipientTokenAccount, feeRecipientTokenAccount }) {
|
|
157447
|
-
const program = new
|
|
157448
|
-
const pda = (seed, value) =>
|
|
157524
|
+
const program = new import_web3136.PublicKey(ids.program);
|
|
157525
|
+
const pda = (seed, value) => import_web3136.PublicKey.findProgramAddressSync([Buffer.from(seed), value], program)[0];
|
|
157449
157526
|
return [
|
|
157450
|
-
{ pubkey: new
|
|
157527
|
+
{ pubkey: new import_web3136.PublicKey(ids.tree), isSigner: false, isWritable: true },
|
|
157451
157528
|
{ pubkey: pda("nullifier0", nullifiers[0]), isSigner: false, isWritable: true },
|
|
157452
157529
|
{ pubkey: pda("nullifier1", nullifiers[1]), isSigner: false, isWritable: true },
|
|
157453
157530
|
{ pubkey: pda("nullifier0", nullifiers[1]), isSigner: false, isWritable: false },
|
|
157454
157531
|
{ pubkey: pda("nullifier1", nullifiers[0]), isSigner: false, isWritable: false },
|
|
157455
|
-
{ pubkey: new
|
|
157532
|
+
{ pubkey: new import_web3136.PublicKey(ids.globalConfig), isSigner: false, isWritable: false },
|
|
157456
157533
|
{ pubkey: signer, isSigner: true, isWritable: true },
|
|
157457
|
-
{ pubkey: new
|
|
157534
|
+
{ pubkey: new import_web3136.PublicKey(ids.mint), isSigner: false, isWritable: false },
|
|
157458
157535
|
{ pubkey: signerTokenAccount, isSigner: false, isWritable: true },
|
|
157459
157536
|
{ pubkey: recipient, isSigner: false, isWritable: true },
|
|
157460
157537
|
{ pubkey: recipientTokenAccount, isSigner: false, isWritable: true },
|
|
157461
|
-
{ pubkey: new
|
|
157538
|
+
{ pubkey: new import_web3136.PublicKey(ids.vault), isSigner: false, isWritable: true },
|
|
157462
157539
|
{ pubkey: feeRecipientTokenAccount, isSigner: false, isWritable: true },
|
|
157463
157540
|
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
157464
157541
|
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
157465
|
-
{ pubkey:
|
|
157542
|
+
{ pubkey: import_web3136.SystemProgram.programId, isSigner: false, isWritable: false }
|
|
157466
157543
|
];
|
|
157467
157544
|
}
|
|
157468
157545
|
async function proveTransact({ internals, sdk, encryptionService, inputs, paths, root, nextIndex, outputAmount, extAmount, fee, recipientTokenAccount, feeRecipientTokenAccount, mint, padChange = false }) {
|
|
@@ -157495,7 +157572,7 @@ async function proveTransact({ internals, sdk, encryptionService, inputs, paths,
|
|
|
157495
157572
|
const extDataHashDecimal = BigInt(`0x${Buffer.from(extDataHash).reverse().toString("hex")}`).toString();
|
|
157496
157573
|
const input = {
|
|
157497
157574
|
root,
|
|
157498
|
-
mintAddress: internals.getMintAddressField(new
|
|
157575
|
+
mintAddress: internals.getMintAddressField(new import_web3136.PublicKey(mint)),
|
|
157499
157576
|
publicAmount: publicAmount.toString(),
|
|
157500
157577
|
extDataHash,
|
|
157501
157578
|
inAmount: inputs.map((utxo) => utxo.amount.toString(10)),
|
|
@@ -157529,7 +157606,7 @@ async function proveTransact({ internals, sdk, encryptionService, inputs, paths,
|
|
|
157529
157606
|
return { data, nullifiers: inputNullifiers.map(toBeBytes), outputs };
|
|
157530
157607
|
}
|
|
157531
157608
|
function compile({ payer, blockhash, instructions: instructions2, lookupTable, priceInstruction }) {
|
|
157532
|
-
const build2 = (list) => new
|
|
157609
|
+
const build2 = (list) => new import_web3136.VersionedTransaction(new import_web3136.TransactionMessage({ payerKey: payer, recentBlockhash: blockhash, instructions: list }).compileToV0Message([lookupTable]));
|
|
157533
157610
|
const transaction = build2(priceInstruction ? [instructions2[0], priceInstruction, ...instructions2.slice(1)] : instructions2);
|
|
157534
157611
|
let bytes2;
|
|
157535
157612
|
try {
|
|
@@ -157561,7 +157638,7 @@ async function buildLocalDeposit({ internals, sdk, connection, ids, source, amou
|
|
|
157561
157638
|
paths = [zeroPath(), zeroPath()];
|
|
157562
157639
|
}
|
|
157563
157640
|
const total = inputs.reduce((sum2, utxo) => sum2 + BigInt(utxo.amount.toString()), 0n) + BigInt(amount);
|
|
157564
|
-
const placeholder = getAssociatedTokenAddressSync(new
|
|
157641
|
+
const placeholder = getAssociatedTokenAddressSync(new import_web3136.PublicKey(mint), new import_web3136.PublicKey(ids.feeRecipient), true, TOKEN_PROGRAM_ID);
|
|
157565
157642
|
const proved = await proveTransact({
|
|
157566
157643
|
internals,
|
|
157567
157644
|
sdk,
|
|
@@ -157577,28 +157654,28 @@ async function buildLocalDeposit({ internals, sdk, connection, ids, source, amou
|
|
|
157577
157654
|
feeRecipientTokenAccount: placeholder,
|
|
157578
157655
|
mint
|
|
157579
157656
|
});
|
|
157580
|
-
const sourceTokenAccount = getAssociatedTokenAddressSync(new
|
|
157581
|
-
const deposit = new
|
|
157582
|
-
programId: new
|
|
157657
|
+
const sourceTokenAccount = getAssociatedTokenAddressSync(new import_web3136.PublicKey(mint), source, false, TOKEN_PROGRAM_ID);
|
|
157658
|
+
const deposit = new import_web3136.TransactionInstruction({
|
|
157659
|
+
programId: new import_web3136.PublicKey(ids.program),
|
|
157583
157660
|
keys: transactAccounts({
|
|
157584
157661
|
ids,
|
|
157585
157662
|
nullifiers: proved.nullifiers,
|
|
157586
157663
|
signer: source,
|
|
157587
157664
|
signerTokenAccount: sourceTokenAccount,
|
|
157588
|
-
recipient: new
|
|
157665
|
+
recipient: new import_web3136.PublicKey(ids.feeRecipient),
|
|
157589
157666
|
recipientTokenAccount: placeholder,
|
|
157590
157667
|
feeRecipientTokenAccount: placeholder
|
|
157591
157668
|
}),
|
|
157592
157669
|
data: proved.data
|
|
157593
157670
|
});
|
|
157594
|
-
const table = (await retryRpc2(() => connection.getAddressLookupTable(new
|
|
157671
|
+
const table = (await retryRpc2(() => connection.getAddressLookupTable(new import_web3136.PublicKey(ids.lookupTable)))).value;
|
|
157595
157672
|
if (!table) fail43("pool_unreadable");
|
|
157596
157673
|
const latest = await retryRpc2(() => connection.getLatestBlockhash("confirmed"));
|
|
157597
157674
|
const transaction = compile({
|
|
157598
157675
|
payer: source,
|
|
157599
157676
|
blockhash: latest.blockhash,
|
|
157600
|
-
instructions: [
|
|
157601
|
-
priceInstruction:
|
|
157677
|
+
instructions: [import_web3136.ComputeBudgetProgram.setComputeUnitLimit({ units: SDK_DEPOSIT_COMPUTE_UNITS }), deposit],
|
|
157678
|
+
priceInstruction: import_web3136.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: SDK_DEPOSIT_MICRO_LAMPORTS }),
|
|
157602
157679
|
lookupTable: table
|
|
157603
157680
|
});
|
|
157604
157681
|
return {
|
|
@@ -157625,13 +157702,13 @@ async function readRelayConfig2({ serviceUrl: serviceUrl2, ids, fetchImpl = fetc
|
|
|
157625
157702
|
let feeTokenAccount;
|
|
157626
157703
|
let lookupTable;
|
|
157627
157704
|
try {
|
|
157628
|
-
feePayer = new
|
|
157629
|
-
feeTokenAccount = new
|
|
157630
|
-
lookupTable = new
|
|
157705
|
+
feePayer = new import_web3136.PublicKey(config?.feePayer);
|
|
157706
|
+
feeTokenAccount = new import_web3136.PublicKey(config?.feeTokenAccount);
|
|
157707
|
+
lookupTable = new import_web3136.PublicKey(config?.lookupTable);
|
|
157631
157708
|
} catch {
|
|
157632
157709
|
fail43("relay_config_invalid");
|
|
157633
157710
|
}
|
|
157634
|
-
if (config?.schema !== PRIVACY_CASH_RELAY_CONFIG_SCHEMA || config.programId !== ids.program || config.mint !== ids.mint || feePayer.toBase58() !== config.feePayer || lookupTable.toBase58() !== config.lookupTable || !feeTokenAccount.equals(getAssociatedTokenAddressSync(new
|
|
157711
|
+
if (config?.schema !== PRIVACY_CASH_RELAY_CONFIG_SCHEMA || config.programId !== ids.program || config.mint !== ids.mint || feePayer.toBase58() !== config.feePayer || lookupTable.toBase58() !== config.lookupTable || !feeTokenAccount.equals(getAssociatedTokenAddressSync(new import_web3136.PublicKey(ids.mint), feePayer, false, TOKEN_PROGRAM_ID)) || !atomic4(config.feeFloorAtomic) || !atomic4(config.minimumAtomic) || !atomic4(config.maximumAtomic) || !atomic4(config.computeUnitPriceMicroLamports) || !Number.isSafeInteger(config.computeUnitLimit) || config.computeUnitLimit < 3e5 || config.computeUnitLimit > 14e5) {
|
|
157635
157712
|
fail43("relay_config_mismatch");
|
|
157636
157713
|
}
|
|
157637
157714
|
return Object.freeze({
|
|
@@ -157654,8 +157731,8 @@ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptio
|
|
|
157654
157731
|
const total = inputs.reduce((sum2, utxo) => sum2 + BigInt(utxo.amount.toString()), 0n);
|
|
157655
157732
|
const change = total - net2 - fee;
|
|
157656
157733
|
if (change < 0n) fail43("withdraw_balance_insufficient");
|
|
157657
|
-
const owner = new
|
|
157658
|
-
const recipientTokenAccount = getAssociatedTokenAddressSync(new
|
|
157734
|
+
const owner = new import_web3136.PublicKey(recipient);
|
|
157735
|
+
const recipientTokenAccount = getAssociatedTokenAddressSync(new import_web3136.PublicKey(mint), owner, false, TOKEN_PROGRAM_ID);
|
|
157659
157736
|
const proved = await proveTransact({
|
|
157660
157737
|
internals,
|
|
157661
157738
|
sdk,
|
|
@@ -157672,8 +157749,8 @@ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptio
|
|
|
157672
157749
|
mint,
|
|
157673
157750
|
padChange: true
|
|
157674
157751
|
});
|
|
157675
|
-
const withdrawal = new
|
|
157676
|
-
programId: new
|
|
157752
|
+
const withdrawal = new import_web3136.TransactionInstruction({
|
|
157753
|
+
programId: new import_web3136.PublicKey(ids.program),
|
|
157677
157754
|
keys: transactAccounts({
|
|
157678
157755
|
ids,
|
|
157679
157756
|
nullifiers: proved.nullifiers,
|
|
@@ -157692,12 +157769,12 @@ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptio
|
|
|
157692
157769
|
payer: relay.feePayer,
|
|
157693
157770
|
blockhash: latest.blockhash,
|
|
157694
157771
|
instructions: [
|
|
157695
|
-
|
|
157772
|
+
import_web3136.ComputeBudgetProgram.setComputeUnitLimit({ units: relay.computeUnitLimit }),
|
|
157696
157773
|
// Create with empty data, as Privacy Cash's relayer sends it (30 of 30 new recipients); the address is fresh.
|
|
157697
|
-
createAssociatedTokenAccountInstruction(relay.feePayer, recipientTokenAccount, owner, new
|
|
157774
|
+
createAssociatedTokenAccountInstruction(relay.feePayer, recipientTokenAccount, owner, new import_web3136.PublicKey(mint), TOKEN_PROGRAM_ID),
|
|
157698
157775
|
withdrawal
|
|
157699
157776
|
],
|
|
157700
|
-
priceInstruction: relay.computeUnitPrice > 0n ?
|
|
157777
|
+
priceInstruction: relay.computeUnitPrice > 0n ? import_web3136.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: relay.computeUnitPrice }) : void 0,
|
|
157701
157778
|
lookupTable: table
|
|
157702
157779
|
});
|
|
157703
157780
|
return {
|
|
@@ -157745,15 +157822,15 @@ async function relayWithdrawal({ serviceUrl: serviceUrl2, transactionBase64, fet
|
|
|
157745
157822
|
}
|
|
157746
157823
|
|
|
157747
157824
|
// wallet/src/deposit/privacyCashTree.mjs
|
|
157748
|
-
var
|
|
157825
|
+
var import_web3137 = __toESM(require_index_cjs(), 1);
|
|
157749
157826
|
init_chain2();
|
|
157750
157827
|
init_proxy();
|
|
157751
157828
|
init_sealedCache();
|
|
157752
157829
|
init_reference2();
|
|
157753
157830
|
import { createHash as createHash32, createPublicKey as createPublicKey6, verify as verify3 } from "node:crypto";
|
|
157754
|
-
var PROGRAM_ID = new
|
|
157755
|
-
var USDC_MINT2 = new
|
|
157756
|
-
var TREE_ACCOUNT =
|
|
157831
|
+
var PROGRAM_ID = new import_web3137.PublicKey("9fhQBbumKEFuXtMBDw8AaQyAjCorLGJQiS3skWZdQyQD");
|
|
157832
|
+
var USDC_MINT2 = new import_web3137.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
157833
|
+
var TREE_ACCOUNT = import_web3137.PublicKey.findProgramAddressSync([Buffer.from("merkle_tree"), USDC_MINT2.toBuffer()], PROGRAM_ID)[0];
|
|
157757
157834
|
var TREE_DEPTH3 = 26;
|
|
157758
157835
|
var TREE_ACCOUNT_BYTES = 4136;
|
|
157759
157836
|
var NEXT_INDEX_OFFSET = 40;
|
|
@@ -157966,7 +158043,7 @@ function transactionMessage(signature2, result) {
|
|
|
157966
158043
|
decoded = decodeVersion1(raw);
|
|
157967
158044
|
} else {
|
|
157968
158045
|
if (raw[0] === 0 || raw[0] > 127) throw new Error("unknown transaction format");
|
|
157969
|
-
const { message } =
|
|
158046
|
+
const { message } = import_web3137.VersionedTransaction.deserialize(raw);
|
|
157970
158047
|
decoded = {
|
|
157971
158048
|
message: raw.subarray(1 + 64 * raw[0]),
|
|
157972
158049
|
first: raw.subarray(1, 65),
|
|
@@ -158311,7 +158388,7 @@ function countCoverDeposits(crowd, { sinceLeafIndex, sinceSlot, grossAtomic }) {
|
|
|
158311
158388
|
return Object.freeze({ count: count2, from: crowd.from, lowerBound });
|
|
158312
158389
|
}
|
|
158313
158390
|
async function findUnspentNotes({ leaves, encryptionService, lightWasm, mint = USDC_MINT2, spent = [], knownSpent = /* @__PURE__ */ new Set() }) {
|
|
158314
|
-
const mintAddress = new
|
|
158391
|
+
const mintAddress = new import_web3137.PublicKey(mint).toBase58();
|
|
158315
158392
|
const notes = [];
|
|
158316
158393
|
for (const [index, leaf] of leaves.entries()) {
|
|
158317
158394
|
let utxo;
|
|
@@ -158535,7 +158612,7 @@ function readSourceKeyFile(path) {
|
|
|
158535
158612
|
fail45("key_file_invalid");
|
|
158536
158613
|
}
|
|
158537
158614
|
try {
|
|
158538
|
-
return
|
|
158615
|
+
return import_web3138.Keypair.fromSecretKey(Uint8Array.from(bytes2));
|
|
158539
158616
|
} catch {
|
|
158540
158617
|
return fail45("key_file_invalid");
|
|
158541
158618
|
}
|
|
@@ -158562,7 +158639,7 @@ async function tokenBalance(connection, tokenAccount, commitment = "finalized")
|
|
|
158562
158639
|
try {
|
|
158563
158640
|
account2 = await retryRpc2(async () => {
|
|
158564
158641
|
try {
|
|
158565
|
-
return await getAccount(connection, new
|
|
158642
|
+
return await getAccount(connection, new import_web3138.PublicKey(tokenAccount), commitment, TOKEN_PROGRAM_ID);
|
|
158566
158643
|
} catch (error) {
|
|
158567
158644
|
if (error instanceof TokenAccountNotFoundError) return null;
|
|
158568
158645
|
throw error;
|
|
@@ -158585,7 +158662,7 @@ function assertDepositTransaction(transaction, { source, sourceTokenAccount, amo
|
|
|
158585
158662
|
}
|
|
158586
158663
|
const key = (index) => keys3.get(index)?.toBase58();
|
|
158587
158664
|
if (key(0) !== source) fail45("deposit_transaction_unexpected");
|
|
158588
|
-
const budget =
|
|
158665
|
+
const budget = import_web3138.ComputeBudgetProgram.programId.toBase58();
|
|
158589
158666
|
let unitLimit;
|
|
158590
158667
|
let unitPrice;
|
|
158591
158668
|
for (const instruction of message.compiledInstructions.filter((candidate) => key(candidate.programIdIndex) === budget)) {
|
|
@@ -158702,12 +158779,12 @@ async function privacyCashDeposit({ store, rpcUrl, treeRpcUrl, keyFile, amountAt
|
|
|
158702
158779
|
}));
|
|
158703
158780
|
return Object.freeze({ command: "privacy-cash deposit", settleOnly: true, source, deposits: deposits2 });
|
|
158704
158781
|
}
|
|
158705
|
-
const mint = new
|
|
158782
|
+
const mint = new import_web3138.PublicKey(USDC_MINT3);
|
|
158706
158783
|
const sourceTokenAccount = getAssociatedTokenAddressSync(mint, keypair.publicKey, false, TOKEN_PROGRAM_ID).toBase58();
|
|
158707
158784
|
const held = await tokenBalance(connection, sourceTokenAccount);
|
|
158708
158785
|
if (held < amount) fail45("source_usdc_insufficient", { heldAtomic: held.toString() });
|
|
158709
158786
|
if (await retryRpc2(() => connection.getBalance(keypair.publicKey, "finalized")) < MIN_SOURCE_LAMPORTS) fail45("source_sol_insufficient");
|
|
158710
|
-
const [tree] =
|
|
158787
|
+
const [tree] = import_web3138.PublicKey.findProgramAddressSync([Buffer.from("merkle_tree"), mint.toBuffer()], new import_web3138.PublicKey(PRIVACY_CASH.program));
|
|
158711
158788
|
const treeAccount = await retryRpc2(() => connection.getAccountInfo(tree, "finalized"));
|
|
158712
158789
|
if (!treeAccount || treeAccount.owner.toBase58() !== PRIVACY_CASH.program || treeAccount.data.length < 4128) fail45("pool_unreadable");
|
|
158713
158790
|
if (amount > Buffer.from(treeAccount.data).readBigUInt64LE(4120)) fail45("deposit_above_limit");
|
|
@@ -158866,8 +158943,8 @@ function relayedDeposit(store, depositId) {
|
|
|
158866
158943
|
const record = store.readWal(`deposit-${depositId}`);
|
|
158867
158944
|
if (!record) fail45("withdraw_no_relayed_deposit");
|
|
158868
158945
|
if (record.schema !== DEPOSIT_WAL_SCHEMA || !record.relay) fail45("withdraw_not_a_relayed_deposit");
|
|
158869
|
-
const owner = new
|
|
158870
|
-
if (record.asset !== USDC_MINT3 || getAssociatedTokenAddressSync(new
|
|
158946
|
+
const owner = new import_web3138.PublicKey(record.relay.owner);
|
|
158947
|
+
if (record.asset !== USDC_MINT3 || getAssociatedTokenAddressSync(new import_web3138.PublicKey(USDC_MINT3), owner, true, TOKEN_PROGRAM_ID).toBase58() !== record.relay.tokenAccount) {
|
|
158871
158948
|
fail45("withdraw_one_time_address_mismatch");
|
|
158872
158949
|
}
|
|
158873
158950
|
return { record, owner: record.relay.owner, tokenAccount: record.relay.tokenAccount, amount: BigInt(record.amountAtomic) };
|
|
@@ -159031,8 +159108,8 @@ function proofFacts(data) {
|
|
|
159031
159108
|
}
|
|
159032
159109
|
const first = data.subarray(NULLIFIERS_OFFSET2, NULLIFIERS_OFFSET2 + 32);
|
|
159033
159110
|
const second = data.subarray(NULLIFIERS_OFFSET2 + 32, NULLIFIERS_OFFSET2 + 64);
|
|
159034
|
-
const program = new
|
|
159035
|
-
const account2 = (seed, nullifier) =>
|
|
159111
|
+
const program = new import_web3138.PublicKey(PRIVACY_CASH.program);
|
|
159112
|
+
const account2 = (seed, nullifier) => import_web3138.PublicKey.findProgramAddressSync([Buffer.from(seed), nullifier], program)[0].toBase58();
|
|
159036
159113
|
return {
|
|
159037
159114
|
rootHex: data.subarray(ROOT_OFFSET, ROOT_OFFSET + 32).toString("hex"),
|
|
159038
159115
|
nullifiersHex: [first.toString("hex"), second.toString("hex")],
|
|
@@ -159042,7 +159119,7 @@ function proofFacts(data) {
|
|
|
159042
159119
|
function transactSplData(transactionBase64) {
|
|
159043
159120
|
let transaction;
|
|
159044
159121
|
try {
|
|
159045
|
-
transaction =
|
|
159122
|
+
transaction = import_web3138.VersionedTransaction.deserialize(Buffer.from(transactionBase64, "base64"));
|
|
159046
159123
|
} catch {
|
|
159047
159124
|
fail45("withdraw_proof_unreadable");
|
|
159048
159125
|
}
|
|
@@ -159091,7 +159168,7 @@ async function oneTimeAccountHistory(connection, tokenAccount, sinceMs) {
|
|
|
159091
159168
|
const signatures = [];
|
|
159092
159169
|
let before;
|
|
159093
159170
|
for (let page = 0; page < 10; page += 1) {
|
|
159094
|
-
const entries = await retryRpc2(() => connection.getSignaturesForAddress(new
|
|
159171
|
+
const entries = await retryRpc2(() => connection.getSignaturesForAddress(new import_web3138.PublicKey(tokenAccount), { limit: 100, ...before ? { before } : {} }, "finalized"));
|
|
159095
159172
|
for (const entry of entries) {
|
|
159096
159173
|
if (entry.blockTime && entry.blockTime * 1e3 < sinceMs) return signatures;
|
|
159097
159174
|
if (entry.err === null) signatures.push(entry.signature);
|
|
@@ -159161,7 +159238,7 @@ async function earlierProofs(connection, record, walk = void 0) {
|
|
|
159161
159238
|
const roots = /* @__PURE__ */ new Set([...finalized.roots, ...confirmed.roots]);
|
|
159162
159239
|
const walked = walk ? (await walk()).synced : void 0;
|
|
159163
159240
|
for (const proof of record.proofs) {
|
|
159164
|
-
const keys3 = proof.nullifierAccounts.map((key) => new
|
|
159241
|
+
const keys3 = proof.nullifierAccounts.map((key) => new import_web3138.PublicKey(key));
|
|
159165
159242
|
if (walked) {
|
|
159166
159243
|
const paid = proof.nullifiersHex.filter((nullifier) => walked.spentNullifiers.has(nullifier)).map((nullifier) => walked.spentNullifiers.get(nullifier));
|
|
159167
159244
|
if (paid.length && paid.every((account2) => account2 !== null && account2 !== record.oneTimeTokenAccount)) continue;
|
|
@@ -159309,7 +159386,7 @@ async function privacyCashWithdraw({ store, rpcUrl, treeRpcUrl, keyFile, deposit
|
|
|
159309
159386
|
if (uncounted && !holdOverride) fail45("withdraw_crowd_uncounted", { via, reason: uncounted });
|
|
159310
159387
|
const recent = via === "sdk" ? await recentCrowd({ connection, seconds: CROWD_WINDOW_DAYS * 86400, now: Math.floor(chainNow / 1e3) }) : void 0;
|
|
159311
159388
|
if (place && !uncounted && recent) countFrom(recent, { sinceLeafIndex: place.leafIndex, sinceSlot: place.slot }, "deposit");
|
|
159312
|
-
const mint = new
|
|
159389
|
+
const mint = new import_web3138.PublicKey(USDC_MINT3);
|
|
159313
159390
|
const encryptionService = noteKeys(sdk.utils, keypair);
|
|
159314
159391
|
const storage = memoryStorage();
|
|
159315
159392
|
const sdkConnection = connect2(rpcUrl, "confirmed");
|
|
@@ -159474,7 +159551,7 @@ async function privacyCashWithdraw({ store, rpcUrl, treeRpcUrl, keyFile, deposit
|
|
|
159474
159551
|
let answer;
|
|
159475
159552
|
try {
|
|
159476
159553
|
answer = await watchedSdkWithdraw(() => quietly(() => sdk.utils.withdrawSPL({
|
|
159477
|
-
recipient: new
|
|
159554
|
+
recipient: new import_web3138.PublicKey(deposit.owner),
|
|
159478
159555
|
lightWasm: sdk.lightWasm,
|
|
159479
159556
|
storage,
|
|
159480
159557
|
publicKey: keypair.publicKey,
|
|
@@ -159978,8 +160055,8 @@ function fundingWait(ctx, held) {
|
|
|
159978
160055
|
const { plan, store } = ctx;
|
|
159979
160056
|
const decimals = Number(store.state.decimals ?? 6);
|
|
159980
160057
|
const part = /^[0-9]{1,20}$/.test(String(held ?? "")) && BigInt(held) > 0n ? BigInt(held) : 0n;
|
|
159981
|
-
const
|
|
159982
|
-
const holds = part > 0n ? `; it holds ${usdc5(part, decimals)} so far: send the rest${
|
|
160058
|
+
const usable = plan.route === "privacy-cash" ? part - part % ONE_USDC : part >= PAY_ME_MIN_ATOMIC ? part : 0n;
|
|
160059
|
+
const holds = part > 0n ? `; it holds ${usdc5(part, decimals)} so far: send the rest${usable > 0n ? `, or stop add-funds (Ctrl-C) and rerun it with --amount ${usdcFlag(usable)}${usable < part ? ` (take the rest back later with ${CLI} deposit-reclaim)` : ""}` : ""}` : "";
|
|
159983
160060
|
return `${usdc5(plan.amountAtomic, decimals)} USDC (Solana SPL) at ${relayedDeposit2(store, plan)?.relay?.owner ?? "the one-time address"}${holds}`;
|
|
159984
160061
|
}
|
|
159985
160062
|
function splitFundingWait(ctx, waiting) {
|
|
@@ -161969,7 +162046,7 @@ function validateMcp(values, env) {
|
|
|
161969
162046
|
for (const address5 of unshieldTo) {
|
|
161970
162047
|
let canonical5 = false;
|
|
161971
162048
|
try {
|
|
161972
|
-
canonical5 = new
|
|
162049
|
+
canonical5 = new import_web3139.PublicKey(address5).toBase58() === address5;
|
|
161973
162050
|
} catch {
|
|
161974
162051
|
canonical5 = false;
|
|
161975
162052
|
}
|
|
@@ -162055,6 +162132,8 @@ function mcpServerOptions(values, deps) {
|
|
|
162055
162132
|
...values.has("--no-shield") ? { noShield: true } : {},
|
|
162056
162133
|
...values.has("--max-shield") ? { maxShieldAtomic: values.get("--max-shield") } : {},
|
|
162057
162134
|
...values.has("--unshield-to") ? { unshieldTo: values.get("--unshield-to") } : {},
|
|
162135
|
+
// A mcp run from config.json reads the user's own addresses again on each send (setup --own-address after the start).
|
|
162136
|
+
...values.get(MCP_FROM_CONFIG) ? { unshieldToNow: () => ownAddressesNow(values.get(MCP_FROM_CONFIG).home) } : {},
|
|
162058
162137
|
...values.has("--max-unshield") ? { maxUnshieldAtomic: values.get("--max-unshield") } : {},
|
|
162059
162138
|
...values.has("--exit-proof-tools") ? { exitProofToolsPath: values.get("--exit-proof-tools") } : {},
|
|
162060
162139
|
...values.has("--profile") ? { profilePath: values.get("--profile") } : {},
|
|
@@ -162369,10 +162448,10 @@ var fundArgvOf = (amount) => SETUP_FUND_ARGV.map((word, index) => SETUP_FUND_ARG
|
|
|
162369
162448
|
var fundCommandText = (tor, amount = "2") => `${CLI2} ${fundArgvOf(amount).map(shellWord).join(" ")}${tor ? " --tor" : ""}`;
|
|
162370
162449
|
function fundingStepText(tor) {
|
|
162371
162450
|
return [
|
|
162372
|
-
"Add money: the wallet starts empty. Two private ways:",
|
|
162373
|
-
|
|
162374
|
-
|
|
162375
|
-
"
|
|
162451
|
+
"Add money: the wallet starts empty. Two private ways, each for any amount from 0.01 USDC:",
|
|
162452
|
+
` In this terminal: ${fundCommandText(tor)}`,
|
|
162453
|
+
" It prints a one-time address and its QR code: send exactly that amount of USDC (Solana SPL) to it from an exchange or a phone wallet, and it makes the USDC private by itself (our relayer pays every fee). --amount is in USDC (2 = 2 USDC, 0.05 = 5 cents): change it to the amount you want.",
|
|
162454
|
+
' Or ask your agent: add the server to your agent host (above), then ask "Add 0.50 USDC to my private balance". It calls wallet_add_funds and gives a one-time address: send that USDC on Solana from any wallet or exchange, and it becomes private a few minutes after it arrives, at the next wallet call (no SOL needed; our relayer pays every fee).',
|
|
162376
162455
|
""
|
|
162377
162456
|
].join("\n");
|
|
162378
162457
|
}
|
|
@@ -162387,8 +162466,8 @@ function privateInferencePath(config, { apiKey } = {}) {
|
|
|
162387
162466
|
text: [
|
|
162388
162467
|
"Private inference: your agent's first private AI answer in five steps.",
|
|
162389
162468
|
` 1. Fund: ${fundCommandText(true)}`,
|
|
162390
|
-
" It prints a one-time address:
|
|
162391
|
-
" Or
|
|
162469
|
+
" It prints a one-time address and its QR code: send exactly that amount of USDC (Solana SPL) to it from an exchange or a phone wallet. --amount is in USDC, any amount from 0.01 (2 = 2 USDC, 0.05 = 5 cents): change it to the amount you want.",
|
|
162470
|
+
" Or let the agent fund it over MCP: ask it to add funds; the tool wallet_add_funds gives a one-time address for USDC in another wallet or an exchange.",
|
|
162392
162471
|
" 2. Shield: add-funds does it. It moves the USDC into the shielded pool (our relayer pays every fee) and says ready with your balance; all of it stays there, where infer pays from.",
|
|
162393
162472
|
` 3. First private call (a short qwen3-8-flash answer costs about 0.0013 USDC: the AI provider's price plus the 0.001 USDC Shinjuku fee; setup never pays one). It needs no flags: config.json gives the wallet, the caps, and Tor:`,
|
|
162394
162473
|
` echo "Say hello" | ${CLI2} infer -`,
|
|
@@ -162405,14 +162484,39 @@ function privateInferencePath(config, { apiKey } = {}) {
|
|
|
162405
162484
|
].join("\n")
|
|
162406
162485
|
};
|
|
162407
162486
|
}
|
|
162487
|
+
async function askOwnAddress(deps, recorded = []) {
|
|
162488
|
+
const question = recorded.length ? `Your own wallet addresses now: ${recorded.join(", ")}. Add another one (Phantom, Solflare, or an exchange)? Paste it, or press Enter to skip: ` : "Your own wallet address (Phantom, Solflare, or an exchange), for sending money back to yourself? Paste it, or press Enter to skip: ";
|
|
162489
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
162490
|
+
const answer = String(await deps.ask(question)).trim();
|
|
162491
|
+
if (!answer || /^(n|no|skip)$/i.test(answer)) return void 0;
|
|
162492
|
+
if (isOwnAddressText(answer)) return answer;
|
|
162493
|
+
deps.io.err("That is not a Solana address (32 to 44 letters and digits, as your wallet app shows it). Paste it again, or press Enter to skip.\n");
|
|
162494
|
+
}
|
|
162495
|
+
deps.io.err(`No address recorded. To add one later, run ${CLI2} setup again in a terminal and paste it at this question.
|
|
162496
|
+
`);
|
|
162497
|
+
return void 0;
|
|
162498
|
+
}
|
|
162499
|
+
var ownAddressLine = (list) => ` own address ${list.join(", ")}: your agent sends money back to you there without asking each time`;
|
|
162500
|
+
function recordOwnAddress(home, address5, deps) {
|
|
162501
|
+
try {
|
|
162502
|
+
const { ownAddresses, dropped } = addOwnAddress({ home, address: address5 }, setupDependencies(deps));
|
|
162503
|
+
return [
|
|
162504
|
+
ownAddressLine(ownAddresses),
|
|
162505
|
+
...dropped.length ? [` note config.json keeps ${MAX_OWN_ADDRESSES} own addresses: the oldest (${dropped.join(", ")}) now ask before each send`] : []
|
|
162506
|
+
];
|
|
162507
|
+
} catch (error) {
|
|
162508
|
+
const why = /^setup_own_address_[a-z_]+: /.test(String(error?.message)) ? error.message : "setup_own_address_unsaved: config.json could not be written";
|
|
162509
|
+
return [` note your own address was not saved: ${why}`];
|
|
162510
|
+
}
|
|
162511
|
+
}
|
|
162408
162512
|
async function offerFundNow(deps, { tor }) {
|
|
162409
162513
|
const io = deps.io;
|
|
162410
162514
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
162411
162515
|
const answer = String(await deps.ask("Fund and shield now? Amount in USDC (Enter to skip): ")).trim();
|
|
162412
162516
|
if (!answer || /^(n|no|skip)$/i.test(answer)) break;
|
|
162413
162517
|
const atomic4 = usdcToAtomic(answer);
|
|
162414
|
-
if (!atomic4 || BigInt(atomic4)
|
|
162415
|
-
io.err(atomic4 ? "
|
|
162518
|
+
if (!atomic4 || BigInt(atomic4) < PAY_ME_MIN_ATOMIC) {
|
|
162519
|
+
io.err(atomic4 ? "The smallest amount is 0.01 USDC. Type an amount like 2 or 0.05, or press Enter (or n) to skip.\n" : "Type an amount of USDC, like 2 or 0.05, or press Enter (or n) to skip.\n");
|
|
162416
162520
|
continue;
|
|
162417
162521
|
}
|
|
162418
162522
|
const argv2 = fundArgvOf(usdcFlagText(atomic4));
|
|
@@ -162423,7 +162527,7 @@ async function offerFundNow(deps, { tor }) {
|
|
|
162423
162527
|
}
|
|
162424
162528
|
return;
|
|
162425
162529
|
}
|
|
162426
|
-
io.out(`Not funded now. When you are ready,
|
|
162530
|
+
io.out(`Not funded now. When you are ready, run ${fundCommandText(tor)} (any amount from 0.01 USDC), or ask your agent to add funds.
|
|
162427
162531
|
`);
|
|
162428
162532
|
}
|
|
162429
162533
|
function setupDependencies(deps) {
|
|
@@ -162568,7 +162672,7 @@ function setupArgvOf(values) {
|
|
|
162568
162672
|
const usdcNames = new Set(COMMAND_BY_NAME.get("setup").flags.filter((spec) => spec.usdc).map((spec) => spec.name));
|
|
162569
162673
|
const argv2 = [];
|
|
162570
162674
|
for (const [name, value] of values) {
|
|
162571
|
-
if (typeof name !== "string" || !name.startsWith("--")) continue;
|
|
162675
|
+
if (typeof name !== "string" || !name.startsWith("--") || name === "--own-address") continue;
|
|
162572
162676
|
if (value === true) argv2.push(name);
|
|
162573
162677
|
else for (const each of Array.isArray(value) ? value : [value]) argv2.push(name, usdcNames.has(name) ? usdcFlagText(String(each)) : String(each));
|
|
162574
162678
|
}
|
|
@@ -162593,21 +162697,33 @@ async function runSetupCommand(values, deps) {
|
|
|
162593
162697
|
const home = setupHome(deps.env);
|
|
162594
162698
|
const interactive = !values.has("--yes");
|
|
162595
162699
|
const torRunRecords = !values.has("--prefer-tor") && !values.has("--no-tor") && childRunProxy(deps.env).args[0] === "--tor";
|
|
162700
|
+
const terminal = deps.stdinIsTTY() && deps.stdoutIsTTY?.() === true;
|
|
162701
|
+
if (values.has("--own-address") && !terminal) {
|
|
162702
|
+
throw new PublicFailure(`setup_own_address_needs_terminal: your own address lets your agent send money to it without asking, so setup takes it only when you type or paste it in your own terminal (this run has none: a script, a pipe, or an agent's tool); nothing was changed. Run ${oneTimeCommandLine("setup", deps.walletVersion().npm)} in a terminal and paste the address at its question`);
|
|
162703
|
+
}
|
|
162704
|
+
if (values.has("--own-address") && !isOwnAddressText(values.get("--own-address"))) {
|
|
162705
|
+
throw new UsageError(`--own-address takes one Solana address (32 to 44 letters and digits, as your wallet app shows it)${NOT_SHOWN}`, COMMAND_BY_NAME.get("setup"));
|
|
162706
|
+
}
|
|
162596
162707
|
if (interactive && !deps.stdinIsTTY()) {
|
|
162597
162708
|
const line = ["setup", "--yes", ...setupArgvOf(values), ...childRunProxy(deps.env).args].map(shellWord).join(" ");
|
|
162598
162709
|
throw new UsageError(
|
|
162599
|
-
`setup asks its questions in a terminal; in a script or a pipe pass --yes: ${oneTimeCommandLine(line, deps.walletVersion().npm)} (add any of --max-payment, --max-session, --max-cumulative, --prefer-tor, --private-inference)`,
|
|
162710
|
+
`setup asks its questions in a terminal; in a script or a pipe pass --yes: ${oneTimeCommandLine(line, deps.walletVersion().npm)} (add any of --max-payment, --max-session, --max-cumulative, --prefer-tor, --private-inference; your own wallet address is asked only in a terminal)`,
|
|
162600
162711
|
COMMAND_BY_NAME.get("setup")
|
|
162601
162712
|
);
|
|
162602
162713
|
}
|
|
162714
|
+
let ownAddress = values.get("--own-address");
|
|
162603
162715
|
const old = setupConfigOf(home);
|
|
162604
162716
|
const behindTor = (wanted) => wanted && !values.has("--no-tor") && !inProxiedRun(deps.env);
|
|
162605
162717
|
if (!interactive && behindTor(values.has("--prefer-tor") || values.has("--private-inference") || old?.tor === true)) {
|
|
162606
|
-
|
|
162718
|
+
await setupBehindTor(setupArgvOf(values), deps);
|
|
162719
|
+
if (ownAddress) io.out(`${recordOwnAddress(home, ownAddress, deps).join("\n")}
|
|
162720
|
+
`);
|
|
162721
|
+
return void 0;
|
|
162607
162722
|
}
|
|
162608
162723
|
const missing = missingPieces(home, old);
|
|
162609
162724
|
const npmVersion = deps.walletVersion().npm;
|
|
162610
162725
|
const introduced = values.has("--yes") && inProxiedRun(deps.env);
|
|
162726
|
+
const asksOwnFirst = interactive && Boolean(old) && terminal && !ownAddress;
|
|
162611
162727
|
io.out([
|
|
162612
162728
|
...introduced ? [] : [
|
|
162613
162729
|
"Shinjuku Shield: a self-custody wallet that pays x402 URLs privately from a shielded USDC balance.",
|
|
@@ -162615,7 +162731,7 @@ async function runSetupCommand(values, deps) {
|
|
|
162615
162731
|
`An agent host then starts it with one command: npx -y --no-audit --no-fund ${npxPackageWord(npmVersion)} mcp`,
|
|
162616
162732
|
""
|
|
162617
162733
|
],
|
|
162618
|
-
old ? `Status: ${missing.includes("pool-retired") ? `set up before for a retired pool: ${retiredPoolText(old.pool, npmVersion).split("; run ")[0]}. This run moves config.json to the new pool and makes its wallet` : missing.length ? `set up before; missing now: ${missing.join(", ")}` : "set up; every piece is checked again"} (home ${home}).` : `Home: ${home}`,
|
|
162734
|
+
old ? `Status: ${missing.includes("pool-retired") ? `set up before for a retired pool: ${retiredPoolText(old.pool, npmVersion).split("; run ")[0]}. This run moves config.json to the new pool and makes its wallet` : missing.length ? `set up before; missing now: ${missing.join(", ")}` : asksOwnFirst ? "set up" : "set up; every piece is checked again"} (home ${home}).` : `Home: ${home}`,
|
|
162619
162735
|
""
|
|
162620
162736
|
].join("\n"));
|
|
162621
162737
|
const options = {
|
|
@@ -162646,6 +162762,26 @@ async function runSetupCommand(values, deps) {
|
|
|
162646
162762
|
const answer = String(await deps.ask(`Set your LLM to private inference now? ${PRIVATE_INFERENCE_WHY} [y/N] `)).trim();
|
|
162647
162763
|
privateInference = /^y(es)?$/i.test(answer);
|
|
162648
162764
|
}
|
|
162765
|
+
if (!ownAddress && terminal) ownAddress = await askOwnAddress(deps);
|
|
162766
|
+
} else if (asksOwnFirst) {
|
|
162767
|
+
ownAddress = await askOwnAddress(deps, old.unshieldTo ?? []);
|
|
162768
|
+
if (!ownAddress && !missing.length) io.out("Every piece of the setup is checked again now.\n");
|
|
162769
|
+
}
|
|
162770
|
+
if (old && ownAddress && !missing.length && !setupArgvOf(values).length && !torRunRecords) {
|
|
162771
|
+
let saved;
|
|
162772
|
+
try {
|
|
162773
|
+
saved = addOwnAddress({ home, address: ownAddress }, setupDependencies(deps));
|
|
162774
|
+
} catch (error) {
|
|
162775
|
+
if (/^setup_own_address_[a-z_]+: /.test(String(error?.message))) throw new PublicFailure(error.message);
|
|
162776
|
+
throw error;
|
|
162777
|
+
}
|
|
162778
|
+
io.out([
|
|
162779
|
+
`Saved: ${ownAddress} is your own address now, so your agent sends money back to you there without asking each time (no restart of your agent app needed).`,
|
|
162780
|
+
...saved.dropped.length ? [`config.json keeps ${MAX_OWN_ADDRESSES} own addresses: the oldest (${saved.dropped.join(", ")}) now ask before each send.`] : [],
|
|
162781
|
+
"Nothing else changed. To check every piece of the setup again, run setup again and press Enter at the address question.",
|
|
162782
|
+
""
|
|
162783
|
+
].join("\n"));
|
|
162784
|
+
return void 0;
|
|
162649
162785
|
}
|
|
162650
162786
|
const inference = inferenceRecordOf(old, privateInference);
|
|
162651
162787
|
if (privateInference === true && (options.tor !== true || torRunRecords) && old?.tor !== true) {
|
|
@@ -162663,6 +162799,9 @@ async function runSetupCommand(values, deps) {
|
|
|
162663
162799
|
...privateInference === true && !values.has("--private-inference") ? ["--private-inference"] : []
|
|
162664
162800
|
];
|
|
162665
162801
|
await setupBehindTor(["--yes", ...answers, ...setupArgvOf(values)], deps);
|
|
162802
|
+
if (ownAddress) io.out(`${recordOwnAddress(home, ownAddress, deps).join("\n")}
|
|
162803
|
+
|
|
162804
|
+
`);
|
|
162666
162805
|
await offerFundNow(deps, { tor: setupConfigOf(home)?.tor === true });
|
|
162667
162806
|
return void 0;
|
|
162668
162807
|
}
|
|
@@ -162685,6 +162824,7 @@ Copy it to two offline places now; it is the only way to restore this wallet.
|
|
|
162685
162824
|
if (/^(setup_[a-z_]+|secret_file_utf16): /.test(String(error?.message))) throw new PublicFailure(error.message);
|
|
162686
162825
|
throw error;
|
|
162687
162826
|
}
|
|
162827
|
+
const own = ownAddress ? recordOwnAddress(home, ownAddress, deps) : summary.ownAddresses?.length ? [ownAddressLine(summary.ownAddresses)] : [];
|
|
162688
162828
|
const lines = [
|
|
162689
162829
|
"",
|
|
162690
162830
|
"Shinjuku Shield is set up.",
|
|
@@ -162693,7 +162833,8 @@ Copy it to two offline places now; it is the only way to restore this wallet.
|
|
|
162693
162833
|
` passphrase ${summary.passphraseFile}${summary.passphraseGenerated ? " (a new random passphrase; only you can read the file; it is never printed)" : ""}`,
|
|
162694
162834
|
` proof tools ${summary.proofTools.folder} (${summary.proofTools.downloaded ? `${summary.proofTools.downloaded} files downloaded, every hash checked` : "already here, every hash checked"})`,
|
|
162695
162835
|
// The setup warm ended well (setup/setupWarm.mjs); nothing is said when it did not.
|
|
162696
|
-
...summary.firstBalanceReady ? [" balance prepared during setup: your first balance after a deposit shows sooner"] : []
|
|
162836
|
+
...summary.firstBalanceReady ? [" balance prepared during setup: your first balance after a deposit shows sooner"] : [],
|
|
162837
|
+
...own
|
|
162697
162838
|
];
|
|
162698
162839
|
if (summary.wallet.status === "created") {
|
|
162699
162840
|
lines.push(
|
|
@@ -162739,9 +162880,12 @@ ${summary.privateInference === true ? privateInferencePath(config, { apiKey }).t
|
|
|
162739
162880
|
function validateAddFunds(values) {
|
|
162740
162881
|
const route = values.get("--route");
|
|
162741
162882
|
if (!FUNDS_ROUTES.includes(route)) throw new UsageError("--route must be exchange, changenow, or privacy-cash (the value given is not repeated here)");
|
|
162883
|
+
if (BigInt(values.get("--amount")) < PAY_ME_MIN_ATOMIC) {
|
|
162884
|
+
throw new UsageError(`--amount must be at least ${usdcFlagText(PAY_ME_MIN_ATOMIC.toString())} USDC: the facilitator moves no smaller deposit into the pool`);
|
|
162885
|
+
}
|
|
162742
162886
|
const unit = RELAYED_DEPOSIT_UNIT[values.get("--pool")];
|
|
162743
|
-
if (unit && BigInt(values.get("--amount")) % BigInt(unit) !== 0n) {
|
|
162744
|
-
throw new UsageError(`--
|
|
162887
|
+
if (route === "privacy-cash" && unit && BigInt(values.get("--amount")) % BigInt(unit) !== 0n) {
|
|
162888
|
+
throw new UsageError(`--route privacy-cash takes a whole number of USDC (a multiple of ${usdcFlagText(unit)} USDC, like 2): an odd amount singles out your Privacy Cash withdrawal. For an amount with cents (from 0.01 USDC), use --route exchange`);
|
|
162745
162889
|
}
|
|
162746
162890
|
if (values.has("--pockets") && !(/^(0|[1-9][0-9]?)$/.test(values.get("--pockets")) && Number(values.get("--pockets")) <= 20)) {
|
|
162747
162891
|
throw new UsageError("--pockets must be a whole number from 0 to 20");
|
|
@@ -162905,7 +163049,7 @@ var COMMANDS = [
|
|
|
162905
163049
|
env: [],
|
|
162906
163050
|
flags: [
|
|
162907
163051
|
flag2("--route", "<exchange|changenow|privacy-cash>", "where the USDC comes from: an exchange withdrawal, a ChangeNOW swap, or your own wallet through the Privacy Cash crowd", { required: true }),
|
|
162908
|
-
flag2("--amount", "<usdc>", "USDC to add
|
|
163052
|
+
flag2("--amount", "<usdc>", "USDC to add, from 0.01 (2 = 2 USDC, 0.05 = 5 cents); --route privacy-cash takes whole USDC", { required: true, check: "atomic", usdc: true }),
|
|
162909
163053
|
flag2("--pool", "<address>", "the shielded pool", { required: true, check: "pubkey" }),
|
|
162910
163054
|
flag2("--program", "<address>", "the shielded pool program", { required: true, check: "pubkey" }),
|
|
162911
163055
|
flag2("--proof-tools", "<file>", "the public proof-tools manifest (the deposit, the pocket fill, and the balance read use it)", { required: true }),
|
|
@@ -162930,6 +163074,7 @@ var COMMANDS = [
|
|
|
162930
163074
|
],
|
|
162931
163075
|
examples: [
|
|
162932
163076
|
`${CLI2} add-funds --route exchange --amount 2 ${FUNDS_BASE}`,
|
|
163077
|
+
`${CLI2} add-funds --route exchange --amount 0.05 ${FUNDS_BASE}`,
|
|
162933
163078
|
`${CLI2} add-funds --route changenow --amount 3 ${FUNDS_BASE}`,
|
|
162934
163079
|
`${CLI2} add-funds --route exchange --amount 2 --split 2 ${FUNDS_BASE}`,
|
|
162935
163080
|
`${CLI2} add-funds --route exchange --amount 5 --split auto ${FUNDS_BASE}`,
|
|
@@ -162938,14 +163083,15 @@ var COMMANDS = [
|
|
|
162938
163083
|
notes: [
|
|
162939
163084
|
"One command instead of six. It runs the steps you would run by hand, in order, and waits between them by itself: deposit --relay (it records a one-time address of this wallet, then proves the deposit once that address holds the amount), deposit --relay --submit (our relayer moves it into the pool and pays every fee), pocket fill (only with --pockets 1 or more; after the dwell: 3 other pool events after your deposit, or a 1-minute cap, whichever comes first; a balance --refresh right before the fill reads the pool's history first), and balance --refresh. The privacy-cash route first runs privacy-cash deposit, waits its 24-hour hold, and only then records the one-time address and runs privacy-cash withdraw.",
|
|
162940
163085
|
'Stages, as it prints them: address > funding > deposit > balance > ready, with dwell > pocket before balance when --pockets is 1 or more (privacy-cash: crowd-deposit > crowd-hold > address > crowd-withdraw > funding > ...). Each wait says what it waits for and when it tries again; the last line says "ready" with your balance and what the route still shows. The start line, the funding instructions, and every status line name what the route shows, and to whom. The balance you hold already pays during any wait: add-funds never holds the wallet while it waits.',
|
|
162941
|
-
"exchange: withdraw exactly --amount USDC on Solana (SPL) from an exchange to the one-time address it prints. The exchange knows its customer; the chain shows only an exchange paying a new address. Minutes, then the dwell (at most about a minute).",
|
|
163086
|
+
"exchange: withdraw exactly --amount USDC on Solana (SPL) from an exchange to the one-time address it prints (or scan its QR code with a phone wallet). The exchange knows its customer; the chain shows only an exchange paying a new address. Minutes, then the dwell (at most about a minute).",
|
|
163087
|
+
"--amount takes any amount from 0.01 USDC, as the MCP tool wallet_add_funds. A whole number of USDC is the most private: many deposits have the same size. An amount with cents goes in as one deposit, and its size is easier to pick out on chain.",
|
|
162942
163088
|
"changenow: a FIXED-rate ChangeNOW swap that delivers exactly --amount USDC on Solana to that address, paid with Monero (best: it hides the sender) or BTC or ETH. ChangeNOW sees the amount and the address. Minutes, then the dwell.",
|
|
162943
163089
|
"privacy-cash: your own wallet (--from-key-file, with about 0.002 SOL) pays --crowd-amount into Privacy Cash; at least 24 hours (add-funds waits by this machine's clock; the withdrawal also checks the chain's time) and 10 real deposits later, Privacy Cash pays the one-time address, so the chain shows no transfer from your wallet to it (about a day; Privacy Cash's server still sees both steps with --via sdk). --crowd-amount is whole USDC and must cover --amount plus Privacy Cash's fee (0.35% plus about 0.72 USDC on 2026-09-30); with --via sdk the change left there must be 10 USDC or more, so a 2 USDC deposit takes --crowd-amount 13. Without --crowd-amount the withdrawal spends notes the key holds there already; the one-time address is read only 24 hours after the later of the newest Privacy Cash deposit this wallet file records (any key) and the moment this run chose the privacy-cash route; a deposit made outside this wallet file is covered only by that second rule. This route's order in add-funds (nothing reads the one-time address before the hold has passed; a random 30 to 120 minutes after a settle-only read) is checked by a run with no money, not yet live end to end.",
|
|
162944
163090
|
"Until any USDC moved (the one-time address is not funded, and no Privacy Cash deposit was made), a run may change its route: rerun it with the other --route (and that route's flags); the one-time address stays the same. If more than --amount reaches the address, the deposit takes --amount and the rest stays at the address: add-funds and funds-status say how much, and what taking it back shows.",
|
|
162945
163091
|
"Ctrl-C, a closed terminal, or a reboot loses nothing: every step keeps its own record. Rerun this same command and it continues at the stage where it stopped. To keep it running in the background: nohup <this command> > add-funds.log 2>&1 & (Windows: Start-Process). funds-status shows the stage from any terminal, and whether add-funds still runs.",
|
|
162946
163092
|
"Back up (backup-export) when it prints the one-time address and again when it says ready: add-funds makes no backup itself. A restore from the recovery text alone still finds the deposit once it landed (recover), and USDC that waits at the one-time address (deposit-scan).",
|
|
162947
163093
|
"A pocket fill moves your own money into your own pocket, so it takes none of the payment budget init set (--max-payment, --max-cumulative). Each payment from a pocket to a seller takes that budget, the same as any other payment.",
|
|
162948
|
-
"It changes no rule: the crowd hold, the dwell,
|
|
163094
|
+
"It changes no rule: the crowd hold, the dwell, the deposit amounts, and every refusal are the single commands' own. A refusal that a later run clears (the hold, the crowd count, the dwell, a paused facilitator) is a wait; any other refusal stops it with that command's own line and hint (exit 1), and the rerun continues after your fix. It has no override flag: run the single command (for example privacy-cash withdraw --hold-override) when you choose to give up a wait.",
|
|
162949
163095
|
"--tor (or --proxy): each step runs as its own Tor run, as if you typed it: a new circuit and its own Tor check. With --tor, --service may be the facilitator's http://<v3 onion>/ origin.",
|
|
162950
163096
|
`--history-rpc: the balance --refresh and pocket fill steps (and the dwell check) read the pool's public history from it (${CLI2} help balance says what it sees); the deposit and Privacy Cash steps never get it. Without it, those two steps read from the history proxy this wallet pins for the pool (its onion with --tor, else https on the facilitator's pay host; --history-rpc own keeps them on your own RPC). add-funds does not keep it: give it again on each rerun. It never falls back to your own RPC: a failed source fails the step with history_rpc_failed, and add-funds handles that as it handles the step's other refusals.`,
|
|
162951
163097
|
"In a terminal it shows one line per step and ends with a short summary (ready with your balance, or where it stopped and what to do); the wallet's own progress lines (Tor, the RPC relay, the pool history, the memo reads) show only with --verbose, and every warning or failure shows always. With --json, or when its output goes to a file or a program, it ends with the status as JSON, as funds-status prints it, and shows every progress line. While it waits for the USDC it checks the one-time address every 20 s for the first 5 minutes, then every 2 minutes.",
|
|
@@ -163562,6 +163708,7 @@ var COMMANDS = [
|
|
|
163562
163708
|
bool2("--prefer-tor", "record Tor for mcp: it then runs behind Tor (needs Tor with HTTPTunnelPort 127.0.0.1:9080); mcp --no-tor skips it for one run. Setup itself then runs behind Tor too. setup --tor does the same: it runs setup behind Tor and records Tor for mcp"),
|
|
163563
163709
|
bool2("--no-tor", "run this setup without Tor although Tor is recorded or asked for (the facilitator then sees this machine's IP address download the release and the proof tools); config.json still records Tor. With --tor it only stops --tor from recording Tor (the run itself still goes over Tor)"),
|
|
163564
163710
|
bool2("--private-inference", 'answer yes to "Set your LLM to private inference now?": your agent buys AI answers from the AI provider, paid from your private balance over Tor. Records inference.enabled and Tor (as --prefer-tor) in config.json, and prints the path to the first private call. Without it, --yes keeps what config.json records'),
|
|
163711
|
+
flag2("--own-address", "<address>", `optional, in your own terminal only (the same as the answer to setup's address question): your own wallet address (Phantom, Solflare, an exchange's deposit address), for sending money back to yourself: the MCP sends to it without asking each time (as mcp --unshield-to), also in an agent app that cannot show a question. Not this wallet's own address. Refused in a script, a pipe, or an agent's tool (no terminal), also with --yes: an agent must never approve an address. A rerun adds it to the ones config.json records (at most ${MAX_OWN_ADDRESSES})`),
|
|
163565
163712
|
flag2("--passphrase-file", "<file>", "your own passphrase file (8 or more characters); default: setup writes a new random passphrase to <home>/passphrase.txt, readable by you alone. Needed for a wallet that exists already"),
|
|
163566
163713
|
flag2("--facilitator", "<https origin>", `the facilitator whose release, pool, and proof tools setup uses; default ${GUIDE.facilitator}`, { check: "origin" }),
|
|
163567
163714
|
flag2("--add-to", "<claude-code|claude-desktop|cursor>", `also add the server (npx -y --no-audit --no-fund ${NPX_AT_VERSION} mcp: the host starts this npm version; a wallet not installed from npm writes shinjuku-shield without a version) to this agent host's config; repeat it for more. Without it, setup prints the configs`, { repeat: true }),
|
|
@@ -163574,7 +163721,7 @@ var COMMANDS = [
|
|
|
163574
163721
|
`${CLI2} setup --yes --private-inference`
|
|
163575
163722
|
],
|
|
163576
163723
|
notes: [
|
|
163577
|
-
`npx -y --no-audit --no-fund ${COMMAND_AT_VERSION} setup runs the same command. Without --yes
|
|
163724
|
+
`npx -y --no-audit --no-fund ${COMMAND_AT_VERSION} setup runs the same command. Without --yes a first setup asks in the terminal: Tor, private inference, and your own wallet address (Enter skips it). A rerun in a terminal asks only for your own wallet address: on a complete setup an address given there is saved and nothing else runs; Enter checks every piece again.`,
|
|
163578
163725
|
`When Tor is recorded or asked for (a yes, --tor, --prefer-tor, or --private-inference), setup itself runs behind Tor: the release, the proof-tool downloads, and the RPC requests go over Tor, so the facilitator never sees this machine's IP address make the wallet. config.json then records Tor for mcp ("tor": true), so the MCP runs behind Tor too. Tor must run first (torrc: HTTPTunnelPort 127.0.0.1:9080); --no-tor runs it without Tor.`,
|
|
163579
163726
|
`Private inference (a yes, or --private-inference): ${PRIVATE_INFERENCE_WHY} Setup records Tor, then prints five steps with real commands: add-funds (it shields the USDC), the first call (echo "Say hello" | ${CLI2} infer -, about 0.0011 USDC; no flags: config.json gives the wallet, the caps, and Tor), infer start for an agent app (the local AI server in the background: base_url and api key), and an MCP restart for inference_chat (and inference_server, which starts the same local AI server from the agent). In a terminal it then offers to run add-funds; it never pays an inference call.`,
|
|
163580
163727
|
"The wallet home is SHIELDED_WALLET_HOME, default ~/.carbon-shielded-wallet (every command of this CLI uses it). setup writes there: config.json, passphrase.txt (mode 0600; on Windows an access list of your account alone), the wallet (<pool>/wallet.json, made by init with the production pool, program, network, and USDC), a recovery file recovery-<time>.txt, and proof-tools/<dir>/.",
|
|
@@ -164216,7 +164363,7 @@ function overviewText() {
|
|
|
164216
164363
|
"",
|
|
164217
164364
|
"Exit codes: 0 done; 1 the command ran and failed (one-line reason); 2 the command line is wrong (shows a working example).",
|
|
164218
164365
|
`Start here: ${oneTimeCommandLine("setup", npm)} (or ${CLI2} setup), then the agent host runs npx -y --no-audit --no-fund ${npxPackageWord(npm)} mcp, and your agent adds funds with wallet_add_funds (from 0.01 USDC).`,
|
|
164219
|
-
`Manual path, without setup: ${CLI2} help init, then ${CLI2} help add-funds (
|
|
164366
|
+
`Manual path, without setup: ${CLI2} help init, then ${CLI2} help add-funds (from 0.01 USDC).`,
|
|
164220
164367
|
`Lost the wallet file? ${CLI2} help restore (from the init recovery file)`,
|
|
164221
164368
|
""
|
|
164222
164369
|
].join("\n");
|
|
@@ -164329,7 +164476,7 @@ function checkValue(spec, value) {
|
|
|
164329
164476
|
if (spec.check === "pubkey") {
|
|
164330
164477
|
let canonical5 = false;
|
|
164331
164478
|
try {
|
|
164332
|
-
canonical5 = new
|
|
164479
|
+
canonical5 = new import_web3139.PublicKey(value).toBase58() === value;
|
|
164333
164480
|
} catch {
|
|
164334
164481
|
canonical5 = false;
|
|
164335
164482
|
}
|
|
@@ -164492,7 +164639,7 @@ var UNSHIELD_MADE_ID = /* @__PURE__ */ Symbol("unshield id made here");
|
|
|
164492
164639
|
var unshieldRefusal = (reason, text3) => new PublicFailure(`p03_unshield_${reason}: ${text3}`);
|
|
164493
164640
|
function walletOwnAddress(store) {
|
|
164494
164641
|
try {
|
|
164495
|
-
return
|
|
164642
|
+
return import_web3139.Keypair.fromSecretKey(Uint8Array.from(store.state.solanaSecretKey), { skipValidation: true }).publicKey;
|
|
164496
164643
|
} catch {
|
|
164497
164644
|
return void 0;
|
|
164498
164645
|
}
|
|
@@ -164518,13 +164665,13 @@ async function runUnshieldCommand(args, values, deps, io) {
|
|
|
164518
164665
|
};
|
|
164519
164666
|
let store;
|
|
164520
164667
|
const openStore = () => store ??= (deps.openWalletStore ?? openWalletStore)(resolve39(values.get("--wallet")), payerPassphrase(values, deps));
|
|
164521
|
-
const owner = values.has("--recipient-owner") ? new
|
|
164668
|
+
const owner = values.has("--recipient-owner") ? new import_web3139.PublicKey(values.get("--recipient-owner")) : new import_web3139.PublicKey(values.get("--to"));
|
|
164522
164669
|
if (!values.has("--recipient-owner")) {
|
|
164523
164670
|
const wallet = openStore();
|
|
164524
164671
|
if (walletOwnAddress(wallet)?.equals(owner)) {
|
|
164525
164672
|
throw unshieldRefusal("recipient_owner_is_deposit_key", `--to is this wallet's own public address (its own key): an exit there would show on chain that the money is yours, so this private wallet does not send there; nothing was sent. Send to another address (best: one that never sent USDC into this wallet), like ${UNSHIELD_EXAMPLE}`);
|
|
164526
164673
|
}
|
|
164527
|
-
const mint = new
|
|
164674
|
+
const mint = new import_web3139.PublicKey(wallet.state.asset);
|
|
164528
164675
|
const check = deps.unshieldRecipientHoldsUsdc ?? ((input) => recipientHoldsUsdc({ ...input, connection: connectRelay(spendRpcUrl(values, deps), "finalized") }));
|
|
164529
164676
|
let holds;
|
|
164530
164677
|
try {
|
|
@@ -165137,19 +165284,22 @@ var RELAYED_DEPOSIT_UNIT = Object.freeze({
|
|
|
165137
165284
|
CDtxyRjCUs2pu7t3U9TwtpnZwyxBFZ4dKXvb4RCmXHXv: "1000000"
|
|
165138
165285
|
});
|
|
165139
165286
|
async function runDeposit(args, values, deps) {
|
|
165140
|
-
const
|
|
165287
|
+
const poolUnit = RELAYED_DEPOSIT_UNIT[values.get("--pool")];
|
|
165288
|
+
const amount = String(values.get("--amount") ?? "");
|
|
165289
|
+
const offUnit = poolUnit !== void 0 && /^[0-9]{1,20}$/.test(amount) && BigInt(amount) % BigInt(poolUnit) !== 0n;
|
|
165290
|
+
const unit = values.has("--relay") && !values.has("--pool-denomination") && !offUnit ? poolUnit : void 0;
|
|
165141
165291
|
try {
|
|
165142
165292
|
await deps.researchWalletMain(["deposit", ...args, ...unit ? ["--pool-denomination", unit] : []]);
|
|
165143
165293
|
} catch (error) {
|
|
165144
165294
|
if (error?.message !== "p03_deposit_relay_fund_one_time_address") throw error;
|
|
165145
165295
|
let address5;
|
|
165146
165296
|
try {
|
|
165147
|
-
address5 = new
|
|
165297
|
+
address5 = new import_web3139.PublicKey(error.oneTimeAddress).toBase58();
|
|
165148
165298
|
} catch {
|
|
165149
165299
|
throw error;
|
|
165150
165300
|
}
|
|
165151
165301
|
const decimals = Number(error.decimals ?? 6);
|
|
165152
|
-
const asset = error.asset === GUIDE.mint ? "USDC" : `tokens of mint ${new
|
|
165302
|
+
const asset = error.asset === GUIDE.mint ? "USDC" : `tokens of mint ${new import_web3139.PublicKey(error.asset).toBase58()}`;
|
|
165153
165303
|
const held = BigInt(error.heldAtomic);
|
|
165154
165304
|
const unitAtomic = BigInt(values.get("--pool-denomination") ?? unit ?? "1");
|
|
165155
165305
|
const usable = held / unitAtomic * unitAtomic;
|
|
@@ -165321,6 +165471,12 @@ async function runBalance(args, values, deps, io) {
|
|
|
165321
165471
|
source: values.has("--refresh") ? "refresh" : "local",
|
|
165322
165472
|
now: deps.now()
|
|
165323
165473
|
});
|
|
165474
|
+
const refreshArgs = values.has("--refresh") || report.status === "current" || report.status === "empty" ? void 0 : homeRefreshArgs(store, deps);
|
|
165475
|
+
if (refreshArgs) {
|
|
165476
|
+
io.err("reading your private balance from the chain\n");
|
|
165477
|
+
const shownFlags = ["--json", "--verbose"].filter((name) => values.has(name));
|
|
165478
|
+
if (await runShinjukuWallet(["balance", ...refreshArgs, ...shownFlags], deps) === 0) return;
|
|
165479
|
+
}
|
|
165324
165480
|
const shown = earlierDeposits.map((outcome) => ({
|
|
165325
165481
|
pool: outcome.pool,
|
|
165326
165482
|
state: outcome.state,
|
|
@@ -165351,6 +165507,16 @@ async function runBalance(args, values, deps, io) {
|
|
|
165351
165507
|
io.out(`${JSON.stringify({ ...report, ...shown.length ? { earlierDeposits: shown } : {}, ...unfinished2.length ? { unfinishedUnshields: unfinished2 } : {} }, null, 2)}
|
|
165352
165508
|
`);
|
|
165353
165509
|
}
|
|
165510
|
+
function homeRefreshArgs(store, deps) {
|
|
165511
|
+
let config;
|
|
165512
|
+
try {
|
|
165513
|
+
config = readSetupConfig(setupHome(deps.env));
|
|
165514
|
+
} catch {
|
|
165515
|
+
return void 0;
|
|
165516
|
+
}
|
|
165517
|
+
if (config?.pool !== store.state.pool || !config.program || !config.proofTools || !config.memoService) return void 0;
|
|
165518
|
+
return ["--pool", config.pool, "--refresh", "--program", config.program, "--proof-tools", config.proofTools, "--service", config.memoService, "--fresh"];
|
|
165519
|
+
}
|
|
165354
165520
|
async function adoptOneTimeForBalance({ store, values, deps, io }) {
|
|
165355
165521
|
try {
|
|
165356
165522
|
const home = setupHome(deps.env);
|