Skip to content

Commit cf47f4e

Browse files
committed
feat(openclaw): add MPP support, serve/claude commands, dual-wallet
- Add `serve` command for local paid inference proxy - Add `claude` command with --model flag (default minimax/minimax-m2.7) - Add MPP payment protocol to OpenClaw plugin inference proxy and x_request tool - Add /x_send slash command with confirmation flow - Add default Surf provider config (works out of the box) - Migrate plugin to definePluginEntry SDK - Rename x_balance -> x_wallet, x_payment -> x_request (old names kept as aliases) - Add addressForNetwork and parseMppAmount shared helpers - Replace hardcoded eip155:4217 with TEMPO_NETWORK constant - Deduplicate SSE tracking into createSseTracker() - Fix preferredNetwork string comparison bug in serve command
1 parent 73dc6d8 commit cf47f4e

16 files changed

Lines changed: 1680 additions & 332 deletions

File tree

packages/x402-proxy/CHANGELOG.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.10.0] - 2026-04-01
11+
12+
### Added
13+
- `serve` command - local HTTP proxy server for paid inference endpoints, auto-detects wallet and preferred network
14+
- `claude` command - run Claude Code through a paid local proxy with `ANTHROPIC_BASE_URL` auto-configured
15+
- `--model` flag on `claude` command (default: `minimax/minimax-m2.7`) - sets `ANTHROPIC_CUSTOM_MODEL_OPTION` for non-Anthropic models
16+
- MPP payment support in OpenClaw plugin - inference proxy and `x_request` tool now handle both x402 (Solana) and MPP (Tempo/Base) protocols
17+
- `/x_send` slash command with confirmation flow (5-min TTL) for USDC transfers from the OpenClaw gateway
18+
- Default Surf provider config - plugin works out of the box without explicit provider configuration
19+
- `defaults.ts` module with provider config types, resolution logic, and built-in model catalog
20+
- Dual-wallet support in OpenClaw plugin - EVM and Solana addresses resolved independently
21+
- `addressForNetwork` and `parseMppAmount` exported as shared helpers from `tools.ts`
22+
23+
### Changed
24+
- OpenClaw plugin migrated to `definePluginEntry` SDK (from hand-rolled types)
25+
- `x_balance` tool renamed to `x_wallet` (alias: `x_balance`)
26+
- `x_payment` tool renamed to `x_request` (alias: `x_payment`) with x402/MPP protocol branching
27+
- `/x_wallet` command: `send` subcommand now redirects to `/x_send`
28+
- Inference proxy route handler renamed from `createX402RouteHandler` to `createInferenceProxyRouteHandler`
29+
- SSE token tracking deduplicated into `createSseTracker()` helper shared by x402 and MPP paths
30+
- Replaced hardcoded `"eip155:4217"` with imported `TEMPO_NETWORK` constant
31+
- `serve` and `claude` commands handle their own SIGINT/SIGTERM (CLI entry point skips default handler for them)
32+
- Wallet loading in plugin uses proper promise dedup (`walletLoadPromise`) instead of boolean flag
33+
- Providers sorted once in route handler closure instead of per-request
34+
35+
### Fixed
36+
- `preferredNetwork === "undefined"` string comparison in serve command replaced with proper `preferredNetwork || undefined` check
37+
1038
## [0.9.4] - 2026-03-27
1139

1240
### Fixed
@@ -300,7 +328,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
300328
- `appendHistory` / `readHistory` / `calcSpend` - JSONL transaction history
301329
- Re-exports from `@x402/fetch`, `@x402/svm`, `@x402/evm`
302330

303-
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.4...HEAD
331+
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.10.0...HEAD
332+
[0.10.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.4...v0.10.0
304333
[0.9.4]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.3...v0.9.4
305334
[0.9.3]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.2...v0.9.3
306335
[0.9.2]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.1...v0.9.2

packages/x402-proxy/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ $ npx x402-proxy https://api.example.com/data | jq '.results'
8181

8282
```bash
8383
$ npx x402-proxy <url> # paid HTTP request (default command)
84+
$ npx x402-proxy serve # local paid inference proxy server
85+
$ npx x402-proxy claude # run Claude Code through a paid local proxy
8486
$ npx x402-proxy mcp <url> # MCP stdio proxy for agents
8587
$ npx x402-proxy mcp add <name> <url> # install MCP server into your AI client
8688
$ npx x402-proxy setup # onboarding wizard
@@ -141,9 +143,11 @@ See the [library API docs](https://github.com/cascade-protocol/x402-proxy/tree/m
141143

142144
## OpenClaw Plugin
143145

144-
x402-proxy ships as an [OpenClaw](https://openclaw.dev) plugin, giving your gateway automatic x402 payment capabilities. Registers `x_balance` and `x_payment` tools, `/x_wallet` command, and an HTTP route proxy for upstream x402 endpoints.
146+
x402-proxy ships as an [OpenClaw](https://openclaw.dev) plugin, giving your gateway automatic x402 and MPP payment capabilities. Registers `x_wallet` and `x_request` tools (aliased as `x_balance`/`x_payment`), `/x_wallet` and `/x_send` commands, and an HTTP route proxy for upstream inference endpoints.
145147

146-
Configure providers and models in OpenClaw plugin settings. Uses the standard wallet resolution (env vars or `wallet.json`).
148+
By default, the plugin registers a built-in `surf` provider at `/x402-proxy/v1` that points at `https://surf.cascade.fyi/api/v1/inference` and prefers MPP. Uses the standard wallet resolution (env vars or `wallet.json`).
149+
150+
For MPP-backed inference, make sure the wallet source includes an EVM key as well as Solana. `npx x402-proxy setup` does this automatically.
147151

148152
## License
149153

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,61 @@
11
{
22
"id": "x402-proxy",
3-
"name": "x402 Proxy",
4-
"description": "x402/MPP payments, Solana wallet, and inference proxying",
3+
"name": "mpp/x402 Payments Proxy",
4+
"description": "x402 and MPP payments, wallet tools, and paid inference proxying",
55
"version": "1.0.0",
6+
"providers": ["surf"],
7+
"autoEnableWhenConfiguredProviders": ["surf"],
8+
"skills": ["skills"],
9+
"contracts": {
10+
"tools": ["x_wallet", "x_balance", "x_request", "x_payment"]
11+
},
612
"configSchema": {
713
"type": "object",
14+
"additionalProperties": false,
815
"properties": {
916
"providers": {
1017
"type": "object",
11-
"description": "Provider catalog keyed by name, each with baseUrl and models array"
18+
"description": "Provider catalog keyed by name. Defaults to the built-in surf provider when omitted.",
19+
"additionalProperties": {
20+
"type": "object",
21+
"additionalProperties": false,
22+
"properties": {
23+
"baseUrl": {
24+
"type": "string",
25+
"description": "Gateway base path for this provider, typically under /x402-proxy"
26+
},
27+
"upstreamUrl": {
28+
"type": "string",
29+
"description": "Upstream inference origin to proxy to"
30+
},
31+
"protocol": {
32+
"type": "string",
33+
"enum": ["x402", "mpp", "auto"],
34+
"description": "Payment protocol for this provider. Defaults to mpp."
35+
},
36+
"mppSessionBudget": {
37+
"type": "string",
38+
"description": "Maximum USDC budget to lock for MPP sessions for this provider (default: 0.5)"
39+
},
40+
"models": {
41+
"type": "array",
42+
"description": "Static OpenClaw model catalog entries for this provider"
43+
}
44+
}
45+
}
46+
},
47+
"protocol": {
48+
"type": "string",
49+
"enum": ["x402", "mpp", "auto"],
50+
"description": "Default payment protocol fallback for providers that do not override it."
51+
},
52+
"mppSessionBudget": {
53+
"type": "string",
54+
"description": "Default maximum USDC budget to lock for MPP sessions (default: 0.5)"
1255
},
1356
"keypairPath": {
1457
"type": "string",
15-
"description": "Optional path to Solana keypair JSON file (overrides x402-proxy wallet resolution)"
58+
"description": "Optional path to Solana keypair JSON file (overrides x402-proxy wallet resolution for Solana/x402 surfaces)"
1659
},
1760
"rpcUrl": {
1861
"type": "string",
@@ -24,5 +67,27 @@
2467
}
2568
},
2669
"required": []
70+
},
71+
"uiHints": {
72+
"protocol": {
73+
"label": "Default protocol",
74+
"help": "Used only when a provider entry does not set its own protocol."
75+
},
76+
"mppSessionBudget": {
77+
"label": "Default MPP budget",
78+
"placeholder": "0.5"
79+
},
80+
"keypairPath": {
81+
"label": "Solana keypair path",
82+
"advanced": true
83+
},
84+
"rpcUrl": {
85+
"label": "Solana RPC URL",
86+
"advanced": true
87+
},
88+
"dashboardUrl": {
89+
"label": "Dashboard URL",
90+
"advanced": true
91+
}
2792
}
2893
}

packages/x402-proxy/package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "x402-proxy",
3-
"version": "0.9.4",
3+
"version": "0.10.0",
44
"description": "curl for x402 paid APIs. Auto-pays any endpoint on Base, Solana, and Tempo. Also works as an OpenClaw plugin.",
55
"type": "module",
66
"sideEffects": false,
@@ -20,7 +20,18 @@
2020
"openclaw": {
2121
"extensions": [
2222
"./dist/openclaw/plugin.js"
23-
]
23+
],
24+
"providers": [
25+
"surf"
26+
],
27+
"compat": {
28+
"pluginApi": ">=2026.3.24",
29+
"minGatewayVersion": "2026.3.24"
30+
},
31+
"build": {
32+
"openclawVersion": "2026.3.24",
33+
"pluginSdkVersion": "2026.3.24"
34+
}
2435
},
2536
"bin": {
2637
"x402-proxy": "./dist/bin/cli.js"

packages/x402-proxy/skills/SKILL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ npx x402-proxy https://api.example.com/data > response.json
4141

4242
```
4343
x402-proxy <url> # paid HTTP request (default)
44+
x402-proxy serve # local paid inference proxy server
45+
x402-proxy claude # run Claude Code through paid local proxy
4446
x402-proxy mcp <url> # MCP stdio proxy for AI agents
4547
x402-proxy mcp add <name> <url> # install MCP server into AI client
4648
x402-proxy setup # wallet onboarding wizard
@@ -174,7 +176,7 @@ openclaw plugins install x402-proxy
174176
npx x402-proxy setup # creates wallet if needed
175177
```
176178

177-
Registers: `x_balance` tool, `x_payment` tool, `/x_wallet` command, `/x402/*` HTTP route for inference proxying.
179+
Registers: `x_wallet` tool, `x_request` tool (aliased as `x_balance`/`x_payment`), `/x_wallet` and `/x_send` commands, `/x402-proxy/*` HTTP route for inference proxying.
178180

179181
## Library API
180182

packages/x402-proxy/skills/references/openclaw-plugin.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# OpenClaw Plugin Setup
22

3-
x402-proxy ships as an [OpenClaw](https://openclaw.dev) plugin. Gives your gateway automatic x402 payment, wallet management, and pay-per-use inference proxying via Solana USDC.
3+
x402-proxy ships as an [OpenClaw](https://openclaw.dev) plugin. Gives your gateway automatic x402 and MPP payment, wallet management, and pay-per-use inference proxying via USDC on Solana, Base, and Tempo.
44

55
## What it registers
66

7-
- **`x_balance` tool** - check wallet SOL/USDC balances, daily spend, available funds
8-
- **`x_payment` tool** - call any x402-enabled endpoint with automatic payment (params: `url`, `method`, `params`, `headers`)
9-
- **`/x_wallet` command** - wallet status dashboard, `send <amount|all> <address>`, `history [page]`
10-
- **HTTP route `/x402/*`** - proxies requests to upstream inference endpoints with payment, tracks token usage and cost
7+
- **`x_wallet` tool** (alias: `x_balance`) - check wallet readiness, balances, and spend history for x402 and MPP payments
8+
- **`x_request` tool** (alias: `x_payment`) - call a paid HTTP endpoint with automatic x402 or MPP settlement (params: `url`, `method`, `params`, `headers`, `protocol`)
9+
- **`/x_wallet` command** - wallet status dashboard, `history [page]`
10+
- **`/x_send` command** - send USDC with confirmation step (`/x_send <amount|all> <address>`, then `/x_send confirm`)
11+
- **HTTP route `/x402-proxy/*`** - proxies requests to upstream inference endpoints with payment, tracks token usage and cost
1112

1213
## Step 1: Install the plugin
1314

@@ -36,6 +37,15 @@ Or set an explicit keypair in plugin config (step 3).
3637

3738
## Step 3: Configure providers and models
3839

40+
If you do nothing, the plugin now defaults to:
41+
42+
- provider id: `surf`
43+
- gateway base URL: `/x402-proxy/v1`
44+
- upstream: `https://surf.cascade.fyi/api/v1/inference`
45+
- protocol: `mpp`
46+
47+
You only need explicit config if you want to override the defaults or supply a custom model catalog.
48+
3949
Add the plugin config to your `openclaw.json` (or via `openclaw config edit`):
4050

4151
```json
@@ -46,7 +56,7 @@ Add the plugin config to your `openclaw.json` (or via `openclaw config edit`):
4656
"config": {
4757
"providers": {
4858
"surf-inference": {
49-
"baseUrl": "/x402/v1",
59+
"baseUrl": "/x402-proxy/v1",
5060
"upstreamUrl": "https://surf.cascade.fyi/api/v1/inference",
5161
"models": [
5262
{ "id": "anthropic/claude-opus-4.6", "name": "Claude Opus 4.6", "maxTokens": 200000, "reasoning": true, "input": ["text", "image"], "cost": { "input": 0.015, "output": 0.075, "cacheRead": 0.0015, "cacheWrite": 0.01875 }, "contextWindow": 200000 },
@@ -78,7 +88,7 @@ Add the plugin config to your `openclaw.json` (or via `openclaw config edit`):
7888

7989
| Field | Description |
8090
|-------|-------------|
81-
| `providers.<name>.baseUrl` | Route path registered in OpenClaw (e.g., `/x402/v1`) |
91+
| `providers.<name>.baseUrl` | Route path registered in OpenClaw (e.g., `/x402-proxy/v1`) |
8292
| `providers.<name>.upstreamUrl` | Actual upstream endpoint (e.g., `https://surf.cascade.fyi/api/v1/inference`) |
8393
| `providers.<name>.models[]` | Model catalog array |
8494
| `keypairPath` | Optional path to solana-keygen JSON file (overrides wallet resolution) |
@@ -111,8 +121,8 @@ openclaw models # verify models appear
111121

112122
1. Plugin boots, loads wallet via the resolution cascade
113123
2. Registers each provider from config into OpenClaw's model catalog (API type: `openai-completions`, no auth required)
114-
3. HTTP route `/x402/*` intercepts inference requests, strips prefix, proxies to `upstreamUrl`
115-
4. On 402 response, auto-signs a Solana USDC payment and retries
124+
3. HTTP route `/x402-proxy/*` intercepts inference requests, strips prefix, proxies to `upstreamUrl`
125+
4. On 402 response, auto-pays via MPP (Tempo/Base) or x402 (Solana) depending on provider config
116126
5. SSE streaming responses are parsed for token usage and logged to `~/.config/x402-proxy/history.jsonl`
117127
6. Tools and command are available to all agents on the gateway
118128

@@ -131,5 +141,5 @@ Then update the `models` array in your plugin config accordingly.
131141

132142
- **Models don't appear in `openclaw models`** - the plugin uses a `catalog` hook (not `models` field). Make sure you're on x402-proxy >= 0.8.5.
133143
- **"no wallet found" in logs** - run `npx x402-proxy setup` or set `X402_PROXY_WALLET_MNEMONIC` env var before starting the gateway.
134-
- **402 errors on inference** - check wallet has USDC balance: use `x_balance` tool or `npx x402-proxy wallet`.
144+
- **402 errors on inference** - check wallet has USDC balance: use `x_wallet` tool or `npx x402-proxy wallet`.
135145
- **Gateway cold start slow** - normal on small VMs (~72s). The `x402-wallet` service eagerly loads the wallet during boot.

packages/x402-proxy/src/app.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
declare const __VERSION__: string;
22

33
import { buildApplication, buildRouteMap } from "@stricli/core";
4+
import { claudeCommand } from "./commands/claude.js";
45
import { configSetCommand, configShowCommand, configUnsetCommand } from "./commands/config.js";
56
import { fetchCommand } from "./commands/fetch.js";
67
import { mcpCommand } from "./commands/mcp.js";
78
import { mcpAddCommand } from "./commands/mcp-add.js";
9+
import { serveCommand } from "./commands/serve.js";
810
import { setupCommand } from "./commands/setup.js";
911
import { statusCommand } from "./commands/status.js";
1012
import { walletInfoCommand } from "./commands/wallet.js";
@@ -49,6 +51,8 @@ const mcpRoutes = buildRouteMap({
4951
const routes = buildRouteMap({
5052
routes: {
5153
fetch: fetchCommand,
54+
serve: serveCommand,
55+
claude: claudeCommand,
5256
mcp: mcpRoutes,
5357
wallet: walletRoutes,
5458
config: configRoutes,

packages/x402-proxy/src/bin/cli.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ import { run } from "@stricli/core";
33
import { app } from "../app.js";
44
import { buildContext } from "../context.js";
55

6-
// Ensure Ctrl+C always exits cleanly (raw mode from @clack/prompts can swallow SIGINT)
7-
process.on("SIGINT", () => process.exit(130));
8-
96
// Pre-process args before Stricli parses them
107
const rawArgs = process.argv.slice(2);
118
const args: string[] = [];
@@ -27,4 +24,11 @@ for (let i = 0; i < rawArgs.length; i++) {
2724
args.push(a);
2825
}
2926
}
27+
28+
const topLevelCommand = args[0];
29+
if (topLevelCommand !== "serve" && topLevelCommand !== "claude") {
30+
// Ensure Ctrl+C always exits cleanly (raw mode from @clack/prompts can swallow SIGINT)
31+
process.on("SIGINT", () => process.exit(130));
32+
}
33+
3034
await run(app, args, buildContext(process));

0 commit comments

Comments
 (0)