x402-proxy 0.5.2 → 0.7.0
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 +37 -1
- package/README.md +20 -2
- package/dist/bin/cli.js +518 -168
- package/dist/{derive-CISr_ond.js → derive-ibF2UinV.js} +2 -2
- package/dist/index.d.ts +43 -8
- package/dist/index.js +108 -13
- package/dist/openclaw/plugin.d.ts +55 -0
- package/dist/openclaw/plugin.js +1120 -0
- package/dist/openclaw.plugin.json +28 -0
- package/dist/{setup-gla-Qyqi.js → setup-hJGkO2Lo.js} +1 -1
- package/dist/setup-j_xQ14-4.js +4 -0
- package/dist/{status-BoH_1kIH.js → status-JNGv2Ghp.js} +12 -6
- package/dist/{status-BVIU3-b6.js → status-w5y-fhhe.js} +1 -1
- package/dist/wallet-DjixXCHy.js +4 -0
- package/dist/{wallet-BMYYtAP6.js → wallet-DxKCHa7U.js} +45 -11
- package/openclaw.plugin.json +28 -0
- package/package.json +29 -4
- package/skills/SKILL.md +22 -7
- package/dist/setup-Crq9TylJ.js +0 -4
- package/dist/wallet-BoY0fgX7.js +0 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
3
|
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
5
|
import { parse, stringify } from "yaml";
|
|
6
6
|
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
7
7
|
import { base58 } from "@scure/base";
|
|
@@ -158,4 +158,4 @@ function checksumAddress(addr) {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
//#endregion
|
|
161
|
-
export {
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,27 @@ import { KeyPairSigner } from "@solana/kit";
|
|
|
5
5
|
|
|
6
6
|
//#region src/handler.d.ts
|
|
7
7
|
type PaymentInfo = {
|
|
8
|
+
protocol: "x402";
|
|
8
9
|
network: string | undefined;
|
|
9
10
|
payTo: string | undefined; /** Raw amount in base units as returned by x402 (e.g. "50000" for 0.05 USDC) */
|
|
10
11
|
amount: string | undefined;
|
|
11
12
|
asset: string | undefined;
|
|
12
13
|
};
|
|
14
|
+
type MppPaymentInfo = {
|
|
15
|
+
protocol: "mpp";
|
|
16
|
+
network: string;
|
|
17
|
+
amount?: string;
|
|
18
|
+
intent?: string;
|
|
19
|
+
channelId?: string;
|
|
20
|
+
receipt?: {
|
|
21
|
+
method: string;
|
|
22
|
+
reference: string;
|
|
23
|
+
status: string;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
acceptedCumulative?: string;
|
|
26
|
+
txHash?: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
13
29
|
type X402ProxyOptions = {
|
|
14
30
|
client: x402Client$1;
|
|
15
31
|
};
|
|
@@ -17,20 +33,39 @@ type X402ProxyHandler = {
|
|
|
17
33
|
/** Wrapped fetch with x402 payment handling */x402Fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>; /** Shift the latest payment info from the queue (call after x402Fetch) */
|
|
18
34
|
shiftPayment: () => PaymentInfo | undefined;
|
|
19
35
|
};
|
|
36
|
+
type MppProxyHandler = {
|
|
37
|
+
/** Payment-aware fetch that handles 402 + WWW-Authenticate automatically */fetch: (input: string | URL, init?: RequestInit) => Promise<Response>; /** SSE streaming with mid-stream voucher cycling */
|
|
38
|
+
sse: (input: string | URL, init?: RequestInit) => Promise<AsyncIterable<string>>; /** Shift the latest payment info from the queue */
|
|
39
|
+
shiftPayment: () => MppPaymentInfo | undefined; /** Settle any active session channel */
|
|
40
|
+
close: () => Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
type DetectedProtocols = {
|
|
43
|
+
x402: boolean;
|
|
44
|
+
mpp: boolean;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Detect which payment protocols a 402 response advertises.
|
|
48
|
+
* - x402: PAYMENT-REQUIRED or X-PAYMENT-REQUIRED header
|
|
49
|
+
* - MPP: WWW-Authenticate header with Payment scheme
|
|
50
|
+
*/
|
|
51
|
+
declare function detectProtocols(response: Response): DetectedProtocols;
|
|
20
52
|
/**
|
|
21
53
|
* Extract the on-chain transaction signature from an x402 payment response header.
|
|
22
54
|
*/
|
|
23
55
|
declare function extractTxSignature(response: Response): string | undefined;
|
|
24
56
|
/**
|
|
25
57
|
* Create an x402 proxy handler that wraps fetch with automatic payment.
|
|
26
|
-
*
|
|
27
|
-
* Chain-agnostic: accepts a pre-configured x402Client with any registered
|
|
28
|
-
* schemes (SVM, EVM, etc). The handler captures payment info via the
|
|
29
|
-
* onAfterPaymentCreation hook. Callers use `x402Fetch` for requests that
|
|
30
|
-
* may require x402 payment, and `shiftPayment` to retrieve captured
|
|
31
|
-
* payment info after each call.
|
|
32
58
|
*/
|
|
33
59
|
declare function createX402ProxyHandler(opts: X402ProxyOptions): X402ProxyHandler;
|
|
60
|
+
declare const TEMPO_NETWORK = "eip155:4217";
|
|
61
|
+
/**
|
|
62
|
+
* Create an MPP proxy handler using mppx client.
|
|
63
|
+
* Dynamically imports mppx/client to keep startup fast.
|
|
64
|
+
*/
|
|
65
|
+
declare function createMppProxyHandler(opts: {
|
|
66
|
+
evmKey: string;
|
|
67
|
+
maxDeposit?: string;
|
|
68
|
+
}): Promise<MppProxyHandler>;
|
|
34
69
|
//#endregion
|
|
35
70
|
//#region src/history.d.ts
|
|
36
71
|
declare const HISTORY_MAX_LINES = 1000;
|
|
@@ -38,7 +73,7 @@ declare const HISTORY_KEEP_LINES = 500;
|
|
|
38
73
|
type TxRecord = {
|
|
39
74
|
t: number;
|
|
40
75
|
ok: boolean;
|
|
41
|
-
kind: "x402_inference" | "x402_payment" | "transfer" | "buy" | "sell" | "mint" | "swap";
|
|
76
|
+
kind: "x402_inference" | "x402_payment" | "mpp_payment" | "transfer" | "buy" | "sell" | "mint" | "swap";
|
|
42
77
|
net: string;
|
|
43
78
|
from: string;
|
|
44
79
|
to?: string;
|
|
@@ -82,4 +117,4 @@ declare function loadSvmWallet(keypairPath: string): Promise<KeyPairSigner>;
|
|
|
82
117
|
*/
|
|
83
118
|
declare function loadEvmWallet(keyPath: string): ClientEvmSigner$1;
|
|
84
119
|
//#endregion
|
|
85
|
-
export { type ClientEvmSigner, ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, type PaymentInfo, type TxRecord, type X402ProxyHandler, type X402ProxyOptions, appendHistory, calcSpend, createX402ProxyHandler, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
|
120
|
+
export { type ClientEvmSigner, type DetectedProtocols, ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, type MppPaymentInfo, type MppProxyHandler, type PaymentInfo, TEMPO_NETWORK, type TxRecord, type X402ProxyHandler, type X402ProxyOptions, appendHistory, calcSpend, createMppProxyHandler, createX402ProxyHandler, detectProtocols, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
1
|
import { ExactEvmScheme, toClientEvmSigner, toClientEvmSigner as toClientEvmSigner$1 } from "@x402/evm";
|
|
2
2
|
import { decodePaymentResponseHeader, wrapFetchWithPayment, x402Client } from "@x402/fetch";
|
|
3
3
|
import { ExactSvmScheme } from "@x402/svm/exact/client";
|
|
4
|
-
import { appendFileSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname } from "node:path";
|
|
5
6
|
import { createKeyPairSignerFromBytes } from "@solana/kit";
|
|
6
7
|
import { privateKeyToAccount } from "viem/accounts";
|
|
7
8
|
|
|
8
9
|
//#region src/handler.ts
|
|
9
10
|
/**
|
|
11
|
+
* Detect which payment protocols a 402 response advertises.
|
|
12
|
+
* - x402: PAYMENT-REQUIRED or X-PAYMENT-REQUIRED header
|
|
13
|
+
* - MPP: WWW-Authenticate header with Payment scheme
|
|
14
|
+
*/
|
|
15
|
+
function detectProtocols(response) {
|
|
16
|
+
const pr = response.headers.get("PAYMENT-REQUIRED") ?? response.headers.get("X-PAYMENT-REQUIRED");
|
|
17
|
+
const wwwAuth = response.headers.get("WWW-Authenticate");
|
|
18
|
+
return {
|
|
19
|
+
x402: !!pr,
|
|
20
|
+
mpp: !!(wwwAuth && /^Payment\b/i.test(wwwAuth.trim()))
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
10
24
|
* Extract the on-chain transaction signature from an x402 payment response header.
|
|
11
25
|
*/
|
|
12
26
|
function extractTxSignature(response) {
|
|
13
|
-
const
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
const x402Header = response.headers.get("PAYMENT-RESPONSE") ?? response.headers.get("X-PAYMENT-RESPONSE");
|
|
28
|
+
if (x402Header) try {
|
|
29
|
+
return decodePaymentResponseHeader(x402Header).transaction ?? void 0;
|
|
30
|
+
} catch {}
|
|
31
|
+
const mppHeader = response.headers.get("Payment-Receipt");
|
|
32
|
+
if (mppHeader) try {
|
|
33
|
+
return JSON.parse(Buffer.from(mppHeader, "base64url").toString()).reference ?? void 0;
|
|
17
34
|
} catch {
|
|
18
35
|
return;
|
|
19
36
|
}
|
|
20
37
|
}
|
|
21
38
|
/**
|
|
22
39
|
* Create an x402 proxy handler that wraps fetch with automatic payment.
|
|
23
|
-
*
|
|
24
|
-
* Chain-agnostic: accepts a pre-configured x402Client with any registered
|
|
25
|
-
* schemes (SVM, EVM, etc). The handler captures payment info via the
|
|
26
|
-
* onAfterPaymentCreation hook. Callers use `x402Fetch` for requests that
|
|
27
|
-
* may require x402 payment, and `shiftPayment` to retrieve captured
|
|
28
|
-
* payment info after each call.
|
|
29
40
|
*/
|
|
30
41
|
function createX402ProxyHandler(opts) {
|
|
31
42
|
const { client } = opts;
|
|
@@ -33,6 +44,7 @@ function createX402ProxyHandler(opts) {
|
|
|
33
44
|
client.onAfterPaymentCreation(async (hookCtx) => {
|
|
34
45
|
const raw = hookCtx.selectedRequirements.amount;
|
|
35
46
|
paymentQueue.push({
|
|
47
|
+
protocol: "x402",
|
|
36
48
|
network: hookCtx.selectedRequirements.network,
|
|
37
49
|
payTo: hookCtx.selectedRequirements.payTo,
|
|
38
50
|
amount: raw,
|
|
@@ -44,6 +56,84 @@ function createX402ProxyHandler(opts) {
|
|
|
44
56
|
shiftPayment: () => paymentQueue.shift()
|
|
45
57
|
};
|
|
46
58
|
}
|
|
59
|
+
const TEMPO_NETWORK = "eip155:4217";
|
|
60
|
+
/**
|
|
61
|
+
* Create an MPP proxy handler using mppx client.
|
|
62
|
+
* Dynamically imports mppx/client to keep startup fast.
|
|
63
|
+
*/
|
|
64
|
+
async function createMppProxyHandler(opts) {
|
|
65
|
+
const { Mppx, tempo } = await import("mppx/client");
|
|
66
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
67
|
+
const account = privateKeyToAccount(opts.evmKey);
|
|
68
|
+
const maxDeposit = opts.maxDeposit ?? "1";
|
|
69
|
+
const paymentQueue = [];
|
|
70
|
+
const mppx = Mppx.create({
|
|
71
|
+
methods: [tempo({
|
|
72
|
+
account,
|
|
73
|
+
maxDeposit
|
|
74
|
+
})],
|
|
75
|
+
polyfill: false
|
|
76
|
+
});
|
|
77
|
+
let session;
|
|
78
|
+
return {
|
|
79
|
+
async fetch(input, init) {
|
|
80
|
+
const response = await mppx.fetch(typeof input === "string" ? input : input.toString(), init);
|
|
81
|
+
const receiptHeader = response.headers.get("Payment-Receipt");
|
|
82
|
+
if (receiptHeader) try {
|
|
83
|
+
const receipt = JSON.parse(Buffer.from(receiptHeader, "base64url").toString());
|
|
84
|
+
paymentQueue.push({
|
|
85
|
+
protocol: "mpp",
|
|
86
|
+
network: TEMPO_NETWORK,
|
|
87
|
+
receipt
|
|
88
|
+
});
|
|
89
|
+
} catch {
|
|
90
|
+
paymentQueue.push({
|
|
91
|
+
protocol: "mpp",
|
|
92
|
+
network: TEMPO_NETWORK
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return response;
|
|
96
|
+
},
|
|
97
|
+
async sse(input, init) {
|
|
98
|
+
session ??= tempo.session({
|
|
99
|
+
account,
|
|
100
|
+
maxDeposit
|
|
101
|
+
});
|
|
102
|
+
const url = typeof input === "string" ? input : input.toString();
|
|
103
|
+
const iterable = await session.sse(url, init);
|
|
104
|
+
paymentQueue.push({
|
|
105
|
+
protocol: "mpp",
|
|
106
|
+
network: TEMPO_NETWORK,
|
|
107
|
+
intent: "session"
|
|
108
|
+
});
|
|
109
|
+
return iterable;
|
|
110
|
+
},
|
|
111
|
+
shiftPayment: () => paymentQueue.shift(),
|
|
112
|
+
async close() {
|
|
113
|
+
if (session?.opened) {
|
|
114
|
+
const receipt = await session.close();
|
|
115
|
+
if (receipt) {
|
|
116
|
+
const spentUsdc = receipt.spent ? (Number(receipt.spent) / 1e6).toString() : void 0;
|
|
117
|
+
paymentQueue.push({
|
|
118
|
+
protocol: "mpp",
|
|
119
|
+
network: TEMPO_NETWORK,
|
|
120
|
+
intent: "session",
|
|
121
|
+
amount: spentUsdc,
|
|
122
|
+
channelId: session.channelId ?? void 0,
|
|
123
|
+
receipt: {
|
|
124
|
+
method: receipt.method,
|
|
125
|
+
reference: receipt.reference,
|
|
126
|
+
status: receipt.status,
|
|
127
|
+
timestamp: receipt.timestamp,
|
|
128
|
+
acceptedCumulative: receipt.acceptedCumulative,
|
|
129
|
+
txHash: receipt.txHash
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
47
137
|
|
|
48
138
|
//#endregion
|
|
49
139
|
//#region src/history.ts
|
|
@@ -51,6 +141,7 @@ const HISTORY_MAX_LINES = 1e3;
|
|
|
51
141
|
const HISTORY_KEEP_LINES = 500;
|
|
52
142
|
function appendHistory(historyPath, record) {
|
|
53
143
|
try {
|
|
144
|
+
mkdirSync(dirname(historyPath), { recursive: true });
|
|
54
145
|
appendFileSync(historyPath, `${JSON.stringify(record)}\n`);
|
|
55
146
|
if (existsSync(historyPath)) {
|
|
56
147
|
if (statSync(historyPath).size > HISTORY_MAX_LINES * 200) {
|
|
@@ -111,6 +202,7 @@ function formatAmount(amount, token) {
|
|
|
111
202
|
const KIND_LABELS = {
|
|
112
203
|
x402_inference: "inference",
|
|
113
204
|
x402_payment: "payment",
|
|
205
|
+
mpp_payment: "mpp payment",
|
|
114
206
|
transfer: "transfer",
|
|
115
207
|
buy: "buy",
|
|
116
208
|
sell: "sell",
|
|
@@ -119,7 +211,9 @@ const KIND_LABELS = {
|
|
|
119
211
|
};
|
|
120
212
|
function explorerUrl(net, tx) {
|
|
121
213
|
if (net.startsWith("eip155:")) {
|
|
122
|
-
|
|
214
|
+
const chainId = net.split(":")[1];
|
|
215
|
+
if (chainId === "4217") return `https://explore.mainnet.tempo.xyz/tx/${tx}`;
|
|
216
|
+
if (chainId === "8453") return `https://basescan.org/tx/${tx}`;
|
|
123
217
|
return `https://basescan.org/tx/${tx}`;
|
|
124
218
|
}
|
|
125
219
|
return `https://solscan.io/tx/${tx}`;
|
|
@@ -133,6 +227,7 @@ function shortModel(model) {
|
|
|
133
227
|
}
|
|
134
228
|
function shortNetwork(net) {
|
|
135
229
|
if (net === "eip155:8453") return "base";
|
|
230
|
+
if (net === "eip155:4217") return "tempo";
|
|
136
231
|
if (net.startsWith("eip155:")) return `evm:${net.split(":")[1]}`;
|
|
137
232
|
if (net.startsWith("solana:")) return "sol";
|
|
138
233
|
return net;
|
|
@@ -178,4 +273,4 @@ function loadEvmWallet(keyPath) {
|
|
|
178
273
|
}
|
|
179
274
|
|
|
180
275
|
//#endregion
|
|
181
|
-
export { ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, appendHistory, calcSpend, createX402ProxyHandler, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
|
276
|
+
export { ExactEvmScheme, ExactSvmScheme, HISTORY_KEEP_LINES, HISTORY_MAX_LINES, TEMPO_NETWORK, appendHistory, calcSpend, createMppProxyHandler, createX402ProxyHandler, detectProtocols, explorerUrl, extractTxSignature, formatTxLine, loadEvmWallet, loadSvmWallet, readHistory, toClientEvmSigner, x402Client };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { x402Client } from "@x402/fetch";
|
|
2
|
+
//#region src/openclaw/tools.d.ts
|
|
3
|
+
type ModelEntry = {
|
|
4
|
+
provider: string;
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
maxTokens: number;
|
|
8
|
+
reasoning: boolean;
|
|
9
|
+
input: string[];
|
|
10
|
+
cost: {
|
|
11
|
+
input: number;
|
|
12
|
+
output: number;
|
|
13
|
+
cacheRead: number;
|
|
14
|
+
cacheWrite: number;
|
|
15
|
+
};
|
|
16
|
+
contextWindow: number;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/openclaw/plugin.d.ts
|
|
20
|
+
type OpenClawPluginApi = {
|
|
21
|
+
pluginConfig?: Record<string, unknown>;
|
|
22
|
+
logger: {
|
|
23
|
+
info: (msg: string) => void;
|
|
24
|
+
error: (msg: string) => void;
|
|
25
|
+
};
|
|
26
|
+
registerProvider: (provider: {
|
|
27
|
+
id: string;
|
|
28
|
+
label: string;
|
|
29
|
+
auth: unknown[];
|
|
30
|
+
models: {
|
|
31
|
+
baseUrl: string;
|
|
32
|
+
api: string;
|
|
33
|
+
authHeader: boolean;
|
|
34
|
+
models: Array<Omit<ModelEntry, "provider"> & {
|
|
35
|
+
input: Array<"text" | "image">;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
38
|
+
}) => void;
|
|
39
|
+
registerTool: (tool: unknown) => void;
|
|
40
|
+
registerCommand: (command: unknown) => void;
|
|
41
|
+
registerService: (service: {
|
|
42
|
+
id: string;
|
|
43
|
+
start: () => Promise<void>;
|
|
44
|
+
stop: () => Promise<void>;
|
|
45
|
+
}) => void;
|
|
46
|
+
registerHttpRoute: (params: {
|
|
47
|
+
path: string;
|
|
48
|
+
match: string;
|
|
49
|
+
auth: string;
|
|
50
|
+
handler: (req: unknown, res: unknown) => Promise<void>;
|
|
51
|
+
}) => void;
|
|
52
|
+
};
|
|
53
|
+
declare function register(api: OpenClawPluginApi): void;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { register };
|