x402-proxy 0.9.0 → 0.9.2
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/CHANGELOG.md +24 -1
- package/README.md +11 -8
- package/dist/bin/cli.js +80 -83
- package/dist/{derive-CAYmX-Yz.js → derive-EDXzwKW2.js} +1 -4
- package/dist/index.js +3 -7
- package/dist/openclaw/plugin.js +4 -20
- package/dist/{setup-BjyoqzT3.js → setup-QtTFsCFs.js} +78 -12
- package/dist/setup-lCsiivm2.js +3 -0
- package/dist/status-Dt8be_kW.js +3 -0
- package/dist/{status-D3f5IVf6.js → status-ZRhJKaXq.js} +3 -5
- package/dist/wallet-8evCw-5Z.js +3 -0
- package/dist/{wallet-DZsXptY7.js → wallet-Bs8cBOv7.js} +4 -13
- package/package.json +16 -16
- package/skills/SKILL.md +17 -7
- package/dist/setup-CJgw4opQ.js +0 -4
- package/dist/status-BkURZYDA.js +0 -4
- package/dist/wallet-BM0ngyqk.js +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.2] - 2026-03-26
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Upgraded all dependencies to latest: `@x402/*` 2.6.0 -> 2.8.0, `@solana/kit` 6.3.0 -> 6.5.0, `viem` 2.47.6, `@modelcontextprotocol/sdk` 1.28.0, `vitest` 4.1.1, `tsdown` 0.21.5, `@biomejs/biome` 2.4.9, `turbo` 2.8.20, `openclaw` 2026.3.24
|
|
14
|
+
- `pnpm check` now runs tests alongside build, type-check, and biome
|
|
15
|
+
- Biome config scoped to supported file types only (`*.ts`, `*.json`, `*.jsonc`)
|
|
16
|
+
|
|
17
|
+
## [0.9.1] - 2026-03-26
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- `setup --non-interactive` flag - auto-generates wallet and outputs addresses as JSON to stdout (`{"base":"0x...","tempo":"0x...","solana":"..."}`)
|
|
21
|
+
- `setup --import-mnemonic` flag - import existing BIP-39 mnemonic non-interactively
|
|
22
|
+
- MCP proxy auto-generates wallet on first run when no wallet exists (no more "No wallet configured" error)
|
|
23
|
+
- OpenClaw integration example in README and SKILL.md: `openclaw mcp set surf '{"command":"npx","args":["-y","x402-proxy","mcp","https://surf.cascade.fyi/mcp"]}'`
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- `npx -y` flag added to all generated MCP configs (`mcp add` command and docs) - prevents npx install prompt from corrupting MCP stdio protocol
|
|
27
|
+
- MCP config examples no longer show `X402_PROXY_WALLET_MNEMONIC` env var as default - wallet file is the primary path, env vars are documented as fallback only
|
|
28
|
+
- All example MCP URLs updated to `https://surf.cascade.fyi/mcp`
|
|
29
|
+
- Non-interactive JSON output uses network names (`base`, `tempo`, `solana`) instead of generic `evm`
|
|
30
|
+
|
|
10
31
|
## [0.9.0] - 2026-03-25
|
|
11
32
|
|
|
12
33
|
### Added
|
|
@@ -263,7 +284,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
263
284
|
- `appendHistory` / `readHistory` / `calcSpend` - JSONL transaction history
|
|
264
285
|
- Re-exports from `@x402/fetch`, `@x402/svm`, `@x402/evm`
|
|
265
286
|
|
|
266
|
-
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.
|
|
287
|
+
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.2...HEAD
|
|
288
|
+
[0.9.2]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.1...v0.9.2
|
|
289
|
+
[0.9.1]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.0...v0.9.1
|
|
267
290
|
[0.9.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.6...v0.9.0
|
|
268
291
|
[0.8.6]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.5...v0.8.6
|
|
269
292
|
[0.8.5]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.4...v0.8.5
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Let your AI agent consume any paid MCP server.
|
|
|
19
19
|
### Quick setup
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npx x402-proxy mcp add
|
|
22
|
+
npx x402-proxy mcp add surf https://surf.cascade.fyi/mcp
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
Auto-detects installed AI clients (Claude Code, Cursor, VS Code, and 16+ others), shows a config preview, and writes it for you. Runs wallet setup if needed.
|
|
@@ -31,18 +31,21 @@ Or add to your client config directly:
|
|
|
31
31
|
```json
|
|
32
32
|
{
|
|
33
33
|
"mcpServers": {
|
|
34
|
-
"
|
|
34
|
+
"surf": {
|
|
35
35
|
"command": "npx",
|
|
36
|
-
"args": ["x402-proxy", "mcp", "https://
|
|
37
|
-
"env": {
|
|
38
|
-
"X402_PROXY_WALLET_MNEMONIC": "your 24 words here"
|
|
39
|
-
}
|
|
36
|
+
"args": ["-y", "x402-proxy", "mcp", "https://surf.cascade.fyi/mcp"]
|
|
40
37
|
}
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
40
|
```
|
|
44
41
|
|
|
45
|
-
The proxy
|
|
42
|
+
The proxy auto-generates a wallet on first run and uses `~/.config/x402-proxy/wallet.json`. No env vars needed. Your agent never touches crypto.
|
|
43
|
+
|
|
44
|
+
For OpenClaw:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
openclaw mcp set surf '{"command":"npx","args":["-y","x402-proxy","mcp","https://surf.cascade.fyi/mcp"]}'
|
|
48
|
+
```
|
|
46
49
|
|
|
47
50
|
## HTTP Requests
|
|
48
51
|
|
|
@@ -110,7 +113,7 @@ $ MY_MNEMONIC=$(npx x402-proxy wallet export-key mnemonic)
|
|
|
110
113
|
|
|
111
114
|
## Env Vars
|
|
112
115
|
|
|
113
|
-
Override wallet per-instance (
|
|
116
|
+
Override wallet per-instance (fallback for environments where the wallet file isn't accessible):
|
|
114
117
|
|
|
115
118
|
```
|
|
116
119
|
X402_PROXY_WALLET_MNEMONIC # BIP-39 mnemonic (derives both chains)
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort, l as loadWalletFile, s as isConfigured, u as saveConfig } from "../derive-
|
|
3
|
-
import { _ as error, b as warn, c as resolveWallet, d as displayNetwork, f as formatAmount, g as dim, h as readHistory, l as appendHistory, m as formatUsdcValue, n as fetchAllBalances, o as walletInfoCommand, p as formatTxLine, s as buildX402Client, u as calcSpend, v as info, y as isTTY } from "../wallet-
|
|
4
|
-
import { n as setupCommand, t as runSetup } from "../setup-
|
|
5
|
-
import { n as statusCommand } from "../status-
|
|
2
|
+
import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort, l as loadWalletFile, s as isConfigured, u as saveConfig } from "../derive-EDXzwKW2.js";
|
|
3
|
+
import { _ as error, b as warn, c as resolveWallet, d as displayNetwork, f as formatAmount, g as dim, h as readHistory, l as appendHistory, m as formatUsdcValue, n as fetchAllBalances, o as walletInfoCommand, p as formatTxLine, s as buildX402Client, u as calcSpend, v as info, y as isTTY } from "../wallet-Bs8cBOv7.js";
|
|
4
|
+
import { n as setupCommand, t as runSetup } from "../setup-QtTFsCFs.js";
|
|
5
|
+
import { n as statusCommand } from "../status-ZRhJKaXq.js";
|
|
6
6
|
import { dirname, join, normalize, resolve } from "node:path";
|
|
7
7
|
import { buildApplication, buildCommand, buildRouteMap, run } from "@stricli/core";
|
|
8
8
|
import pc from "picocolors";
|
|
@@ -11,7 +11,6 @@ import { homedir } from "node:os";
|
|
|
11
11
|
import { decodePaymentResponseHeader, wrapFetchWithPayment } from "@x402/fetch";
|
|
12
12
|
import { base58 } from "@scure/base";
|
|
13
13
|
import * as prompts from "@clack/prompts";
|
|
14
|
-
|
|
15
14
|
//#region src/commands/config.ts
|
|
16
15
|
const VALID_KEYS = {
|
|
17
16
|
defaultNetwork: {
|
|
@@ -161,7 +160,6 @@ const configUnsetCommand = buildCommand({
|
|
|
161
160
|
dim(` ${key} unset`);
|
|
162
161
|
}
|
|
163
162
|
});
|
|
164
|
-
|
|
165
163
|
//#endregion
|
|
166
164
|
//#region src/handler.ts
|
|
167
165
|
/**
|
|
@@ -301,7 +299,6 @@ async function createMppProxyHandler(opts) {
|
|
|
301
299
|
}
|
|
302
300
|
};
|
|
303
301
|
}
|
|
304
|
-
|
|
305
302
|
//#endregion
|
|
306
303
|
//#region src/commands/fetch.ts
|
|
307
304
|
function isStreamingResponse(res) {
|
|
@@ -401,7 +398,7 @@ Examples:
|
|
|
401
398
|
};
|
|
402
399
|
if (!url) {
|
|
403
400
|
if (isConfigured()) {
|
|
404
|
-
const { displayStatus } = await import("../status-
|
|
401
|
+
const { displayStatus } = await import("../status-Dt8be_kW.js");
|
|
405
402
|
await displayStatus();
|
|
406
403
|
console.log();
|
|
407
404
|
console.log(pc.dim(" Commands:"));
|
|
@@ -453,7 +450,7 @@ Examples:
|
|
|
453
450
|
process.exit(1);
|
|
454
451
|
}
|
|
455
452
|
dim(" No wallet found. Let's set one up first.\n");
|
|
456
|
-
const { runSetup } = await import("../setup-
|
|
453
|
+
const { runSetup } = await import("../setup-lCsiivm2.js");
|
|
457
454
|
await runSetup();
|
|
458
455
|
console.log();
|
|
459
456
|
wallet = resolveWallet();
|
|
@@ -466,7 +463,7 @@ Examples:
|
|
|
466
463
|
verbose(`protocol: ${resolvedProtocol ?? "auto-detect"}, maxDeposit: ${maxDeposit}`);
|
|
467
464
|
let preferredNetwork = config?.defaultNetwork;
|
|
468
465
|
if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
|
|
469
|
-
const { fetchAllBalances } = await import("../wallet-
|
|
466
|
+
const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
|
|
470
467
|
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
471
468
|
const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
|
|
472
469
|
const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
|
|
@@ -527,7 +524,7 @@ Examples:
|
|
|
527
524
|
verbose(closeReceipt ? `close receipt: amount=${closeReceipt.amount ?? "none"}, channelId=${closeReceipt.channelId ?? "none"}, txHash=${closeReceipt.receipt?.txHash ?? "none"}` : "no close receipt (session close may have failed)");
|
|
528
525
|
mppPayment = closeReceipt ?? {
|
|
529
526
|
protocol: "mpp",
|
|
530
|
-
network:
|
|
527
|
+
network: "eip155:4217",
|
|
531
528
|
intent: "session"
|
|
532
529
|
};
|
|
533
530
|
usedProtocol = "mpp";
|
|
@@ -633,7 +630,7 @@ Examples:
|
|
|
633
630
|
const hasSolana = accepts.some((a) => a.network.startsWith("solana:"));
|
|
634
631
|
const hasMpp = detected.mpp;
|
|
635
632
|
const hasOther = accepts.some((a) => !a.network.startsWith("eip155:") && !a.network.startsWith("solana:"));
|
|
636
|
-
const { fetchAllBalances } = await import("../wallet-
|
|
633
|
+
const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
|
|
637
634
|
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
638
635
|
const evmUsdc = hasEvm && balances.evm ? Number(balances.evm.usdc) : 0;
|
|
639
636
|
const solUsdc = hasSolana && balances.sol ? Number(balances.sol.usdc) : 0;
|
|
@@ -754,7 +751,6 @@ Examples:
|
|
|
754
751
|
}
|
|
755
752
|
}
|
|
756
753
|
});
|
|
757
|
-
|
|
758
754
|
//#endregion
|
|
759
755
|
//#region src/commands/mcp.ts
|
|
760
756
|
const mcpCommand = buildCommand({
|
|
@@ -764,8 +760,9 @@ const mcpCommand = buildCommand({
|
|
|
764
760
|
|
|
765
761
|
Add to your MCP client config (Claude, Cursor, etc.):
|
|
766
762
|
"command": "npx",
|
|
767
|
-
"args": ["x402-proxy", "mcp", "https://
|
|
768
|
-
|
|
763
|
+
"args": ["-y", "x402-proxy", "mcp", "https://surf.cascade.fyi/mcp"]
|
|
764
|
+
|
|
765
|
+
Wallet is auto-generated on first run. No env vars needed.`
|
|
769
766
|
},
|
|
770
767
|
parameters: {
|
|
771
768
|
flags: {
|
|
@@ -808,8 +805,18 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
808
805
|
solanaKey: flags.solanaKey
|
|
809
806
|
});
|
|
810
807
|
if (wallet.source === "none") {
|
|
811
|
-
|
|
812
|
-
|
|
808
|
+
dim("No wallet found. Auto-generating...");
|
|
809
|
+
const { runSetup } = await import("../setup-lCsiivm2.js");
|
|
810
|
+
await runSetup({ nonInteractive: true });
|
|
811
|
+
const fresh = resolveWallet({
|
|
812
|
+
evmKey: flags.evmKey,
|
|
813
|
+
solanaKey: flags.solanaKey
|
|
814
|
+
});
|
|
815
|
+
if (fresh.source === "none") {
|
|
816
|
+
error("Wallet auto-setup failed. Run: $ npx x402-proxy setup");
|
|
817
|
+
process.exit(1);
|
|
818
|
+
}
|
|
819
|
+
Object.assign(wallet, fresh);
|
|
813
820
|
}
|
|
814
821
|
dim(`x402-proxy MCP proxy -> ${remoteUrl}`);
|
|
815
822
|
if (wallet.evmAddress) dim(` EVM: ${wallet.evmAddress}`);
|
|
@@ -843,7 +850,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
843
850
|
async function startX402Proxy() {
|
|
844
851
|
let preferredNetwork = config?.defaultNetwork;
|
|
845
852
|
if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
|
|
846
|
-
const { fetchAllBalances } = await import("../wallet-
|
|
853
|
+
const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
|
|
847
854
|
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
848
855
|
const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
|
|
849
856
|
const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
|
|
@@ -863,7 +870,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
863
870
|
}
|
|
864
871
|
const remoteClient = new Client({
|
|
865
872
|
name: "x402-proxy",
|
|
866
|
-
version: "0.9.
|
|
873
|
+
version: "0.9.2"
|
|
867
874
|
});
|
|
868
875
|
const x402Mcp = new x402MCPClient(remoteClient, x402PaymentClient, {
|
|
869
876
|
autoPayment: true,
|
|
@@ -901,7 +908,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
901
908
|
}
|
|
902
909
|
const localServer = new Server({
|
|
903
910
|
name: "x402-proxy",
|
|
904
|
-
version: "0.9.
|
|
911
|
+
version: "0.9.2"
|
|
905
912
|
}, { capabilities: {
|
|
906
913
|
tools: tools.length > 0 ? {} : void 0,
|
|
907
914
|
resources: remoteResources.length > 0 ? {} : void 0
|
|
@@ -996,7 +1003,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
996
1003
|
}));
|
|
997
1004
|
const remoteClient = new Client({
|
|
998
1005
|
name: "x402-proxy",
|
|
999
|
-
version: "0.9.
|
|
1006
|
+
version: "0.9.2"
|
|
1000
1007
|
});
|
|
1001
1008
|
await connectTransport(remoteClient);
|
|
1002
1009
|
const mppClient = McpClient.wrap(remoteClient, { methods: wrappedMethods });
|
|
@@ -1011,7 +1018,7 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
1011
1018
|
}
|
|
1012
1019
|
const localServer = new Server({
|
|
1013
1020
|
name: "x402-proxy",
|
|
1014
|
-
version: "0.9.
|
|
1021
|
+
version: "0.9.2"
|
|
1015
1022
|
}, { capabilities: {
|
|
1016
1023
|
tools: tools.length > 0 ? {} : void 0,
|
|
1017
1024
|
resources: remoteResources.length > 0 ? {} : void 0
|
|
@@ -1087,7 +1094,6 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
1087
1094
|
}
|
|
1088
1095
|
}
|
|
1089
1096
|
});
|
|
1090
|
-
|
|
1091
1097
|
//#endregion
|
|
1092
1098
|
//#region src/commands/mcp-add.ts
|
|
1093
1099
|
function resolvePlatformPath(raw) {
|
|
@@ -1197,6 +1203,7 @@ const mcpAddCommand = buildCommand({
|
|
|
1197
1203
|
const generated = generateConfig(clientId, serverName, {
|
|
1198
1204
|
command: "npx",
|
|
1199
1205
|
args: [
|
|
1206
|
+
"-y",
|
|
1200
1207
|
"x402-proxy",
|
|
1201
1208
|
"mcp",
|
|
1202
1209
|
url
|
|
@@ -1270,7 +1277,6 @@ const mcpAddCommand = buildCommand({
|
|
|
1270
1277
|
prompts.outro(pc.green(`MCP server ${pc.bold(serverName)} is ready to use!`));
|
|
1271
1278
|
}
|
|
1272
1279
|
});
|
|
1273
|
-
|
|
1274
1280
|
//#endregion
|
|
1275
1281
|
//#region src/commands/wallet-export.ts
|
|
1276
1282
|
const walletExportCommand = buildCommand({
|
|
@@ -1324,62 +1330,57 @@ const walletExportCommand = buildCommand({
|
|
|
1324
1330
|
else process.stdout.write(base58.encode(wallet.solanaKey.slice(0, 32)));
|
|
1325
1331
|
}
|
|
1326
1332
|
});
|
|
1327
|
-
|
|
1328
|
-
//#endregion
|
|
1329
|
-
//#region src/commands/wallet-history.ts
|
|
1330
|
-
const walletHistoryCommand = buildCommand({
|
|
1331
|
-
docs: { brief: "Show payment history" },
|
|
1332
|
-
parameters: {
|
|
1333
|
-
flags: {
|
|
1334
|
-
limit: {
|
|
1335
|
-
kind: "parsed",
|
|
1336
|
-
brief: "Number of entries to show",
|
|
1337
|
-
parse: Number,
|
|
1338
|
-
default: "20"
|
|
1339
|
-
},
|
|
1340
|
-
json: {
|
|
1341
|
-
kind: "boolean",
|
|
1342
|
-
brief: "Output raw JSONL",
|
|
1343
|
-
default: false
|
|
1344
|
-
}
|
|
1345
|
-
},
|
|
1346
|
-
positional: {
|
|
1347
|
-
kind: "tuple",
|
|
1348
|
-
parameters: []
|
|
1349
|
-
}
|
|
1350
|
-
},
|
|
1351
|
-
func(flags) {
|
|
1352
|
-
const records = readHistory(getHistoryPath());
|
|
1353
|
-
if (records.length === 0) {
|
|
1354
|
-
console.log(pc.dim("No payment history yet."));
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
if (flags.json) {
|
|
1358
|
-
const slice = records.slice(-flags.limit);
|
|
1359
|
-
for (const r of slice) process.stdout.write(`${JSON.stringify(r)}\n`);
|
|
1360
|
-
return;
|
|
1361
|
-
}
|
|
1362
|
-
const spend = calcSpend(records);
|
|
1363
|
-
const slice = records.slice(-flags.limit);
|
|
1364
|
-
console.log();
|
|
1365
|
-
info("Payment History");
|
|
1366
|
-
console.log();
|
|
1367
|
-
for (const r of slice) {
|
|
1368
|
-
const line = formatTxLine(r).replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
|
|
1369
|
-
console.log(line);
|
|
1370
|
-
}
|
|
1371
|
-
console.log();
|
|
1372
|
-
console.log(pc.dim(` Today: ${formatAmount(spend.today, "USDC")} | Total: ${formatAmount(spend.total, "USDC")} | ${spend.count} transactions`));
|
|
1373
|
-
console.log();
|
|
1374
|
-
}
|
|
1375
|
-
});
|
|
1376
|
-
|
|
1377
1333
|
//#endregion
|
|
1378
1334
|
//#region src/app.ts
|
|
1379
1335
|
const walletRoutes = buildRouteMap({
|
|
1380
1336
|
routes: {
|
|
1381
1337
|
info: walletInfoCommand,
|
|
1382
|
-
history:
|
|
1338
|
+
history: buildCommand({
|
|
1339
|
+
docs: { brief: "Show payment history" },
|
|
1340
|
+
parameters: {
|
|
1341
|
+
flags: {
|
|
1342
|
+
limit: {
|
|
1343
|
+
kind: "parsed",
|
|
1344
|
+
brief: "Number of entries to show",
|
|
1345
|
+
parse: Number,
|
|
1346
|
+
default: "20"
|
|
1347
|
+
},
|
|
1348
|
+
json: {
|
|
1349
|
+
kind: "boolean",
|
|
1350
|
+
brief: "Output raw JSONL",
|
|
1351
|
+
default: false
|
|
1352
|
+
}
|
|
1353
|
+
},
|
|
1354
|
+
positional: {
|
|
1355
|
+
kind: "tuple",
|
|
1356
|
+
parameters: []
|
|
1357
|
+
}
|
|
1358
|
+
},
|
|
1359
|
+
func(flags) {
|
|
1360
|
+
const records = readHistory(getHistoryPath());
|
|
1361
|
+
if (records.length === 0) {
|
|
1362
|
+
console.log(pc.dim("No payment history yet."));
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
if (flags.json) {
|
|
1366
|
+
const slice = records.slice(-flags.limit);
|
|
1367
|
+
for (const r of slice) process.stdout.write(`${JSON.stringify(r)}\n`);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
const spend = calcSpend(records);
|
|
1371
|
+
const slice = records.slice(-flags.limit);
|
|
1372
|
+
console.log();
|
|
1373
|
+
info("Payment History");
|
|
1374
|
+
console.log();
|
|
1375
|
+
for (const r of slice) {
|
|
1376
|
+
const line = formatTxLine(r).replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
|
|
1377
|
+
console.log(line);
|
|
1378
|
+
}
|
|
1379
|
+
console.log();
|
|
1380
|
+
console.log(pc.dim(` Today: ${formatAmount(spend.today, "USDC")} | Total: ${formatAmount(spend.total, "USDC")} | ${spend.count} transactions`));
|
|
1381
|
+
console.log();
|
|
1382
|
+
}
|
|
1383
|
+
}),
|
|
1383
1384
|
"export-key": walletExportCommand
|
|
1384
1385
|
},
|
|
1385
1386
|
defaultCommand: "info",
|
|
@@ -1394,7 +1395,7 @@ const configRoutes = buildRouteMap({
|
|
|
1394
1395
|
defaultCommand: "show",
|
|
1395
1396
|
docs: { brief: "Manage configuration" }
|
|
1396
1397
|
});
|
|
1397
|
-
const
|
|
1398
|
+
const app = buildApplication(buildRouteMap({
|
|
1398
1399
|
routes: {
|
|
1399
1400
|
fetch: fetchCommand,
|
|
1400
1401
|
mcp: buildRouteMap({
|
|
@@ -1412,19 +1413,16 @@ const routes = buildRouteMap({
|
|
|
1412
1413
|
},
|
|
1413
1414
|
defaultCommand: "fetch",
|
|
1414
1415
|
docs: { brief: "curl for x402 paid APIs" }
|
|
1415
|
-
})
|
|
1416
|
-
const app = buildApplication(routes, {
|
|
1416
|
+
}), {
|
|
1417
1417
|
name: "x402-proxy",
|
|
1418
|
-
versionInfo: { currentVersion: "0.9.
|
|
1418
|
+
versionInfo: { currentVersion: "0.9.2" },
|
|
1419
1419
|
scanner: { caseStyle: "allow-kebab-for-camel" }
|
|
1420
1420
|
});
|
|
1421
|
-
|
|
1422
1421
|
//#endregion
|
|
1423
1422
|
//#region src/context.ts
|
|
1424
1423
|
function buildContext(process) {
|
|
1425
1424
|
return { process };
|
|
1426
1425
|
}
|
|
1427
|
-
|
|
1428
1426
|
//#endregion
|
|
1429
1427
|
//#region src/bin/cli.ts
|
|
1430
1428
|
process.on("SIGINT", () => process.exit(130));
|
|
@@ -1444,6 +1442,5 @@ for (let i = 0; i < rawArgs.length; i++) {
|
|
|
1444
1442
|
} else args.push(a);
|
|
1445
1443
|
}
|
|
1446
1444
|
await run(app, args, buildContext(process));
|
|
1447
|
-
|
|
1448
1445
|
//#endregion
|
|
1449
|
-
export {
|
|
1446
|
+
export {};
|
|
@@ -12,7 +12,6 @@ import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
|
12
12
|
import { HDKey } from "@scure/bip32";
|
|
13
13
|
import { generateMnemonic, mnemonicToSeedSync } from "@scure/bip39";
|
|
14
14
|
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
15
|
-
|
|
16
15
|
//#region src/lib/config.ts
|
|
17
16
|
const APP_NAME = "x402-proxy";
|
|
18
17
|
function getConfigDir() {
|
|
@@ -85,7 +84,6 @@ function isConfigured() {
|
|
|
85
84
|
if (process.env.X402_PROXY_WALLET_SOLANA_KEY) return true;
|
|
86
85
|
return loadWalletFile() !== null;
|
|
87
86
|
}
|
|
88
|
-
|
|
89
87
|
//#endregion
|
|
90
88
|
//#region src/lib/derive.ts
|
|
91
89
|
/**
|
|
@@ -156,6 +154,5 @@ function checksumAddress(addr) {
|
|
|
156
154
|
for (let i = 0; i < 40; i++) out += Number.parseInt(hash[i], 16) >= 8 ? addr[i].toUpperCase() : addr[i];
|
|
157
155
|
return out;
|
|
158
156
|
}
|
|
159
|
-
|
|
160
157
|
//#endregion
|
|
161
|
-
export { getHistoryPath as a, loadConfig as c, saveWalletFile as d, getConfigDirShort as i, loadWalletFile as l, deriveSolanaKeypair as n, getWalletPath as o, generateMnemonic$1 as r, isConfigured as s, deriveEvmKeypair as t, saveConfig as u };
|
|
158
|
+
export { getHistoryPath as a, loadConfig as c, saveWalletFile as d, getConfigDirShort as i, loadWalletFile as l, deriveSolanaKeypair as n, getWalletPath as o, generateMnemonic$1 as r, isConfigured as s, deriveEvmKeypair as t, saveConfig as u };
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFil
|
|
|
5
5
|
import { dirname } from "node:path";
|
|
6
6
|
import { createKeyPairSignerFromBytes } from "@solana/kit";
|
|
7
7
|
import { privateKeyToAccount } from "viem/accounts";
|
|
8
|
-
|
|
9
8
|
//#region src/handler.ts
|
|
10
9
|
/**
|
|
11
10
|
* Detect which payment protocols a 402 response advertises.
|
|
@@ -144,7 +143,6 @@ async function createMppProxyHandler(opts) {
|
|
|
144
143
|
}
|
|
145
144
|
};
|
|
146
145
|
}
|
|
147
|
-
|
|
148
146
|
//#endregion
|
|
149
147
|
//#region src/history.ts
|
|
150
148
|
const HISTORY_MAX_LINES = 1e3;
|
|
@@ -154,9 +152,9 @@ function appendHistory(historyPath, record) {
|
|
|
154
152
|
mkdirSync(dirname(historyPath), { recursive: true });
|
|
155
153
|
appendFileSync(historyPath, `${JSON.stringify(record)}\n`);
|
|
156
154
|
if (existsSync(historyPath)) {
|
|
157
|
-
if (statSync(historyPath).size >
|
|
155
|
+
if (statSync(historyPath).size > 1e3 * 200) {
|
|
158
156
|
const lines = readFileSync(historyPath, "utf-8").trimEnd().split("\n");
|
|
159
|
-
if (lines.length >
|
|
157
|
+
if (lines.length > 1e3) writeFileSync(historyPath, `${lines.slice(-500).join("\n")}\n`);
|
|
160
158
|
}
|
|
161
159
|
}
|
|
162
160
|
} catch {}
|
|
@@ -263,7 +261,6 @@ function formatTxLine(r, opts) {
|
|
|
263
261
|
}
|
|
264
262
|
return ` ${timeStr} ${r.ok ? "" : "✗ "}${parts.join(" · ")}`;
|
|
265
263
|
}
|
|
266
|
-
|
|
267
264
|
//#endregion
|
|
268
265
|
//#region src/wallet.ts
|
|
269
266
|
/**
|
|
@@ -283,6 +280,5 @@ function loadEvmWallet(keyPath) {
|
|
|
283
280
|
if (!hex.startsWith("0x")) hex = `0x${hex}`;
|
|
284
281
|
return toClientEvmSigner$1(privateKeyToAccount(hex));
|
|
285
282
|
}
|
|
286
|
-
|
|
287
283
|
//#endregion
|
|
288
|
-
export { ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, TEMPO_NETWORK, appendHistory, calcSpend, createMppProxyHandler, createX402ProxyHandler, detectProtocols, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
|
284
|
+
export { ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, TEMPO_NETWORK, appendHistory, calcSpend, createMppProxyHandler, createX402ProxyHandler, detectProtocols, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
package/dist/openclaw/plugin.js
CHANGED
|
@@ -20,7 +20,6 @@ import { HDKey } from "@scure/bip32";
|
|
|
20
20
|
import { mnemonicToSeedSync } from "@scure/bip39";
|
|
21
21
|
import "@scure/bip39/wordlists/english.js";
|
|
22
22
|
import { Type } from "@sinclair/typebox";
|
|
23
|
-
|
|
24
23
|
//#region src/handler.ts
|
|
25
24
|
/**
|
|
26
25
|
* Extract the on-chain transaction signature from an x402 payment response header.
|
|
@@ -58,7 +57,6 @@ function createX402ProxyHandler(opts) {
|
|
|
58
57
|
shiftPayment: () => paymentQueue.shift()
|
|
59
58
|
};
|
|
60
59
|
}
|
|
61
|
-
|
|
62
60
|
//#endregion
|
|
63
61
|
//#region src/lib/config.ts
|
|
64
62
|
const APP_NAME = "x402-proxy";
|
|
@@ -83,19 +81,14 @@ function loadWalletFile() {
|
|
|
83
81
|
return null;
|
|
84
82
|
}
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/history.ts
|
|
89
|
-
const HISTORY_MAX_LINES = 1e3;
|
|
90
|
-
const HISTORY_KEEP_LINES = 500;
|
|
91
84
|
function appendHistory(historyPath, record) {
|
|
92
85
|
try {
|
|
93
86
|
mkdirSync(dirname(historyPath), { recursive: true });
|
|
94
87
|
appendFileSync(historyPath, `${JSON.stringify(record)}\n`);
|
|
95
88
|
if (existsSync(historyPath)) {
|
|
96
|
-
if (statSync(historyPath).size >
|
|
89
|
+
if (statSync(historyPath).size > 1e3 * 200) {
|
|
97
90
|
const lines = readFileSync(historyPath, "utf-8").trimEnd().split("\n");
|
|
98
|
-
if (lines.length >
|
|
91
|
+
if (lines.length > 1e3) writeFileSync(historyPath, `${lines.slice(-500).join("\n")}\n`);
|
|
99
92
|
}
|
|
100
93
|
}
|
|
101
94
|
} catch {}
|
|
@@ -202,7 +195,6 @@ function formatTxLine(r, opts) {
|
|
|
202
195
|
}
|
|
203
196
|
return ` ${timeStr} ${r.ok ? "" : "✗ "}${parts.join(" · ")}`;
|
|
204
197
|
}
|
|
205
|
-
|
|
206
198
|
//#endregion
|
|
207
199
|
//#region src/lib/derive.ts
|
|
208
200
|
/**
|
|
@@ -270,7 +262,6 @@ function checksumAddress(addr) {
|
|
|
270
262
|
for (let i = 0; i < 40; i++) out += Number.parseInt(hash[i], 16) >= 8 ? addr[i].toUpperCase() : addr[i];
|
|
271
263
|
return out;
|
|
272
264
|
}
|
|
273
|
-
|
|
274
265
|
//#endregion
|
|
275
266
|
//#region src/lib/resolve-wallet.ts
|
|
276
267
|
/**
|
|
@@ -341,7 +332,6 @@ function solanaAddressFromKey(keyBytes) {
|
|
|
341
332
|
if (keyBytes.length >= 64) return base58.encode(keyBytes.slice(32));
|
|
342
333
|
return base58.encode(ed25519.getPublicKey(keyBytes));
|
|
343
334
|
}
|
|
344
|
-
|
|
345
335
|
//#endregion
|
|
346
336
|
//#region src/wallet.ts
|
|
347
337
|
/**
|
|
@@ -352,7 +342,6 @@ async function loadSvmWallet(keypairPath) {
|
|
|
352
342
|
const data = JSON.parse(readFileSync(keypairPath, "utf-8"));
|
|
353
343
|
return createKeyPairSignerFromBytes(new Uint8Array(data));
|
|
354
344
|
}
|
|
355
|
-
|
|
356
345
|
//#endregion
|
|
357
346
|
//#region src/openclaw/solana.ts
|
|
358
347
|
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
@@ -444,7 +433,6 @@ async function transferUsdc(signer, rpcUrl, dest, amountRaw) {
|
|
|
444
433
|
const encoded = getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (m) => setTransactionMessageFeePayer(signer.address, m), (m) => appendTransactionMessageInstructions([transferIx], m), (m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m))));
|
|
445
434
|
return await rpc.sendTransaction(encoded, { encoding: "base64" }).send();
|
|
446
435
|
}
|
|
447
|
-
|
|
448
436
|
//#endregion
|
|
449
437
|
//#region src/openclaw/tools.ts
|
|
450
438
|
const SOL_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
@@ -606,7 +594,6 @@ function createPaymentTool(ctx) {
|
|
|
606
594
|
}
|
|
607
595
|
};
|
|
608
596
|
}
|
|
609
|
-
|
|
610
597
|
//#endregion
|
|
611
598
|
//#region src/openclaw/commands.ts
|
|
612
599
|
const HISTORY_PAGE_SIZE = 5;
|
|
@@ -726,7 +713,7 @@ function createWalletCommand(ctx) {
|
|
|
726
713
|
try {
|
|
727
714
|
const snap = await getWalletSnapshot(ctx.rpcUrl, walletAddress, ctx.historyPath);
|
|
728
715
|
const solscanUrl = `https://solscan.io/account/${walletAddress}`;
|
|
729
|
-
const lines = [`x402-proxy v0.9.
|
|
716
|
+
const lines = [`x402-proxy v0.9.2`];
|
|
730
717
|
const defaultModel = ctx.allModels[0];
|
|
731
718
|
if (defaultModel) lines.push("", `**Model** - ${defaultModel.name} (${defaultModel.provider})`);
|
|
732
719
|
lines.push("", `**[Wallet](${solscanUrl})**`, `\`${walletAddress}\``);
|
|
@@ -759,7 +746,6 @@ function createWalletCommand(ctx) {
|
|
|
759
746
|
}
|
|
760
747
|
};
|
|
761
748
|
}
|
|
762
|
-
|
|
763
749
|
//#endregion
|
|
764
750
|
//#region src/openclaw/route.ts
|
|
765
751
|
function createX402RouteHandler(opts) {
|
|
@@ -992,7 +978,6 @@ function createX402RouteHandler(opts) {
|
|
|
992
978
|
}
|
|
993
979
|
};
|
|
994
980
|
}
|
|
995
|
-
|
|
996
981
|
//#endregion
|
|
997
982
|
//#region src/openclaw/plugin.ts
|
|
998
983
|
function parseProviders(config) {
|
|
@@ -1120,6 +1105,5 @@ function register(api) {
|
|
|
1120
1105
|
};
|
|
1121
1106
|
api.registerCommand(createWalletCommand(cmdCtx));
|
|
1122
1107
|
}
|
|
1123
|
-
|
|
1124
1108
|
//#endregion
|
|
1125
|
-
export { register };
|
|
1109
|
+
export { register };
|
|
@@ -1,15 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { d as saveWalletFile, i as getConfigDirShort, n as deriveSolanaKeypair, o as getWalletPath, r as generateMnemonic, s as isConfigured, t as deriveEvmKeypair, u as saveConfig } from "./derive-
|
|
2
|
+
import { d as saveWalletFile, i as getConfigDirShort, l as loadWalletFile, n as deriveSolanaKeypair, o as getWalletPath, r as generateMnemonic, s as isConfigured, t as deriveEvmKeypair, u as saveConfig } from "./derive-EDXzwKW2.js";
|
|
3
3
|
import { buildCommand } from "@stricli/core";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import * as prompts from "@clack/prompts";
|
|
6
|
-
|
|
7
6
|
//#region src/commands/setup.ts
|
|
8
7
|
async function runSetup(opts) {
|
|
8
|
+
const nonInteractive = opts?.nonInteractive ?? false;
|
|
9
|
+
if (nonInteractive && isConfigured() && !opts?.force) {
|
|
10
|
+
const walletFile = loadWalletFile();
|
|
11
|
+
if (walletFile) {
|
|
12
|
+
process.stdout.write(`${JSON.stringify({
|
|
13
|
+
base: walletFile.addresses.evm,
|
|
14
|
+
tempo: walletFile.addresses.evm,
|
|
15
|
+
solana: walletFile.addresses.solana
|
|
16
|
+
})}\n`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
9
20
|
if (isConfigured() && !opts?.force) {
|
|
10
21
|
prompts.log.warn(`Already configured. Wallet at ${pc.dim(getWalletPath())}\nTo reconfigure, run:\n ${pc.cyan("$ npx x402-proxy setup --force")}`);
|
|
11
22
|
return;
|
|
12
23
|
}
|
|
24
|
+
let mnemonic;
|
|
25
|
+
if (nonInteractive) {
|
|
26
|
+
if (opts?.importMnemonic) {
|
|
27
|
+
const words = opts.importMnemonic.trim().split(/\s+/);
|
|
28
|
+
if (words.length !== 12 && words.length !== 24) {
|
|
29
|
+
process.stderr.write("Error: mnemonic must be 12 or 24 words\n");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
mnemonic = opts.importMnemonic.trim();
|
|
33
|
+
} else mnemonic = generateMnemonic();
|
|
34
|
+
const evm = deriveEvmKeypair(mnemonic);
|
|
35
|
+
const sol = deriveSolanaKeypair(mnemonic);
|
|
36
|
+
saveWalletFile({
|
|
37
|
+
version: 1,
|
|
38
|
+
mnemonic,
|
|
39
|
+
addresses: {
|
|
40
|
+
evm: evm.address,
|
|
41
|
+
solana: sol.address
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
saveConfig({ preferredProtocol: "x402" });
|
|
45
|
+
process.stdout.write(`${JSON.stringify({
|
|
46
|
+
base: evm.address,
|
|
47
|
+
tempo: evm.address,
|
|
48
|
+
solana: sol.address
|
|
49
|
+
})}\n`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
13
52
|
prompts.intro(pc.cyan("x402-proxy setup"));
|
|
14
53
|
prompts.log.info("This will generate a single BIP-39 mnemonic that derives wallets for both Solana and EVM chains.");
|
|
15
54
|
const action = await prompts.select({
|
|
@@ -26,7 +65,6 @@ async function runSetup(opts) {
|
|
|
26
65
|
prompts.cancel("Setup cancelled.");
|
|
27
66
|
process.exit(0);
|
|
28
67
|
}
|
|
29
|
-
let mnemonic;
|
|
30
68
|
if (action === "generate") {
|
|
31
69
|
mnemonic = generateMnemonic();
|
|
32
70
|
prompts.log.warn("Write down your mnemonic and store it safely. It will NOT be shown again.");
|
|
@@ -109,22 +147,50 @@ async function runSetup(opts) {
|
|
|
109
147
|
prompts.outro(pc.green("Setup complete!"));
|
|
110
148
|
}
|
|
111
149
|
const setupCommand = buildCommand({
|
|
112
|
-
docs: {
|
|
150
|
+
docs: {
|
|
151
|
+
brief: "Set up x402-proxy wallet (generate new or import existing mnemonic)",
|
|
152
|
+
fullDescription: `Set up x402-proxy wallet interactively, or use --non-interactive for automated environments.
|
|
153
|
+
|
|
154
|
+
Non-interactive mode auto-generates a wallet and outputs JSON to stdout:
|
|
155
|
+
$ npx x402-proxy setup --non-interactive
|
|
156
|
+
{"base":"0x...","tempo":"0x...","solana":"..."}
|
|
157
|
+
|
|
158
|
+
Import an existing mnemonic non-interactively:
|
|
159
|
+
$ npx x402-proxy setup --non-interactive --import-mnemonic "word1 word2 ... word24"
|
|
160
|
+
|
|
161
|
+
If a wallet already exists, --non-interactive outputs the existing addresses.`
|
|
162
|
+
},
|
|
113
163
|
parameters: {
|
|
114
|
-
flags: {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
164
|
+
flags: {
|
|
165
|
+
force: {
|
|
166
|
+
kind: "boolean",
|
|
167
|
+
brief: "Overwrite existing configuration",
|
|
168
|
+
default: false
|
|
169
|
+
},
|
|
170
|
+
nonInteractive: {
|
|
171
|
+
kind: "boolean",
|
|
172
|
+
brief: "Auto-generate wallet and output addresses as JSON (no prompts)",
|
|
173
|
+
default: false
|
|
174
|
+
},
|
|
175
|
+
importMnemonic: {
|
|
176
|
+
kind: "parsed",
|
|
177
|
+
brief: "Import a BIP-39 mnemonic (use with --non-interactive)",
|
|
178
|
+
parse: String,
|
|
179
|
+
optional: true
|
|
180
|
+
}
|
|
181
|
+
},
|
|
119
182
|
positional: {
|
|
120
183
|
kind: "tuple",
|
|
121
184
|
parameters: []
|
|
122
185
|
}
|
|
123
186
|
},
|
|
124
187
|
async func(flags) {
|
|
125
|
-
await runSetup({
|
|
188
|
+
await runSetup({
|
|
189
|
+
force: flags.force,
|
|
190
|
+
nonInteractive: flags.nonInteractive,
|
|
191
|
+
importMnemonic: flags.importMnemonic
|
|
192
|
+
});
|
|
126
193
|
}
|
|
127
194
|
});
|
|
128
|
-
|
|
129
195
|
//#endregion
|
|
130
|
-
export { setupCommand as n, runSetup as t };
|
|
196
|
+
export { setupCommand as n, runSetup as t };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort } from "./derive-
|
|
3
|
-
import { c as resolveWallet, f as formatAmount, g as dim, h as readHistory, m as formatUsdcValue, n as fetchAllBalances, p as formatTxLine, t as balanceLine, u as calcSpend } from "./wallet-
|
|
2
|
+
import { a as getHistoryPath, c as loadConfig, i as getConfigDirShort } from "./derive-EDXzwKW2.js";
|
|
3
|
+
import { c as resolveWallet, f as formatAmount, g as dim, h as readHistory, m as formatUsdcValue, n as fetchAllBalances, p as formatTxLine, t as balanceLine, u as calcSpend } from "./wallet-Bs8cBOv7.js";
|
|
4
4
|
import { buildCommand } from "@stricli/core";
|
|
5
5
|
import pc from "picocolors";
|
|
6
|
-
|
|
7
6
|
//#region src/commands/status.ts
|
|
8
7
|
async function displayStatus() {
|
|
9
8
|
const wallet = resolveWallet();
|
|
@@ -73,6 +72,5 @@ const statusCommand = buildCommand({
|
|
|
73
72
|
console.log();
|
|
74
73
|
}
|
|
75
74
|
});
|
|
76
|
-
|
|
77
75
|
//#endregion
|
|
78
|
-
export { statusCommand as n, displayStatus as t };
|
|
76
|
+
export { statusCommand as n, displayStatus as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as getHistoryPath, l as loadWalletFile, n as deriveSolanaKeypair, t as deriveEvmKeypair } from "./derive-
|
|
2
|
+
import { a as getHistoryPath, l as loadWalletFile, n as deriveSolanaKeypair, t as deriveEvmKeypair } from "./derive-EDXzwKW2.js";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import { buildCommand } from "@stricli/core";
|
|
5
5
|
import pc from "picocolors";
|
|
@@ -14,7 +14,6 @@ import { createPublicClient, http } from "viem";
|
|
|
14
14
|
import { privateKeyToAccount } from "viem/accounts";
|
|
15
15
|
import { base } from "viem/chains";
|
|
16
16
|
import { address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit";
|
|
17
|
-
|
|
18
17
|
//#region src/lib/output.ts
|
|
19
18
|
function isTTY() {
|
|
20
19
|
return !!process.stderr.isTTY;
|
|
@@ -31,19 +30,14 @@ function error(msg) {
|
|
|
31
30
|
function dim(msg) {
|
|
32
31
|
process.stderr.write(`${isTTY() ? pc.dim(msg) : msg}\n`);
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region src/history.ts
|
|
37
|
-
const HISTORY_MAX_LINES = 1e3;
|
|
38
|
-
const HISTORY_KEEP_LINES = 500;
|
|
39
33
|
function appendHistory(historyPath, record) {
|
|
40
34
|
try {
|
|
41
35
|
mkdirSync(dirname(historyPath), { recursive: true });
|
|
42
36
|
appendFileSync(historyPath, `${JSON.stringify(record)}\n`);
|
|
43
37
|
if (existsSync(historyPath)) {
|
|
44
|
-
if (statSync(historyPath).size >
|
|
38
|
+
if (statSync(historyPath).size > 1e3 * 200) {
|
|
45
39
|
const lines = readFileSync(historyPath, "utf-8").trimEnd().split("\n");
|
|
46
|
-
if (lines.length >
|
|
40
|
+
if (lines.length > 1e3) writeFileSync(historyPath, `${lines.slice(-500).join("\n")}\n`);
|
|
47
41
|
}
|
|
48
42
|
}
|
|
49
43
|
} catch {}
|
|
@@ -157,7 +151,6 @@ function formatTxLine(r, opts) {
|
|
|
157
151
|
}
|
|
158
152
|
return ` ${timeStr} ${r.ok ? "" : "✗ "}${parts.join(" · ")}`;
|
|
159
153
|
}
|
|
160
|
-
|
|
161
154
|
//#endregion
|
|
162
155
|
//#region src/lib/resolve-wallet.ts
|
|
163
156
|
/**
|
|
@@ -312,7 +305,6 @@ async function buildX402Client(wallet, opts) {
|
|
|
312
305
|
});
|
|
313
306
|
return client;
|
|
314
307
|
}
|
|
315
|
-
|
|
316
308
|
//#endregion
|
|
317
309
|
//#region src/commands/wallet.ts
|
|
318
310
|
const BASE_RPC = "https://mainnet.base.org";
|
|
@@ -454,6 +446,5 @@ const walletInfoCommand = buildCommand({
|
|
|
454
446
|
console.log();
|
|
455
447
|
}
|
|
456
448
|
});
|
|
457
|
-
|
|
458
449
|
//#endregion
|
|
459
|
-
export { error as _, fetchTempoBalances as a, warn as b, resolveWallet as c, displayNetwork as d, formatAmount as f, dim as g, readHistory as h, fetchSolanaBalances as i, appendHistory as l, formatUsdcValue as m, fetchAllBalances as n, walletInfoCommand as o, formatTxLine as p, fetchEvmBalances as r, buildX402Client as s, balanceLine as t, calcSpend as u, info as v, isTTY as y };
|
|
450
|
+
export { error as _, fetchTempoBalances as a, warn as b, resolveWallet as c, displayNetwork as d, formatAmount as f, dim as g, readHistory as h, fetchSolanaBalances as i, appendHistory as l, formatUsdcValue as m, fetchAllBalances as n, walletInfoCommand as o, formatTxLine as p, fetchEvmBalances as r, buildX402Client as s, balanceLine as t, calcSpend as u, info as v, isTTY as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x402-proxy",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "curl for x402 paid APIs. Auto-pays any endpoint on Base, Solana, and Tempo. Also works as an OpenClaw plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -28,24 +28,24 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@clack/prompts": "^1.1.0",
|
|
30
30
|
"@getmcp/generators": "^0.10.1",
|
|
31
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
32
32
|
"@noble/curves": "^2.0.1",
|
|
33
33
|
"@noble/hashes": "^2.0.1",
|
|
34
34
|
"@scure/base": "^2.0.0",
|
|
35
35
|
"@scure/bip32": "^2.0.1",
|
|
36
36
|
"@scure/bip39": "^2.0.1",
|
|
37
37
|
"@sinclair/typebox": "^0.34.48",
|
|
38
|
-
"@solana/kit": "^6.
|
|
38
|
+
"@solana/kit": "^6.5.0",
|
|
39
39
|
"@stricli/core": "^1.2.6",
|
|
40
|
-
"@x402/evm": "^2.
|
|
41
|
-
"@x402/fetch": "^2.
|
|
42
|
-
"@x402/mcp": "^2.
|
|
43
|
-
"@x402/svm": "^2.
|
|
44
|
-
"ethers": "^6.
|
|
40
|
+
"@x402/evm": "^2.8.0",
|
|
41
|
+
"@x402/fetch": "^2.8.0",
|
|
42
|
+
"@x402/mcp": "^2.8.0",
|
|
43
|
+
"@x402/svm": "^2.8.0",
|
|
44
|
+
"ethers": "^6.16.0",
|
|
45
45
|
"mppx": "^0.4.9",
|
|
46
46
|
"picocolors": "^1.1.1",
|
|
47
|
-
"viem": "^2.
|
|
48
|
-
"yaml": "^2.8.
|
|
47
|
+
"viem": "^2.47.6",
|
|
48
|
+
"yaml": "^2.8.3"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"openclaw": ">=2026.3.8"
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@types/node": "^
|
|
60
|
-
"openclaw": "
|
|
61
|
-
"publint": "^0.3.
|
|
62
|
-
"tsdown": "^0.
|
|
63
|
-
"typescript": "^5.9.
|
|
64
|
-
"vitest": "^4.
|
|
59
|
+
"@types/node": "^25.5.0",
|
|
60
|
+
"openclaw": "^2026.3.24",
|
|
61
|
+
"publint": "^0.3.18",
|
|
62
|
+
"tsdown": "^0.21.5",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vitest": "^4.1.1"
|
|
65
65
|
},
|
|
66
66
|
"files": [
|
|
67
67
|
"dist/**",
|
package/skills/SKILL.md
CHANGED
|
@@ -74,7 +74,7 @@ x402-proxy wallet export-key mnemonic # bare mnemonic to stdout
|
|
|
74
74
|
Quick setup (auto-detects installed AI clients):
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
|
-
x402-proxy mcp add
|
|
77
|
+
x402-proxy mcp add surf https://surf.cascade.fyi/mcp
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
Or drop into your client config manually:
|
|
@@ -82,18 +82,28 @@ Or drop into your client config manually:
|
|
|
82
82
|
```json
|
|
83
83
|
{
|
|
84
84
|
"mcpServers": {
|
|
85
|
-
"
|
|
85
|
+
"surf": {
|
|
86
86
|
"command": "npx",
|
|
87
|
-
"args": ["x402-proxy", "mcp", "https://
|
|
88
|
-
"env": {
|
|
89
|
-
"X402_PROXY_WALLET_MNEMONIC": "your 24 words here"
|
|
90
|
-
}
|
|
87
|
+
"args": ["-y", "x402-proxy", "mcp", "https://surf.cascade.fyi/mcp"]
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
91
|
```
|
|
95
92
|
|
|
96
|
-
|
|
93
|
+
For OpenClaw:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
openclaw mcp set surf '{"command":"npx","args":["-y","x402-proxy","mcp","https://surf.cascade.fyi/mcp"]}'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The wallet is auto-generated on first run and stored at `~/.config/x402-proxy/wallet.json`. No env vars needed. The proxy intercepts 402 responses, pays automatically, forwards the result. Supports StreamableHTTP and SSE.
|
|
100
|
+
|
|
101
|
+
For non-interactive setup (e.g. automated provisioning):
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx x402-proxy setup --non-interactive
|
|
105
|
+
# outputs: {"evm":"0x...","solana":"..."}
|
|
106
|
+
```
|
|
97
107
|
|
|
98
108
|
## Wallet & env vars
|
|
99
109
|
|
package/dist/setup-CJgw4opQ.js
DELETED
package/dist/status-BkURZYDA.js
DELETED
package/dist/wallet-BM0ngyqk.js
DELETED