x402-proxy-openclaw 0.10.12 → 0.11.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/dist/commands.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { generateMnemonic, isValidMnemonic } from "./lib/derive.js";
2
+ import { createWalletFile, getWalletPath, saveWalletFile } from "./lib/config.js";
1
3
  import { appendHistory, formatTxLine, readHistory } from "./history.js";
2
4
  import { checkAtaExists, getUsdcBalance, transferUsdc } from "./solana.js";
3
5
  import { SOL_MAINNET, getWalletSnapshot } from "./tools.js";
@@ -108,6 +110,43 @@ function handleHistory(histPath, page) {
108
110
  if (nav.length > 0) lines.push("", nav.join(" · "));
109
111
  return { text: lines.join("\n") };
110
112
  }
113
+ /** Parse mnemonic from import args, stripping surrounding quotes. Returns error string or clean mnemonic. */
114
+ function parseMnemonicImport(parts) {
115
+ const words = parts.join(" ").replace(/^["'""\u201C\u201D]+|["'""\u201C\u201D]+$/g, "").split(/\s+/).filter(Boolean);
116
+ if (words.length !== 12 && words.length !== 24) return { error: `Mnemonic must be 12 or 24 words (got ${words.length}).\nUsage: \`/x_wallet setup import word1 word2 ... word24\`` };
117
+ const mnemonic = words.join(" ");
118
+ if (!isValidMnemonic(mnemonic)) return { error: "Invalid BIP-39 mnemonic. Check the words and try again." };
119
+ return { mnemonic };
120
+ }
121
+ async function handleSetup(ctx, parts) {
122
+ const action = parts[0]?.toLowerCase();
123
+ let mnemonic = null;
124
+ if (action === "generate") mnemonic = generateMnemonic();
125
+ else if (action === "import") {
126
+ const result = parseMnemonicImport(parts.slice(1));
127
+ if ("error" in result) return { text: result.error };
128
+ mnemonic = result.mnemonic;
129
+ }
130
+ if (!mnemonic) return { text: [
131
+ "No wallet configured.",
132
+ "",
133
+ " `/x_wallet setup generate` - generate a new wallet",
134
+ " `/x_wallet setup import <mnemonic>` - import a BIP-39 mnemonic (12 or 24 words)"
135
+ ].join("\n") };
136
+ const wallet = createWalletFile(mnemonic);
137
+ saveWalletFile(wallet);
138
+ await ctx.ensureReady({ reload: true });
139
+ const lines = [
140
+ action === "generate" ? "Wallet generated." : "Wallet imported.",
141
+ "",
142
+ `**EVM**: \`${wallet.addresses.evm}\``,
143
+ `**Solana**: \`${wallet.addresses.solana}\``,
144
+ "",
145
+ `Saved to \`${getWalletPath()}\``
146
+ ];
147
+ if (action === "generate") lines.push("Fund these addresses with USDC to start using paid tools.", "", "Recover mnemonic later: `npx x402-proxy wallet export-key mnemonic`");
148
+ return { text: lines.join("\n") };
149
+ }
111
150
  function createWalletCommand(ctx) {
112
151
  return {
113
152
  name: "x_wallet",
@@ -116,11 +155,13 @@ function createWalletCommand(ctx) {
116
155
  requireAuth: true,
117
156
  handler: async (cmdCtx) => {
118
157
  await ctx.ensureReady();
158
+ const parts = (cmdCtx.args?.trim() ?? "").split(/\s+/).filter(Boolean);
159
+ const sub = parts[0]?.toLowerCase();
160
+ if (sub === "setup") return handleSetup(ctx, parts.slice(1));
119
161
  const solanaWallet = ctx.getSolanaWalletAddress();
120
162
  const evmWallet = ctx.getEvmWalletAddress();
121
- if (!solanaWallet && !evmWallet) return { text: "Wallet not configured yet.\nRun `x402-proxy setup` or set `X402_PROXY_WALLET_MNEMONIC` on the gateway host." };
122
- const parts = (cmdCtx.args?.trim() ?? "").split(/\s+/).filter(Boolean);
123
- if (parts[0]?.toLowerCase() === "history") {
163
+ if (!solanaWallet && !evmWallet) return handleSetup(ctx, []);
164
+ if (sub === "history") {
124
165
  const pageArg = parts[1];
125
166
  const page = pageArg ? Math.max(1, Number.parseInt(pageArg, 10) || 1) : 1;
126
167
  return handleHistory(ctx.historyPath, page);
@@ -128,9 +169,7 @@ function createWalletCommand(ctx) {
128
169
  if (parts[0]?.toLowerCase() === "send") return { text: "Use `/x_send <amount|all> <address>` for transfers." };
129
170
  try {
130
171
  const snap = await getWalletSnapshot(ctx.rpcUrl, solanaWallet, evmWallet, ctx.historyPath);
131
- const lines = [`x402-proxy v0.10.12`];
132
- const defaultModel = ctx.allModels[0];
133
- if (defaultModel) lines.push("", `**Model** - ${defaultModel.name} (${defaultModel.provider})`);
172
+ const lines = [`x402-proxy v0.11.2`];
134
173
  lines.push("", `**Protocol** - ${ctx.getDefaultRequestProtocol()}`);
135
174
  lines.push(`MPP session budget: ${ctx.getDefaultMppSessionBudget()} USDC`);
136
175
  lines.push(`MPP ready: ${evmWallet ? "yes" : "no"}`);
package/dist/handler.js CHANGED
@@ -1,6 +1,10 @@
1
+ import { clearSession, saveSession } from "./lib/config.js";
1
2
  import { getMppVoucherHeadroomUsdc, isDebugEnabled } from "./lib/env.js";
2
3
  import { decodePaymentResponseHeader, wrapFetchWithPayment } from "@x402/fetch";
4
+ import { Mppx, tempo } from "mppx/client";
5
+ import { Session } from "mppx/tempo";
3
6
  import { parseUnits } from "viem";
7
+ import { privateKeyToAccount } from "viem/accounts";
4
8
  //#region packages/x402-proxy/src/handler.ts
5
9
  /**
6
10
  * Extract the on-chain transaction signature from an x402 payment response header.
@@ -58,13 +62,8 @@ function parseVoucherHeadroom(value) {
58
62
  }
59
63
  /**
60
64
  * Create an MPP proxy handler using mppx client.
61
- * Dynamically imports mppx/client to keep startup fast.
62
65
  */
63
66
  async function createMppProxyHandler(opts) {
64
- const { Mppx, tempo } = await import("mppx/client");
65
- const { Session } = await import("mppx/tempo");
66
- const { privateKeyToAccount } = await import("viem/accounts");
67
- const { saveSession, clearSession } = await import("./lib/config.js");
68
67
  const account = privateKeyToAccount(opts.evmKey);
69
68
  const maxDeposit = opts.maxDeposit ?? "1";
70
69
  const voucherHeadroomRaw = parseVoucherHeadroom(getMppVoucherHeadroomUsdc());
@@ -1,3 +1,4 @@
1
+ import { deriveEvmKeypair, deriveSolanaKeypair } from "./derive.js";
1
2
  import os from "node:os";
2
3
  import path from "node:path";
3
4
  import fs from "node:fs";
@@ -31,6 +32,25 @@ function loadWalletFile() {
31
32
  return null;
32
33
  }
33
34
  }
35
+ function createWalletFile(mnemonic) {
36
+ const evm = deriveEvmKeypair(mnemonic);
37
+ const sol = deriveSolanaKeypair(mnemonic);
38
+ return {
39
+ version: 1,
40
+ mnemonic,
41
+ addresses: {
42
+ evm: evm.address,
43
+ solana: sol.address
44
+ }
45
+ };
46
+ }
47
+ function saveWalletFile(wallet) {
48
+ ensureConfigDir();
49
+ fs.writeFileSync(getWalletPath(), JSON.stringify(wallet, null, 2), {
50
+ mode: 384,
51
+ encoding: "utf-8"
52
+ });
53
+ }
34
54
  function getSessionPath() {
35
55
  return path.join(getConfigDir(), "session.json");
36
56
  }
@@ -44,4 +64,4 @@ function clearSession() {
44
64
  } catch {}
45
65
  }
46
66
  //#endregion
47
- export { clearSession, ensureConfigDir, getDebugLogPath, getHistoryPath, loadWalletFile, saveSession };
67
+ export { clearSession, createWalletFile, ensureConfigDir, getDebugLogPath, getHistoryPath, getWalletPath, loadWalletFile, saveSession, saveWalletFile };
@@ -1,12 +1,12 @@
1
1
  import { ed25519 } from "@noble/curves/ed25519.js";
2
- import { base58 } from "@scure/base";
3
2
  import { secp256k1 } from "@noble/curves/secp256k1.js";
4
3
  import { hmac } from "@noble/hashes/hmac.js";
5
4
  import { sha512 } from "@noble/hashes/sha2.js";
6
5
  import { keccak_256 } from "@noble/hashes/sha3.js";
6
+ import { base58 } from "@scure/base";
7
7
  import { HDKey } from "@scure/bip32";
8
- import { mnemonicToSeedSync } from "@scure/bip39";
9
- import "@scure/bip39/wordlists/english.js";
8
+ import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
9
+ import { wordlist } from "@scure/bip39/wordlists/english.js";
10
10
  //#region packages/x402-proxy/src/lib/derive.ts
11
11
  /**
12
12
  * Wallet derivation from BIP-39 mnemonic.
@@ -19,6 +19,12 @@ import "@scure/bip39/wordlists/english.js";
19
19
  *
20
20
  * Ported from agentbox/packages/openclaw-x402/src/wallet.ts
21
21
  */
22
+ function generateMnemonic$1() {
23
+ return generateMnemonic(wordlist, 256);
24
+ }
25
+ function isValidMnemonic(mnemonic) {
26
+ return validateMnemonic(mnemonic, wordlist);
27
+ }
22
28
  /**
23
29
  * SLIP-10 Ed25519 derivation at m/44'/501'/0'/0' (Phantom/Backpack compatible).
24
30
  */
@@ -74,4 +80,4 @@ function checksumAddress(addr) {
74
80
  return out;
75
81
  }
76
82
  //#endregion
77
- export { deriveEvmKeypair, deriveSolanaKeypair };
83
+ export { deriveEvmKeypair, deriveSolanaKeypair, generateMnemonic$1 as generateMnemonic, isValidMnemonic };
@@ -1,8 +1,8 @@
1
- import { loadWalletFile } from "./config.js";
2
1
  import { deriveEvmKeypair, deriveSolanaKeypair } from "./derive.js";
2
+ import { loadWalletFile } from "./config.js";
3
+ import { privateKeyToAccount } from "viem/accounts";
3
4
  import { ed25519 } from "@noble/curves/ed25519.js";
4
5
  import { base58 } from "@scure/base";
5
- import { privateKeyToAccount } from "viem/accounts";
6
6
  //#region packages/x402-proxy/src/lib/wallet-resolution.ts
7
7
  /**
8
8
  * Resolve wallet keys following the priority cascade:
@@ -1,6 +1,5 @@
1
+ import * as openclaw_plugin_sdk_plugin_entry0 from "openclaw/plugin-sdk/plugin-entry";
1
2
  import { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
2
- import * as openclaw_plugin_sdk0 from "openclaw/plugin-sdk";
3
- import * as openclaw_plugin_sdk_core0 from "openclaw/plugin-sdk/core";
4
3
 
5
4
  //#region packages/x402-proxy/src/openclaw/plugin.d.ts
6
5
  declare function register(api: OpenClawPluginApi): void;
@@ -8,8 +7,8 @@ declare const _default: {
8
7
  id: string;
9
8
  name: string;
10
9
  description: string;
11
- configSchema: openclaw_plugin_sdk0.OpenClawPluginConfigSchema;
12
- register: NonNullable<openclaw_plugin_sdk_core0.OpenClawPluginDefinition["register"]>;
13
- } & Pick<openclaw_plugin_sdk_core0.OpenClawPluginDefinition, "kind">;
10
+ configSchema: openclaw_plugin_sdk_plugin_entry0.OpenClawPluginConfigSchema;
11
+ register: NonNullable<openclaw_plugin_sdk_plugin_entry0.OpenClawPluginDefinition["register"]>;
12
+ } & Pick<openclaw_plugin_sdk_plugin_entry0.OpenClawPluginDefinition, "kind">;
14
13
  //#endregion
15
14
  export { _default as default, register };
@@ -1,5 +1,6 @@
1
+ import { generateMnemonic, isValidMnemonic } from "../lib/derive.js";
2
+ import { createWalletFile, getHistoryPath, getWalletPath, saveWalletFile } from "../lib/config.js";
1
3
  import { createMppProxyHandler, createX402ProxyHandler } from "../handler.js";
2
- import { getHistoryPath } from "../lib/config.js";
3
4
  import { OptimizedSvmScheme } from "../lib/optimized-svm-scheme.js";
4
5
  import { resolveWallet } from "../lib/wallet-resolution.js";
5
6
  import { loadSvmWallet } from "../wallet.js";
@@ -20,20 +21,80 @@ function register(api) {
20
21
  const dashboardUrl = config.dashboardUrl || "";
21
22
  const { providers, models: allModels } = resolveProviders(config);
22
23
  const defaultProvider = providers[0];
23
- for (const provider of providers) api.registerProvider({
24
- id: provider.id,
25
- label: provider.id,
26
- auth: [],
27
- catalog: {
28
- order: "simple",
29
- run: async () => ({ provider: {
30
- baseUrl: provider.baseUrl,
31
- api: "openai-completions",
32
- authHeader: false,
33
- models: provider.models
34
- } })
24
+ const walletAuthMethod = {
25
+ id: "wallet-setup",
26
+ label: "x402-proxy wallet setup",
27
+ hint: "Generate or import a crypto wallet for paid inference",
28
+ kind: "custom",
29
+ run: async (ctx) => {
30
+ const existing = resolveWallet();
31
+ if (existing.source !== "none") {
32
+ const addresses = [existing.evmAddress ? `EVM: ${existing.evmAddress}` : null, existing.solanaAddress ? `Solana: ${existing.solanaAddress}` : null].filter(Boolean).join("\n");
33
+ await ctx.prompter.note(`Wallet already configured (source: ${existing.source}).\n\n${addresses}`, "x402-proxy wallet");
34
+ return { profiles: [] };
35
+ }
36
+ const action = await ctx.prompter.select({
37
+ message: "How would you like to set up your x402-proxy wallet?",
38
+ options: [{
39
+ value: "generate",
40
+ label: "Generate a new wallet"
41
+ }, {
42
+ value: "import",
43
+ label: "Import an existing BIP-39 mnemonic"
44
+ }]
45
+ });
46
+ let mnemonic;
47
+ if (action === "import") {
48
+ mnemonic = await ctx.prompter.text({
49
+ message: "Enter your BIP-39 mnemonic (12 or 24 words):",
50
+ validate: (v) => {
51
+ const words = String(v ?? "").trim().split(/\s+/);
52
+ if (words.length !== 12 && words.length !== 24) return "Mnemonic must be 12 or 24 words";
53
+ if (!isValidMnemonic(words.join(" "))) return "Invalid BIP-39 mnemonic. Check the words and try again.";
54
+ }
55
+ });
56
+ mnemonic = String(mnemonic).trim();
57
+ } else mnemonic = generateMnemonic();
58
+ const wallet = createWalletFile(mnemonic);
59
+ saveWalletFile(wallet);
60
+ const msg = [
61
+ `EVM: ${wallet.addresses.evm}`,
62
+ `Solana: ${wallet.addresses.solana}`,
63
+ "",
64
+ `Wallet saved to ${getWalletPath()}`,
65
+ "",
66
+ "Fund these addresses with USDC to start using paid inference.",
67
+ action === "generate" ? "\nRecover your mnemonic later with: npx x402-proxy wallet export-key mnemonic" : ""
68
+ ].filter(Boolean).join("\n");
69
+ await ctx.prompter.note(msg, "Wallet created");
70
+ return { profiles: [{
71
+ profileId: "surf:x402-proxy",
72
+ credential: {
73
+ type: "api_key",
74
+ provider: "surf",
75
+ key: "x402-proxy-managed"
76
+ }
77
+ }] };
35
78
  }
36
- });
79
+ };
80
+ for (const provider of providers) {
81
+ const isFirst = provider === providers[0];
82
+ api.registerProvider({
83
+ id: provider.id,
84
+ label: provider.id,
85
+ auth: isFirst ? [walletAuthMethod] : [],
86
+ resolveConfigApiKey: () => "x402-proxy-managed",
87
+ catalog: {
88
+ order: "simple",
89
+ run: async () => ({ provider: {
90
+ baseUrl: provider.baseUrl,
91
+ api: "openai-completions",
92
+ authHeader: false,
93
+ models: provider.models
94
+ } })
95
+ }
96
+ });
97
+ }
37
98
  api.logger.info(`x402-proxy: ${providers.map((provider) => `${provider.id}:${provider.protocol}`).join(", ")} - ${allModels.length} models`);
38
99
  let solanaWalletAddress = null;
39
100
  let evmWalletAddress = null;
@@ -60,8 +121,20 @@ function register(api) {
60
121
  auth: "plugin",
61
122
  handler
62
123
  });
63
- api.logger.info(`proxy: HTTP routes ${routePrefixes.join(", ")} registered for ${providers.map((provider) => provider.upstreamUrl).join(", ")}`);
64
- async function ensureWalletLoaded() {
124
+ api.logger.info(`x402-proxy: HTTP routes ${routePrefixes.join(", ")} registered for ${providers.map((provider) => provider.upstreamUrl).join(", ")}`);
125
+ async function ensureWalletLoaded(opts) {
126
+ if (opts?.reload) {
127
+ if (mppHandlerRef) try {
128
+ await mppHandlerRef.close();
129
+ } catch {}
130
+ walletLoadPromise = null;
131
+ solanaWalletAddress = null;
132
+ evmWalletAddress = null;
133
+ signerRef = null;
134
+ proxyRef = null;
135
+ mppHandlerRef = null;
136
+ evmKeyRef = null;
137
+ }
65
138
  if (walletLoadPromise) {
66
139
  await walletLoadPromise;
67
140
  return;
@@ -82,7 +155,7 @@ function register(api) {
82
155
  solanaWalletAddress = null;
83
156
  }
84
157
  if (!solanaWalletAddress && !evmWalletAddress) {
85
- api.logger.error("x402-proxy: no wallet found. Run `x402-proxy setup` to create one, or set X402_PROXY_WALLET_MNEMONIC / X402_PROXY_WALLET_EVM_KEY.");
158
+ api.logger.error("x402-proxy: no wallet found. Use /x_wallet setup or run `npx x402-proxy setup` on the host.");
86
159
  return;
87
160
  }
88
161
  if (signerRef) {
@@ -2,13 +2,24 @@
2
2
  "id": "x402-proxy",
3
3
  "name": "mpp/x402 Payments Proxy",
4
4
  "description": "x402 and MPP payments, wallet tools, and paid inference proxying",
5
- "version": "0.10.12",
6
5
  "providers": [
7
6
  "surf"
8
7
  ],
9
8
  "autoEnableWhenConfiguredProviders": [
10
9
  "surf"
11
10
  ],
11
+ "providerAuthChoices": [
12
+ {
13
+ "provider": "surf",
14
+ "method": "wallet-setup",
15
+ "choiceId": "x402-wallet-setup",
16
+ "choiceLabel": "x402-proxy wallet",
17
+ "choiceHint": "Generate or import a crypto wallet for paid inference",
18
+ "groupId": "x402-proxy",
19
+ "groupLabel": "x402-proxy",
20
+ "groupHint": "Crypto wallet for x402/MPP payments"
21
+ }
22
+ ],
12
23
  "skills": [
13
24
  "skills"
14
25
  ],
@@ -108,5 +119,6 @@
108
119
  "label": "Dashboard URL",
109
120
  "advanced": true
110
121
  }
111
- }
122
+ },
123
+ "version": "0.11.2"
112
124
  }
package/dist/wallet.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createKeyPairSignerFromBytes } from "@solana/kit";
2
- import { readFileSync } from "node:fs";
3
2
  import "viem/accounts";
3
+ import { readFileSync } from "node:fs";
4
4
  import "@x402/evm";
5
5
  //#region packages/x402-proxy/src/wallet.ts
6
6
  /**
@@ -2,13 +2,24 @@
2
2
  "id": "x402-proxy",
3
3
  "name": "mpp/x402 Payments Proxy",
4
4
  "description": "x402 and MPP payments, wallet tools, and paid inference proxying",
5
- "version": "0.10.12",
6
5
  "providers": [
7
6
  "surf"
8
7
  ],
9
8
  "autoEnableWhenConfiguredProviders": [
10
9
  "surf"
11
10
  ],
11
+ "providerAuthChoices": [
12
+ {
13
+ "provider": "surf",
14
+ "method": "wallet-setup",
15
+ "choiceId": "x402-wallet-setup",
16
+ "choiceLabel": "x402-proxy wallet",
17
+ "choiceHint": "Generate or import a crypto wallet for paid inference",
18
+ "groupId": "x402-proxy",
19
+ "groupLabel": "x402-proxy",
20
+ "groupHint": "Crypto wallet for x402/MPP payments"
21
+ }
22
+ ],
12
23
  "skills": [
13
24
  "skills"
14
25
  ],
@@ -108,5 +119,6 @@
108
119
  "label": "Dashboard URL",
109
120
  "advanced": true
110
121
  }
111
- }
122
+ },
123
+ "version": "0.11.2"
112
124
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "x402-proxy-openclaw",
3
3
  "description": "OpenClaw plugin for x402 and MPP payments, wallet tools, and paid inference proxying.",
4
- "version": "0.10.12",
4
+ "version": "0.11.2",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "license": "Apache-2.0",
@@ -34,16 +34,16 @@
34
34
  "surf"
35
35
  ],
36
36
  "compat": {
37
- "pluginApi": ">=2026.3.24",
38
- "minGatewayVersion": "2026.3.24"
37
+ "pluginApi": ">=2026.4.1",
38
+ "minGatewayVersion": "2026.4.1"
39
39
  },
40
40
  "build": {
41
- "openclawVersion": "2026.3.24",
42
- "pluginSdkVersion": "2026.3.24"
41
+ "openclawVersion": "2026.4.1",
42
+ "pluginSdkVersion": "2026.4.1"
43
43
  }
44
44
  },
45
45
  "peerDependencies": {
46
- "openclaw": ">=2026.3.8"
46
+ "openclaw": ">=2026.3.24"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "openclaw": {
package/skills/SKILL.md CHANGED
@@ -10,7 +10,7 @@ description: Use x402-proxy CLI for consuming and debugging x402 and MPP paid AP
10
10
  ## Quick start
11
11
 
12
12
  ```bash
13
- npx x402-proxy -X POST -d '{"ref":"CoinbaseDev"}' https://surf.cascade.fyi/api/v1/twitter/user
13
+ npx x402-proxy https://surf.cascade.fyi/api/v1/twitter/user/openclaw
14
14
  ```
15
15
 
16
16
  First run auto-creates a wallet. No setup needed.