shinjuku-shielded 0.3.153 → 0.3.154

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 CHANGED
@@ -6,19 +6,19 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
6
6
  command runs a local MCP server (stdio) for your agent. Your keys never
7
7
  leave your machine.
8
8
 
9
- This is version 0.3.153. The npm packages `shinjuku-shield` and
9
+ This is version 0.3.154. The npm packages `shinjuku-shield` and
10
10
  `shinjuku-shielded` hold the same files. The command is `shinjuku`.
11
11
 
12
12
  ## Set up
13
13
 
14
14
  ```sh
15
- npm install -g shinjuku@0.3.153
15
+ npm install -g shinjuku@0.3.154
16
16
  shinjuku setup
17
17
  ```
18
18
 
19
19
  Type the two lines as they are. `npx install shinjuku` does not work: npx
20
20
  reads `install` as the name of another npm package. To set up without
21
- installing, type `npx shinjuku@0.3.153 setup`.
21
+ installing, type `npx shinjuku@0.3.154 setup`.
22
22
 
23
23
  Setup makes the wallet on this machine, a private passphrase file, and the
24
24
  checked proof tools (about 191 MB), and writes `config.json`. It also writes
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
36
36
  Claude Code:
37
37
 
38
38
  ```sh
39
- claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.153 mcp
39
+ claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.154 mcp
40
40
  ```
41
41
 
42
42
  Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
43
43
 
44
44
  ```json
45
- { "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.153", "mcp"] } } }
45
+ { "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.154", "mcp"] } } }
46
46
  ```
47
47
 
48
48
  On native Windows, if the host cannot find `npx`, use `"command": "cmd"` and
@@ -55,7 +55,7 @@ Codex (the Codex app and Codex CLI read the same file, `~/.codex/config.toml`):
55
55
  ```toml
56
56
  [mcp_servers.shinjuku]
57
57
  command = "npx"
58
- args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.153", "mcp"]
58
+ args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.154", "mcp"]
59
59
  startup_timeout_sec = 120
60
60
  tool_timeout_sec = 300
61
61
  ```
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": "d446c36da9b526aea16cf685fb7b1532542f1eea13d0f2acabca373711bace8f",
5
- "bytes": 9048030,
6
- "sourceCommit": "9c091872009ec4e8a82ff9d5540fe00015cc93d1",
4
+ "sha256": "706b774ac8ab6d671a81f7aa269e2a1d1e222d60f545ddde48945fbfdc8b0bcd",
5
+ "bytes": 9052676,
6
+ "sourceCommit": "7b23397db24686bbab6bd45734cb9560c914981a",
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",
@@ -1038,5 +1038,5 @@
1038
1038
  "version": "1.8.0"
1039
1039
  }
1040
1040
  ],
1041
- "publishedAt": "2026-11-03T05:08:33.860Z"
1041
+ "publishedAt": "2026-11-03T05:31:30.536Z"
1042
1042
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.153",
3
+ "version": "0.3.154",
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": "d446c36d",
7
- "shinjukuSha256": "d446c36da9b526aea16cf685fb7b1532542f1eea13d0f2acabca373711bace8f",
6
+ "shinjukuRelease": "706b774a",
7
+ "shinjukuSha256": "706b774ac8ab6d671a81f7aa269e2a1d1e222d60f545ddde48945fbfdc8b0bcd",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
@@ -17386,7 +17386,7 @@ var require_receiver = __commonJS({
17386
17386
  var require_sender = __commonJS({
17387
17387
  "node_modules/ws/lib/sender.js"(exports, module) {
17388
17388
  "use strict";
17389
- var { Duplex } = __require("stream");
17389
+ var { Duplex: Duplex2 } = __require("stream");
17390
17390
  var { randomFillSync } = __require("crypto");
17391
17391
  var {
17392
17392
  types: { isUint8Array }
@@ -18264,10 +18264,10 @@ var require_websocket = __commonJS({
18264
18264
  var EventEmitter = __require("events");
18265
18265
  var https = __require("https");
18266
18266
  var http3 = __require("http");
18267
- var net2 = __require("net");
18267
+ var net3 = __require("net");
18268
18268
  var tls = __require("tls");
18269
18269
  var { randomBytes: randomBytes33, createHash: createHash34 } = __require("crypto");
18270
- var { Duplex, Readable } = __require("stream");
18270
+ var { Duplex: Duplex2, Readable } = __require("stream");
18271
18271
  var { URL: URL4 } = __require("url");
18272
18272
  var PerMessageDeflate = require_permessage_deflate();
18273
18273
  var Receiver = require_receiver();
@@ -19008,12 +19008,12 @@ var require_websocket = __commonJS({
19008
19008
  }
19009
19009
  function netConnect(options) {
19010
19010
  options.path = options.socketPath;
19011
- return net2.connect(options);
19011
+ return net3.connect(options);
19012
19012
  }
19013
19013
  function tlsConnect(options) {
19014
19014
  options.path = void 0;
19015
19015
  if (!options.servername && options.servername !== "") {
19016
- options.servername = net2.isIP(options.host) ? "" : options.host;
19016
+ options.servername = net3.isIP(options.host) ? "" : options.host;
19017
19017
  }
19018
19018
  return tls.connect(options);
19019
19019
  }
@@ -19158,7 +19158,7 @@ var require_stream = __commonJS({
19158
19158
  "node_modules/ws/lib/stream.js"(exports, module) {
19159
19159
  "use strict";
19160
19160
  var WebSocket = require_websocket();
19161
- var { Duplex } = __require("stream");
19161
+ var { Duplex: Duplex2 } = __require("stream");
19162
19162
  function emitClose(stream) {
19163
19163
  stream.emit("close");
19164
19164
  }
@@ -19176,7 +19176,7 @@ var require_stream = __commonJS({
19176
19176
  }
19177
19177
  function createWebSocketStream(ws, options) {
19178
19178
  let terminateOnDestroy = true;
19179
- const duplex = new Duplex({
19179
+ const duplex = new Duplex2({
19180
19180
  ...options,
19181
19181
  autoDestroy: false,
19182
19182
  emitClose: false,
@@ -19302,7 +19302,7 @@ var require_websocket_server = __commonJS({
19302
19302
  "use strict";
19303
19303
  var EventEmitter = __require("events");
19304
19304
  var http3 = __require("http");
19305
- var { Duplex } = __require("stream");
19305
+ var { Duplex: Duplex2 } = __require("stream");
19306
19306
  var { createHash: createHash34 } = __require("crypto");
19307
19307
  var extension2 = require_extension();
19308
19308
  var PerMessageDeflate = require_permessage_deflate();
@@ -42866,12 +42866,15 @@ var init_keepAlive = __esm({
42866
42866
  });
42867
42867
 
42868
42868
  // wallet/src/net/tunnelGuard.mjs
42869
- function tunnelClient(Dispatcher, proxyPort) {
42869
+ import net from "node:net";
42870
+ import { Duplex } from "node:stream";
42871
+ function tunnelClient(Dispatcher, proxyPort, proxyHost) {
42870
42872
  const direct = new Dispatcher({ httpProxy: "", httpsProxy: "", noProxy: "*" });
42871
42873
  const closedInRow = /* @__PURE__ */ new Map();
42872
42874
  return {
42873
42875
  async connect(params) {
42874
42876
  const target = String(params?.path ?? "");
42877
+ if (optimisticTarget(target)) return optimisticConnect(params, { proxyHost, proxyPort, closedInRow });
42875
42878
  try {
42876
42879
  const answer = await direct.connect(params);
42877
42880
  closedInRow.delete(target);
@@ -42903,14 +42906,143 @@ function proxyDispatcher(Dispatcher, proxy) {
42903
42906
  noProxy: "",
42904
42907
  keepAliveTimeout: KEEP_ALIVE_MS,
42905
42908
  keepAliveMaxTimeout: KEEP_ALIVE_MS,
42906
- clientFactory: () => tunnelClient(Dispatcher, port)
42909
+ clientFactory: () => tunnelClient(Dispatcher, port, url.hostname)
42910
+ });
42911
+ }
42912
+ function optimisticTarget(target) {
42913
+ return String(process.env[RUN_MARK] ?? "").startsWith("tor ") && /:443$/.test(target);
42914
+ }
42915
+ function tunnelRefused(statusCode) {
42916
+ return Object.assign(new Error(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`), { name: "AbortError", code: "UND_ERR_ABORTED" });
42917
+ }
42918
+ function optimisticConnect(params, { proxyHost, proxyPort, closedInRow }) {
42919
+ const target = String(params.path);
42920
+ const head = `CONNECT ${target} HTTP/1.1\r
42921
+ ${Object.entries(params.headers ?? {}).filter(([name, value2]) => value2 !== void 0 && !/[\r\n]/.test(`${name}${value2}`)).map(([name, value2]) => `${name}: ${value2}\r
42922
+ `).join("")}\r
42923
+ `;
42924
+ const sent = [];
42925
+ let socket;
42926
+ let ready = false;
42927
+ let open4 = false;
42928
+ let reply = Buffer.alloc(0);
42929
+ let pendingReject;
42930
+ const stream = new Duplex({
42931
+ // Backpressure (Codex review): the tunnel socket pauses when this buffer is full and resumes when TLS reads.
42932
+ read() {
42933
+ if (socket && !socket.destroyed && socket.isPaused()) socket.resume();
42934
+ },
42935
+ write(chunk, encoding, done) {
42936
+ if (!open4) sent.push(Buffer.from(chunk, encoding));
42937
+ if (!ready || socket.destroyed) {
42938
+ done();
42939
+ return;
42940
+ }
42941
+ socket.write(chunk, encoding, done);
42942
+ },
42943
+ final(done) {
42944
+ socket?.end();
42945
+ done();
42946
+ },
42947
+ destroy(error, done) {
42948
+ socket?.destroy();
42949
+ done(error);
42950
+ }
42951
+ });
42952
+ stream.on("error", () => {
42953
+ });
42954
+ const abortReason = () => params.signal?.reason ?? Object.assign(new Error("This operation was aborted"), { name: "AbortError", code: "ABORT_ERR" });
42955
+ if (params.signal?.aborted) return Promise.reject(abortReason());
42956
+ const onAbort = () => {
42957
+ if (pendingReject) {
42958
+ const reject = pendingReject;
42959
+ pendingReject = void 0;
42960
+ socket?.destroy();
42961
+ stream.destroy();
42962
+ reject(abortReason());
42963
+ return;
42964
+ }
42965
+ stream.destroy(abortReason());
42966
+ };
42967
+ params.signal?.addEventListener?.("abort", onAbort, { once: true });
42968
+ const dial = (first) => new Promise((resolve39, reject) => {
42969
+ if (first) pendingReject = reject;
42970
+ reply = Buffer.alloc(0);
42971
+ ready = false;
42972
+ socket = net.connect(proxyPort, proxyHost);
42973
+ socket.setNoDelay(true);
42974
+ let connected = false;
42975
+ socket.once("connect", () => {
42976
+ connected = true;
42977
+ socket.write(head);
42978
+ for (const chunk of sent) socket.write(chunk);
42979
+ ready = true;
42980
+ if (first) pendingReject = void 0;
42981
+ resolve39();
42982
+ });
42983
+ socket.on("data", (chunk) => {
42984
+ if (open4) {
42985
+ if (!stream.push(chunk)) socket.pause();
42986
+ return;
42987
+ }
42988
+ reply = Buffer.concat([reply, chunk]);
42989
+ const end = reply.indexOf("\r\n\r\n");
42990
+ if (end < 0) return;
42991
+ const status = Number(/^HTTP\/1\.[01] (\d{3})/.exec(reply.subarray(0, reply.indexOf("\r\n")).toString("latin1"))?.[1] ?? 0);
42992
+ if (status !== 200) {
42993
+ stream.destroy(tunnelRefused(status));
42994
+ return;
42995
+ }
42996
+ open4 = true;
42997
+ sent.length = 0;
42998
+ closedInRow.delete(target);
42999
+ const rest = reply.subarray(end + 4);
43000
+ reply = Buffer.alloc(0);
43001
+ if (rest.length && !stream.push(rest)) socket.pause();
43002
+ });
43003
+ socket.on("error", (error) => {
43004
+ if (!connected) {
43005
+ if (first) {
43006
+ if (pendingReject) {
43007
+ pendingReject = void 0;
43008
+ reject(error);
43009
+ }
43010
+ } else stream.destroy(error);
43011
+ return;
43012
+ }
43013
+ if (open4) stream.destroy(error);
43014
+ });
43015
+ socket.on("close", () => {
43016
+ if (!connected || stream.destroyed) return;
43017
+ if (open4) {
43018
+ stream.push(null);
43019
+ return;
43020
+ }
43021
+ const closed = (closedInRow.get(target) ?? 0) + 1;
43022
+ if (closed < TUNNEL_CLOSED_TRIES) {
43023
+ closedInRow.set(target, closed);
43024
+ dial(false).catch((error) => stream.destroy(error));
43025
+ return;
43026
+ }
43027
+ closedInRow.delete(target);
43028
+ stream.destroy(Object.assign(
43029
+ new Error(`the local proxy closed ${TUNNEL_CLOSED_TRIES} tunnels in a row with no answer`),
43030
+ { code: "ECONNREFUSED", port: proxyPort, tunnelClosed: true }
43031
+ ));
43032
+ });
43033
+ });
43034
+ stream.once("close", () => params.signal?.removeEventListener?.("abort", onAbort));
43035
+ return dial(true).then(() => ({ statusCode: 200, socket: stream, headers: {} }), (error) => {
43036
+ params.signal?.removeEventListener?.("abort", onAbort);
43037
+ throw error;
42907
43038
  });
42908
43039
  }
42909
- var TUNNEL_CLOSED_TRIES;
43040
+ var RUN_MARK, TUNNEL_CLOSED_TRIES;
42910
43041
  var init_tunnelGuard = __esm({
42911
43042
  "wallet/src/net/tunnelGuard.mjs"() {
42912
43043
  "use strict";
42913
43044
  init_keepAlive();
43045
+ RUN_MARK = "SHINJUKU_WALLET_PROXIED";
42914
43046
  TUNNEL_CLOSED_TRIES = 3;
42915
43047
  }
42916
43048
  });
@@ -47239,7 +47371,7 @@ import { spawn } from "node:child_process";
47239
47371
  import { randomBytes as randomBytes5 } from "node:crypto";
47240
47372
  import dns from "node:dns";
47241
47373
  import http from "node:http";
47242
- import net from "node:net";
47374
+ import net2 from "node:net";
47243
47375
  function proxyRefusedConnection(error) {
47244
47376
  if (ownProxyRefused) return true;
47245
47377
  const proxied = process.env[MARK];
@@ -47335,8 +47467,8 @@ function refuseDirectSockets(proxy) {
47335
47467
  const host = target.hostname.replace(/^\[|\]$/g, "");
47336
47468
  const loopback = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
47337
47469
  const isProxy = (candidateHost, candidatePort) => Number(candidatePort) === port && (candidateHost === host || loopback.has(candidateHost) && loopback.has(host));
47338
- const connect3 = net.Socket.prototype.connect;
47339
- net.Socket.prototype.connect = function guardedConnect(...args) {
47470
+ const connect3 = net2.Socket.prototype.connect;
47471
+ net2.Socket.prototype.connect = function guardedConnect(...args) {
47340
47472
  const [first] = args;
47341
47473
  const options = Array.isArray(first) ? first[0] : first;
47342
47474
  const allowed = options !== null && typeof options === "object" ? options.path !== void 0 || isProxy(options.host ?? "localhost", options.port) : typeof first === "string" && !/^\d+$/.test(first) || isProxy(typeof args[1] === "string" ? args[1] : "localhost", first);
@@ -47365,7 +47497,7 @@ function localTorCheck(proxy) {
47365
47497
  return new Promise((resolvePromise) => {
47366
47498
  let text3 = "";
47367
47499
  let done = false;
47368
- const socket = net.connect({ host, port });
47500
+ const socket = net2.connect({ host, port });
47369
47501
  const finish = (answer, version3) => {
47370
47502
  if (done) return;
47371
47503
  done = true;
@@ -127519,13 +127651,13 @@ function networkPreference(network) {
127519
127651
  return { network: n };
127520
127652
  }
127521
127653
  function offerSupport(a, prefer) {
127522
- const net2 = a.network.toLowerCase();
127654
+ const net3 = a.network.toLowerCase();
127523
127655
  if (prefer.any || prefer.solana) {
127524
- if (net2 !== "solana" && net2 !== SOLANA_MAINNET.toLowerCase()) return prefer.any ? 1 : 0;
127656
+ if (net3 !== "solana" && net3 !== SOLANA_MAINNET.toLowerCase()) return prefer.any ? 1 : 0;
127525
127657
  if (a.scheme === null) return 1;
127526
127658
  return a.asset === SOLANA_USDC && SOLANA_SCHEMES.has(a.scheme) ? 2 : 1;
127527
127659
  }
127528
- return net2 === prefer.network ? 2 : 0;
127660
+ return net3 === prefer.network ? 2 : 0;
127529
127661
  }
127530
127662
  function pickOffer(accepts, prefer) {
127531
127663
  let best = accepts[0];
@@ -127538,8 +127670,8 @@ function pickOffer(accepts, prefer) {
127538
127670
  }
127539
127671
  }
127540
127672
  const atomic4 = best?.amount == null ? null : String(best.amount);
127541
- const net2 = String(best?.network ?? "").toLowerCase();
127542
- const usdc7 = atomic4 !== null && /^[0-9]{1,31}$/.test(atomic4) && best.asset === SOLANA_USDC && (net2 === "solana" || net2 === SOLANA_MAINNET.toLowerCase()) ? formatUsdc(atomic4) : void 0;
127673
+ const net3 = String(best?.network ?? "").toLowerCase();
127674
+ const usdc7 = atomic4 !== null && /^[0-9]{1,31}$/.test(atomic4) && best.asset === SOLANA_USDC && (net3 === "solana" || net3 === SOLANA_MAINNET.toLowerCase()) ? formatUsdc(atomic4) : void 0;
127543
127675
  const price2 = best ? { atomic: atomic4, ...usdc7 === void 0 ? {} : { usdc: usdc7 }, asset: best.asset || null, network: best.network || null, scheme: best.scheme ?? null } : { atomic: null, asset: null, network: null, scheme: null };
127544
127676
  return { price: price2, support };
127545
127677
  }
@@ -148452,8 +148584,8 @@ async function programFeeRule(connection, ids) {
148452
148584
  const data = Buffer.from(info.data);
148453
148585
  return { withdrawalFeeRate: BigInt(data.readUInt16LE(WITHDRAWAL_FEE_RATE_OFFSET)), feeErrorMargin: BigInt(data.readUInt16LE(FEE_ERROR_MARGIN_OFFSET)) };
148454
148586
  }
148455
- function programMinimumFee(net2, rule) {
148456
- const expected = BigInt(net2) * rule.withdrawalFeeRate / 10000n;
148587
+ function programMinimumFee(net3, rule) {
148588
+ const expected = BigInt(net3) * rule.withdrawalFeeRate / 10000n;
148457
148589
  return expected === 0n ? 0n : expected * (10000n - rule.feeErrorMargin) / 10000n;
148458
148590
  }
148459
148591
  function transactAccounts({ ids, nullifiers, signer, signerTokenAccount, recipient, recipientTokenAccount, feeRecipientTokenAccount }) {
@@ -148658,14 +148790,14 @@ async function readRelayConfig2({ serviceUrl: serviceUrl2, ids, fetchImpl = fetc
148658
148790
  computeUnitPrice: BigInt(config.computeUnitPriceMicroLamports)
148659
148791
  });
148660
148792
  }
148661
- async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptionService, notes, tree, net: net2, fee, relay, recipient }) {
148793
+ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptionService, notes, tree, net: net3, fee, relay, recipient }) {
148662
148794
  const mint = ids.mint;
148663
148795
  const lightWasm = sdk.lightWasm;
148664
148796
  const dummyKey = new internals.UtxoKeypair(encryptionService.deriveUtxoPrivateKey(), lightWasm);
148665
148797
  const inputs = [notes[0].utxo, notes[1]?.utxo ?? new internals.Utxo({ lightWasm, keypair: dummyKey, amount: "0", mintAddress: mint, blinding: blinding() })];
148666
148798
  const paths = [tree.path(notes[0].index).pathElements, notes[1] ? tree.path(notes[1].index).pathElements : zeroPath()];
148667
148799
  const total = inputs.reduce((sum2, utxo) => sum2 + BigInt(utxo.amount.toString()), 0n);
148668
- const change = total - net2 - fee;
148800
+ const change = total - net3 - fee;
148669
148801
  if (change < 0n) fail43("withdraw_balance_insufficient");
148670
148802
  const owner = new import_web3136.PublicKey(recipient);
148671
148803
  const recipientTokenAccount = getAssociatedTokenAddressSync(new import_web3136.PublicKey(mint), owner, false, TOKEN_PROGRAM_ID);
@@ -148678,7 +148810,7 @@ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptio
148678
148810
  root: tree.root(),
148679
148811
  nextIndex: tree.elements().length,
148680
148812
  outputAmount: change,
148681
- extAmount: -net2,
148813
+ extAmount: -net3,
148682
148814
  fee,
148683
148815
  recipientTokenAccount,
148684
148816
  feeRecipientTokenAccount: relay.feeTokenAccount,
@@ -149850,11 +149982,11 @@ async function privacyCashDeposit({ store, rpcUrl, treeRpcUrl, keyFile: keyFile2
149850
149982
  });
149851
149983
  }
149852
149984
  var withdrawFee = (gross, rate, rentFee) => Math.floor(gross * rate + UNITS * rentFee);
149853
- function grossForNet(net2, rate, rentFee) {
149985
+ function grossForNet(net3, rate, rentFee) {
149854
149986
  const netOf = (gross2) => gross2 - withdrawFee(gross2, rate, rentFee);
149855
- let gross = Math.ceil((net2 + UNITS * rentFee) / (1 - rate));
149856
- while (netOf(gross) < net2) gross += 1;
149857
- while (netOf(gross - 1) >= net2) gross -= 1;
149987
+ let gross = Math.ceil((net3 + UNITS * rentFee) / (1 - rate));
149988
+ while (netOf(gross) < net3) gross += 1;
149989
+ while (netOf(gross - 1) >= net3) gross -= 1;
149858
149990
  return gross;
149859
149991
  }
149860
149992
  async function feeConfig(utils) {
@@ -150004,17 +150136,17 @@ function crowdLines({ crowd, uncounted, gross }) {
150004
150136
  const deposits2 = `deposits of ${usdc4(gross)} USDC or more landed in Privacy Cash after ${ANCHOR_WORDS[crowd.anchor]}${crowd.lowerBound ? ` (at least: ${where})` : ""}, with no withdrawal of any amount within 5 minutes after them`;
150005
150137
  return short ? `--hold-override: only ${crowd.count} ${deposits2}, of the ${crowd.needed} this hold waits for: an observer who pairs deposits and withdrawals by time and amount has few candidates besides yours` : `cover: ${crowd.count} ${deposits2}: to an observer who pairs deposits and withdrawals by time and amount, each could have funded this withdrawal as well as yours`;
150006
150138
  }
150007
- function withdrawLines({ owner, net: net2, fee, via = "sdk", relayer = PRIVACY_CASH.relayer }) {
150139
+ function withdrawLines({ owner, net: net3, fee, via = "sdk", relayer = PRIVACY_CASH.relayer }) {
150008
150140
  const reads = `reads of ${owner}'s USDC balance; no read names your source wallet`;
150009
150141
  if (via === "local") {
150010
150142
  return {
150011
- chain: `our facilitator's relayer (${relayer}) pays ${usdc4(net2)} USDC out of Privacy Cash's pool to the one-time address ${owner} and lets it hold USDC, and takes a ${usdc4(fee)} USDC fee in the same transaction; the amount and the time are public, and no transfer from your source wallet to ${owner} appears`,
150143
+ chain: `our facilitator's relayer (${relayer}) pays ${usdc4(net3)} USDC out of Privacy Cash's pool to the one-time address ${owner} and lets it hold USDC, and takes a ${usdc4(fee)} USDC fee in the same transaction; the amount and the time are public, and no transfer from your source wallet to ${owner} appears`,
150012
150144
  privacyCash: `${PRIVACY_CASH.server} sees nothing: this wallet read the tree from the chain and built the proof itself; our facilitator sees your IP address, ${owner}, the amount, the time, and the notes this withdrawal spends (if it never lands and those notes are spent later, the facilitator can link that spend to ${owner})`,
150013
150145
  rpc: `your IP address (a Tor exit with --tor), the Privacy Cash tree reads (every transaction of its USDC tree), and reads of ${owner}'s USDC balance; no read names your source wallet or one of your notes (this wallet finds which notes are spent in the tree it read), except on a rerun after an earlier proof's spend paid ${owner} or went through a lookup table: that rerun reads the proof's nullifier records on chain`
150014
150146
  };
150015
150147
  }
150016
150148
  return {
150017
- chain: `Privacy Cash's relayer (${PRIVACY_CASH.relayer}) pays ${usdc4(net2)} USDC out of its pool to the one-time address ${owner} and lets it hold USDC; Privacy Cash keeps a ${usdc4(fee)} USDC fee; the amount and the time are public, and no transfer from your source wallet to ${owner} appears`,
150149
+ chain: `Privacy Cash's relayer (${PRIVACY_CASH.relayer}) pays ${usdc4(net3)} USDC out of its pool to the one-time address ${owner} and lets it hold USDC; Privacy Cash keeps a ${usdc4(fee)} USDC fee; the amount and the time are public, and no transfer from your source wallet to ${owner} appears`,
150018
150150
  privacyCash: `${PRIVACY_CASH.server} sees your IP address, which notes are yours (so it can find the deposits that made them), the notes this withdrawal spends, and ${owner}: it can link this withdrawal to your deposit`,
150019
150151
  rpc: `your IP address (a Tor exit with --tor), the reads that check your notes, and ${reads}`
150020
150152
  };