shinjuku-shielded 0.3.153 → 0.3.155
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 +6 -6
- package/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +249 -46
package/README.md
CHANGED
|
@@ -6,19 +6,19 @@ answers privately, in a terminal chat or for your agent app. Its `mcp`
|
|
|
6
6
|
command runs a local MCP server (stdio) for your agent. Your keys never
|
|
7
7
|
leave your machine.
|
|
8
8
|
|
|
9
|
-
This is version 0.3.
|
|
9
|
+
This is version 0.3.155. The npm packages `shinjuku-shield` and
|
|
10
10
|
`shinjuku-shielded` hold the same files. The command is `shinjuku`.
|
|
11
11
|
|
|
12
12
|
## Set up
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm install -g shinjuku@0.3.
|
|
15
|
+
npm install -g shinjuku@0.3.155
|
|
16
16
|
shinjuku setup
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Type the two lines as they are. `npx install shinjuku` does not work: npx
|
|
20
20
|
reads `install` as the name of another npm package. To set up without
|
|
21
|
-
installing, type `npx shinjuku@0.3.
|
|
21
|
+
installing, type `npx shinjuku@0.3.155 setup`.
|
|
22
22
|
|
|
23
23
|
Setup makes the wallet on this machine, a private passphrase file, and the
|
|
24
24
|
checked proof tools (about 191 MB), and writes `config.json`. It also writes
|
|
@@ -36,13 +36,13 @@ Every wallet command works after `shinjuku`, for example `shinjuku balance`,
|
|
|
36
36
|
Claude Code:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.
|
|
39
|
+
claude mcp add --scope user shinjuku -- npx -y --no-audit --no-fund shinjuku-shield@0.3.155 mcp
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Claude Desktop (`claude_desktop_config.json`) or Cursor (`~/.cursor/mcp.json`):
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
|
-
{ "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.
|
|
45
|
+
{ "mcpServers": { "shinjuku": { "command": "npx", "args": ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.155", "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.
|
|
58
|
+
args = ["-y", "--no-audit", "--no-fund", "shinjuku-shield@0.3.155", "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": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "65d2837cf983622ed22a9d2bfb488a3a6ff0f276cb0d561b1be6074415daab0f",
|
|
5
|
+
"bytes": 9055610,
|
|
6
|
+
"sourceCommit": "5645304267acd2efd47b75cf75ae25ffae3096c5",
|
|
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:
|
|
1041
|
+
"publishedAt": "2026-11-03T05:58:09.739Z"
|
|
1042
1042
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shielded",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.155",
|
|
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": "65d2837c",
|
|
7
|
+
"shinjukuSha256": "65d2837cf983622ed22a9d2bfb488a3a6ff0f276cb0d561b1be6074415daab0f",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-shield#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
47339
|
-
|
|
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 =
|
|
47500
|
+
const socket = net2.connect({ host, port });
|
|
47369
47501
|
const finish = (answer, version3) => {
|
|
47370
47502
|
if (done) return;
|
|
47371
47503
|
done = true;
|
|
@@ -59547,7 +59679,7 @@ async function readCompactP03HistoryNow({
|
|
|
59547
59679
|
poolPreRead,
|
|
59548
59680
|
// walletHistory.mjs, with poolPreRead: page 0 asked beside the same refresh (requestCompactFirstPage).
|
|
59549
59681
|
// Used as this read's page 0 when this read asks page 0 at all; readPages checks it as any page.
|
|
59550
|
-
// Ignored with knownSnapshot.
|
|
59682
|
+
// Ignored with knownSnapshot, except in the read again after a refused tail hit (`tail` false).
|
|
59551
59683
|
firstPreRead,
|
|
59552
59684
|
// compactP03HistoryReport: run beside the spot checks once the initialization is verified
|
|
59553
59685
|
// ({ snapshot, initialization, contexts }); its result comes back as `alongside`.
|
|
@@ -59561,7 +59693,7 @@ async function readCompactP03HistoryNow({
|
|
|
59561
59693
|
// result and any throw are ignored.
|
|
59562
59694
|
onList,
|
|
59563
59695
|
// compactP03HistoryReport: the records of a compact cache that is not warm (cached.served). When the
|
|
59564
|
-
// list is read (no
|
|
59696
|
+
// list is read (no page 0 handed over by a behind wait), these records (or `served`'s, when the pool outgrew them) that pass
|
|
59565
59697
|
// the start of the pool's last grid page take that page instead of every page (3b, combineCompactTail);
|
|
59566
59698
|
// page 0 still goes out and is read to its end.
|
|
59567
59699
|
prefix,
|
|
@@ -59570,8 +59702,8 @@ async function readCompactP03HistoryNow({
|
|
|
59570
59702
|
// false: no tail path (compactP03HistoryReport's read again after a refused tail hit; it sent its set already).
|
|
59571
59703
|
tail = true,
|
|
59572
59704
|
// compactP03HistoryReport's read again (with tail false): the set the refused tail hit sent at this same count
|
|
59573
|
-
// (sendRestOfSet's { pages, tail }), so the read again takes its pages instead of asking them a second time
|
|
59574
|
-
//
|
|
59705
|
+
// (sendRestOfSet's { pages, tail }), so the read again takes its pages instead of asking them a second time,
|
|
59706
|
+
// with knownSnapshot too.
|
|
59575
59707
|
restPreRead,
|
|
59576
59708
|
// compactP03HistoryReport: called on a tail hit with { first (page 0's answer promise), snapshot (the pool
|
|
59577
59709
|
// account read), check, rest (the set sent at the count) }, so a refused list can be read again from that same
|
|
@@ -59596,7 +59728,7 @@ async function readCompactP03HistoryNow({
|
|
|
59596
59728
|
const hintIndex = knownSnapshot?.currentIndex ?? knownIndex;
|
|
59597
59729
|
const cachedReachesKnown = hintIndex !== void 0 && served !== void 0 && Array.isArray(served.records) && Boolean(served.initialization) && BigInt(served.records.length) * SUBTREE_LEAVES3 >= hintIndex;
|
|
59598
59730
|
const reusedFirst = knownSnapshot !== void 0 && knownFirst !== void 0 ? knownFirst : void 0;
|
|
59599
|
-
const preFirst = knownSnapshot === void 0 ? firstPreRead : void 0;
|
|
59731
|
+
const preFirst = knownSnapshot === void 0 || !tail ? firstPreRead : void 0;
|
|
59600
59732
|
const first = reusedFirst ?? (served === void 0 || hintIndex !== void 0 && !cachedReachesKnown ? preFirst ?? requestPage(source, poolString, 0, signal) : void 0);
|
|
59601
59733
|
if (first !== void 0 && reusedFirst === void 0) markPhase(preFirst !== void 0 ? "compact-page0-handed-over" : "compact-page0-sent");
|
|
59602
59734
|
let early = heldPicks.early;
|
|
@@ -59660,7 +59792,7 @@ async function readCompactP03HistoryNow({
|
|
|
59660
59792
|
const count2 = Number(snapshot.currentIndex / SUBTREE_LEAVES3);
|
|
59661
59793
|
if (!Number.isSafeInteger(count2)) throw refuse3("p03_compact_history_snapshot_invalid");
|
|
59662
59794
|
const anchors = freezeFinalizedAnchors(snapshot);
|
|
59663
|
-
const preRest = knownSnapshot === void 0 ? restPreRead : void 0;
|
|
59795
|
+
const preRest = knownSnapshot === void 0 || !tail ? restPreRead : void 0;
|
|
59664
59796
|
let rest;
|
|
59665
59797
|
const restOfSet = () => rest ??= preRest ?? sendRestOfSet(source, poolString, count2, tailGrid, signal);
|
|
59666
59798
|
let aheadHere;
|
|
@@ -59705,7 +59837,7 @@ async function readCompactP03HistoryNow({
|
|
|
59705
59837
|
};
|
|
59706
59838
|
let prefixCheck;
|
|
59707
59839
|
const readTailOrPages = async () => {
|
|
59708
|
-
if (
|
|
59840
|
+
if (reusedFirst !== void 0 || !tail) return readServedPages();
|
|
59709
59841
|
const zero = first ?? preFirst ?? requestPage(source, poolString, 0, signal);
|
|
59710
59842
|
if (first === void 0 && preFirst === void 0) markPhase("compact-page0-sent");
|
|
59711
59843
|
const from = tailFrom(count2, tailGrid);
|
|
@@ -127519,13 +127651,13 @@ function networkPreference(network) {
|
|
|
127519
127651
|
return { network: n };
|
|
127520
127652
|
}
|
|
127521
127653
|
function offerSupport(a, prefer) {
|
|
127522
|
-
const
|
|
127654
|
+
const net3 = a.network.toLowerCase();
|
|
127523
127655
|
if (prefer.any || prefer.solana) {
|
|
127524
|
-
if (
|
|
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
|
|
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
|
|
127542
|
-
const usdc7 = atomic4 !== null && /^[0-9]{1,31}$/.test(atomic4) && best.asset === SOLANA_USDC && (
|
|
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
|
}
|
|
@@ -144559,13 +144691,30 @@ var init_homeScreen = __esm({
|
|
|
144559
144691
|
|
|
144560
144692
|
// wallet/src/inference/brand.mjs
|
|
144561
144693
|
function columnsOf(text3) {
|
|
144694
|
+
const parts = GRAPHEMES ? Array.from(GRAPHEMES.segment(text3), (part) => part.segment) : Array.from(text3);
|
|
144562
144695
|
let count2 = 0;
|
|
144563
|
-
for (const
|
|
144564
|
-
|
|
144565
|
-
count2 +=
|
|
144696
|
+
for (const part of parts) {
|
|
144697
|
+
if (/^[\p{M}\p{Cf}]+$/u.test(part)) continue;
|
|
144698
|
+
count2 += new RegExp("\\p{Extended_Pictographic}|[\\u{1F1E6}-\\u{1F1FF}]|\u20E3", "u").test(part) || wideCode(part.codePointAt(0)) ? 2 : 1;
|
|
144566
144699
|
}
|
|
144567
144700
|
return count2;
|
|
144568
144701
|
}
|
|
144702
|
+
function expandTabs(line, start = 0) {
|
|
144703
|
+
if (!line.includes(" ")) return line;
|
|
144704
|
+
let out = "";
|
|
144705
|
+
let column = start;
|
|
144706
|
+
for (const piece of line.match(/\x1b\[[0-9;]*m|\t|[^\t\x1b]+|\x1b/g) ?? []) {
|
|
144707
|
+
if (piece === " ") {
|
|
144708
|
+
const spaces = 8 - column % 8;
|
|
144709
|
+
out += " ".repeat(spaces);
|
|
144710
|
+
column += spaces;
|
|
144711
|
+
} else {
|
|
144712
|
+
out += piece;
|
|
144713
|
+
if (!piece.startsWith("\x1B[")) column += columnsOf(piece);
|
|
144714
|
+
}
|
|
144715
|
+
}
|
|
144716
|
+
return out;
|
|
144717
|
+
}
|
|
144569
144718
|
function brandColor(stream = process.stderr, env = process.env) {
|
|
144570
144719
|
if (!stream?.isTTY || (env.CI ?? "") !== "" || env.TERM === "dumb") return 0;
|
|
144571
144720
|
return screenColor(stream, env);
|
|
@@ -144640,10 +144789,57 @@ function brandLine({ model: model2, tor = true, color = 0 }) {
|
|
|
144640
144789
|
...tor ? [[" \xB7 ", "ash"], ["Tor on", "brass"]] : []
|
|
144641
144790
|
], color);
|
|
144642
144791
|
}
|
|
144792
|
+
function fitColumns(text3, columns, { prefix = "" } = {}) {
|
|
144793
|
+
const width = Math.floor(Number(columns));
|
|
144794
|
+
if (!(width >= 1)) return `${prefix}${text3}`;
|
|
144795
|
+
const visible = (part) => part.replace(/\x1b\[[0-9;]*m/g, "");
|
|
144796
|
+
return String(text3).split("\n").map((raw, index) => {
|
|
144797
|
+
const head = index === 0 ? prefix : "";
|
|
144798
|
+
const headColumns = columnsOf(visible(head));
|
|
144799
|
+
const line = expandTabs(raw, headColumns);
|
|
144800
|
+
if (headColumns + columnsOf(visible(line)) <= width) return `${head}${raw}`;
|
|
144801
|
+
const pad = " ".repeat(Math.min(visible(line).match(/^ */)[0].length, Math.max(0, width - 1)));
|
|
144802
|
+
const out = [];
|
|
144803
|
+
let current = head;
|
|
144804
|
+
let used = headColumns;
|
|
144805
|
+
let hasWord = false;
|
|
144806
|
+
let spaces = "";
|
|
144807
|
+
for (const piece of line.match(/ +|(?:\x1b\[[0-9;]*m|\x1b|[^ \x1b])+/g) ?? []) {
|
|
144808
|
+
if (piece[0] === " ") {
|
|
144809
|
+
if (hasWord) spaces += piece;
|
|
144810
|
+
else {
|
|
144811
|
+
const kept3 = Math.max(0, Math.min(piece.length, width - 1 - used));
|
|
144812
|
+
current += " ".repeat(kept3);
|
|
144813
|
+
used += kept3;
|
|
144814
|
+
}
|
|
144815
|
+
continue;
|
|
144816
|
+
}
|
|
144817
|
+
const seen = columnsOf(visible(piece));
|
|
144818
|
+
if (seen === 0) {
|
|
144819
|
+
current += piece;
|
|
144820
|
+
continue;
|
|
144821
|
+
}
|
|
144822
|
+
if (hasWord && used + spaces.length + seen > width) {
|
|
144823
|
+
out.push(current);
|
|
144824
|
+
current = pad;
|
|
144825
|
+
used = pad.length;
|
|
144826
|
+
} else {
|
|
144827
|
+
current += spaces;
|
|
144828
|
+
used += spaces.length;
|
|
144829
|
+
}
|
|
144830
|
+
spaces = "";
|
|
144831
|
+
current += piece;
|
|
144832
|
+
used += seen;
|
|
144833
|
+
hasWord = true;
|
|
144834
|
+
}
|
|
144835
|
+
out.push(current);
|
|
144836
|
+
return out.join("\n");
|
|
144837
|
+
}).join("\n");
|
|
144838
|
+
}
|
|
144643
144839
|
function paidLine(atomic4, { color = 0, tail = "" } = {}) {
|
|
144644
144840
|
return paint([["\u2713 ", "brass"], ["paid privately ", "dim"], [usdcWords(atomic4), "verm"], ...tail ? [[tail, "mute"]] : []], color);
|
|
144645
144841
|
}
|
|
144646
|
-
var HEADER_COLUMNS, STATEMENTS, KATAKANA2, PRIVATE_AI, TONES, joinParts2;
|
|
144842
|
+
var HEADER_COLUMNS, STATEMENTS, KATAKANA2, GRAPHEMES, wideCode, PRIVATE_AI, TONES, joinParts2;
|
|
144647
144843
|
var init_brand = __esm({
|
|
144648
144844
|
"wallet/src/inference/brand.mjs"() {
|
|
144649
144845
|
"use strict";
|
|
@@ -144653,6 +144849,8 @@ var init_brand = __esm({
|
|
|
144653
144849
|
HEADER_COLUMNS = 80;
|
|
144654
144850
|
STATEMENTS = "Shield once. Take it everywhere. Pay unseen.";
|
|
144655
144851
|
KATAKANA2 = Array.from({ length: 65438 - 65382 }, (_, index) => String.fromCharCode(65382 + index));
|
|
144852
|
+
GRAPHEMES = typeof Intl.Segmenter === "function" ? new Intl.Segmenter("en", { granularity: "grapheme" }) : void 0;
|
|
144853
|
+
wideCode = (code2) => code2 >= 4352 && code2 <= 4447 || code2 >= 11904 && code2 <= 42191 || code2 >= 44032 && code2 <= 55203 || code2 >= 63744 && code2 <= 64255 || code2 >= 65072 && code2 <= 65103 || code2 >= 65280 && code2 <= 65376 || code2 >= 65504 && code2 <= 65510 || code2 >= 131072 && code2 <= 262141;
|
|
144656
144854
|
PRIVATE_AI = [["Private ", "bone"], ["AI", "crim"]];
|
|
144657
144855
|
TONES = { b: "brass", c: "crim", o: "crimdim" };
|
|
144658
144856
|
joinParts2 = (cells) => cells.reduce((parts, [ch, cls]) => {
|
|
@@ -144947,7 +145145,8 @@ async function runChat({ io, values, deps = {} }) {
|
|
|
144947
145145
|
servedNow();
|
|
144948
145146
|
const color = brandColor(process.stderr, env);
|
|
144949
145147
|
const answerColor = brandColor(process.stdout, env);
|
|
144950
|
-
const
|
|
145148
|
+
const fitErr = (text3) => fitColumns(text3, process.stderr.isTTY ? process.stderr.columns : 0);
|
|
145149
|
+
const say3 = (line) => io.err(`${fitErr(line)}
|
|
144951
145150
|
`);
|
|
144952
145151
|
const modeName = () => state.mode === "each" ? "one question at a time" : "a conversation";
|
|
144953
145152
|
const youPrompt = () => paint([
|
|
@@ -145482,7 +145681,7 @@ When it says ready, type your message here.`);
|
|
|
145482
145681
|
lineAbove = (text3) => {
|
|
145483
145682
|
lastLineAt = Date.now();
|
|
145484
145683
|
clearStatus();
|
|
145485
|
-
io.err(String(text3).
|
|
145684
|
+
io.err(`${fitErr(String(text3).replace(/\n$/, ""))}
|
|
145486
145685
|
`);
|
|
145487
145686
|
if (inPlace) status();
|
|
145488
145687
|
};
|
|
@@ -145551,7 +145750,11 @@ When it says ready, type your message here.`);
|
|
|
145551
145750
|
}
|
|
145552
145751
|
state.answers += 1;
|
|
145553
145752
|
if (state.mode === "talk") state.history = [...turn.messages, { role: "assistant", content }];
|
|
145554
|
-
io.out(`${
|
|
145753
|
+
io.out(`${fitColumns(
|
|
145754
|
+
content,
|
|
145755
|
+
process.stdout.isTTY ? process.stdout.columns : 0,
|
|
145756
|
+
{ prefix: answerColor ? paint([["AI ", "crim"], ["\u203A ", "ash"]], answerColor) : "" }
|
|
145757
|
+
)}
|
|
145555
145758
|
`);
|
|
145556
145759
|
const cut2 = result.finishReason === "length" ? `(the answer stopped at its ${turn.maxTokens}-token limit) ` : "";
|
|
145557
145760
|
const plainPaid = paid !== void 0 && !replayed && !unpaid;
|
|
@@ -148452,8 +148655,8 @@ async function programFeeRule(connection, ids) {
|
|
|
148452
148655
|
const data = Buffer.from(info.data);
|
|
148453
148656
|
return { withdrawalFeeRate: BigInt(data.readUInt16LE(WITHDRAWAL_FEE_RATE_OFFSET)), feeErrorMargin: BigInt(data.readUInt16LE(FEE_ERROR_MARGIN_OFFSET)) };
|
|
148454
148657
|
}
|
|
148455
|
-
function programMinimumFee(
|
|
148456
|
-
const expected = BigInt(
|
|
148658
|
+
function programMinimumFee(net3, rule) {
|
|
148659
|
+
const expected = BigInt(net3) * rule.withdrawalFeeRate / 10000n;
|
|
148457
148660
|
return expected === 0n ? 0n : expected * (10000n - rule.feeErrorMargin) / 10000n;
|
|
148458
148661
|
}
|
|
148459
148662
|
function transactAccounts({ ids, nullifiers, signer, signerTokenAccount, recipient, recipientTokenAccount, feeRecipientTokenAccount }) {
|
|
@@ -148658,14 +148861,14 @@ async function readRelayConfig2({ serviceUrl: serviceUrl2, ids, fetchImpl = fetc
|
|
|
148658
148861
|
computeUnitPrice: BigInt(config.computeUnitPriceMicroLamports)
|
|
148659
148862
|
});
|
|
148660
148863
|
}
|
|
148661
|
-
async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptionService, notes, tree, net:
|
|
148864
|
+
async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptionService, notes, tree, net: net3, fee, relay, recipient }) {
|
|
148662
148865
|
const mint = ids.mint;
|
|
148663
148866
|
const lightWasm = sdk.lightWasm;
|
|
148664
148867
|
const dummyKey = new internals.UtxoKeypair(encryptionService.deriveUtxoPrivateKey(), lightWasm);
|
|
148665
148868
|
const inputs = [notes[0].utxo, notes[1]?.utxo ?? new internals.Utxo({ lightWasm, keypair: dummyKey, amount: "0", mintAddress: mint, blinding: blinding() })];
|
|
148666
148869
|
const paths = [tree.path(notes[0].index).pathElements, notes[1] ? tree.path(notes[1].index).pathElements : zeroPath()];
|
|
148667
148870
|
const total = inputs.reduce((sum2, utxo) => sum2 + BigInt(utxo.amount.toString()), 0n);
|
|
148668
|
-
const change = total -
|
|
148871
|
+
const change = total - net3 - fee;
|
|
148669
148872
|
if (change < 0n) fail43("withdraw_balance_insufficient");
|
|
148670
148873
|
const owner = new import_web3136.PublicKey(recipient);
|
|
148671
148874
|
const recipientTokenAccount = getAssociatedTokenAddressSync(new import_web3136.PublicKey(mint), owner, false, TOKEN_PROGRAM_ID);
|
|
@@ -148678,7 +148881,7 @@ async function buildLocalWithdrawal({ internals, sdk, connection, ids, encryptio
|
|
|
148678
148881
|
root: tree.root(),
|
|
148679
148882
|
nextIndex: tree.elements().length,
|
|
148680
148883
|
outputAmount: change,
|
|
148681
|
-
extAmount: -
|
|
148884
|
+
extAmount: -net3,
|
|
148682
148885
|
fee,
|
|
148683
148886
|
recipientTokenAccount,
|
|
148684
148887
|
feeRecipientTokenAccount: relay.feeTokenAccount,
|
|
@@ -149850,11 +150053,11 @@ async function privacyCashDeposit({ store, rpcUrl, treeRpcUrl, keyFile: keyFile2
|
|
|
149850
150053
|
});
|
|
149851
150054
|
}
|
|
149852
150055
|
var withdrawFee = (gross, rate, rentFee) => Math.floor(gross * rate + UNITS * rentFee);
|
|
149853
|
-
function grossForNet(
|
|
150056
|
+
function grossForNet(net3, rate, rentFee) {
|
|
149854
150057
|
const netOf = (gross2) => gross2 - withdrawFee(gross2, rate, rentFee);
|
|
149855
|
-
let gross = Math.ceil((
|
|
149856
|
-
while (netOf(gross) <
|
|
149857
|
-
while (netOf(gross - 1) >=
|
|
150058
|
+
let gross = Math.ceil((net3 + UNITS * rentFee) / (1 - rate));
|
|
150059
|
+
while (netOf(gross) < net3) gross += 1;
|
|
150060
|
+
while (netOf(gross - 1) >= net3) gross -= 1;
|
|
149858
150061
|
return gross;
|
|
149859
150062
|
}
|
|
149860
150063
|
async function feeConfig(utils) {
|
|
@@ -150004,17 +150207,17 @@ function crowdLines({ crowd, uncounted, gross }) {
|
|
|
150004
150207
|
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
150208
|
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
150209
|
}
|
|
150007
|
-
function withdrawLines({ owner, net:
|
|
150210
|
+
function withdrawLines({ owner, net: net3, fee, via = "sdk", relayer = PRIVACY_CASH.relayer }) {
|
|
150008
150211
|
const reads = `reads of ${owner}'s USDC balance; no read names your source wallet`;
|
|
150009
150212
|
if (via === "local") {
|
|
150010
150213
|
return {
|
|
150011
|
-
chain: `our facilitator's relayer (${relayer}) pays ${usdc4(
|
|
150214
|
+
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
150215
|
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
150216
|
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
150217
|
};
|
|
150015
150218
|
}
|
|
150016
150219
|
return {
|
|
150017
|
-
chain: `Privacy Cash's relayer (${PRIVACY_CASH.relayer}) pays ${usdc4(
|
|
150220
|
+
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
150221
|
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
150222
|
rpc: `your IP address (a Tor exit with --tor), the reads that check your notes, and ${reads}`
|
|
150020
150223
|
};
|