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 +6 -6
- package/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +164 -32
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.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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
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:
|
|
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.
|
|
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": "
|
|
7
|
-
"shinjukuSha256": "
|
|
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",
|
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;
|
|
@@ -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
|
}
|
|
@@ -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(
|
|
148456
|
-
const expected = BigInt(
|
|
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:
|
|
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 -
|
|
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: -
|
|
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(
|
|
149985
|
+
function grossForNet(net3, rate, rentFee) {
|
|
149854
149986
|
const netOf = (gross2) => gross2 - withdrawFee(gross2, rate, rentFee);
|
|
149855
|
-
let gross = Math.ceil((
|
|
149856
|
-
while (netOf(gross) <
|
|
149857
|
-
while (netOf(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:
|
|
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(
|
|
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(
|
|
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
|
};
|