x402-proxy 0.9.2 → 0.9.3

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 CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.3] - 2026-03-26
11
+
12
+ ### Fixed
13
+ - Solana RPC 429 rate-limit failures on concurrent payments - replaced upstream `ExactSvmScheme` (creates new RPC client per call) with `OptimizedSvmScheme` that shares a single RPC client with `@solana/kit` request coalescing (identical calls in the same microtask merge into one network request)
14
+ - Hardcoded USDC mint metadata (Token Program address, 6 decimals) to skip `fetchMint` RPC call entirely for USDC payments
15
+ - Added RPC failover transport: on 429 from one endpoint, immediately tries the next instead of failing. Two public mainnet RPCs: `api.mainnet.solana.com` (Solana Labs, 100 req/10s) and `public.rpc.solanavibestation.com` (community, 5 RPS)
16
+ - Custom RPC URL (via config or OpenClaw plugin) is tried first, with public RPCs as fallback
17
+
18
+ ### Changed
19
+ - Added `@solana-program/compute-budget`, `@solana-program/token`, `@solana-program/token-2022`, `@x402/core` as direct dependencies (previously transitive via `@x402/svm`)
20
+
10
21
  ## [0.9.2] - 2026-03-26
11
22
 
12
23
  ### Changed
@@ -284,7 +295,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
284
295
  - `appendHistory` / `readHistory` / `calcSpend` - JSONL transaction history
285
296
  - Re-exports from `@x402/fetch`, `@x402/svm`, `@x402/evm`
286
297
 
287
- [Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.2...HEAD
298
+ [Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.3...HEAD
299
+ [0.9.3]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.2...v0.9.3
288
300
  [0.9.2]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.1...v0.9.2
289
301
  [0.9.1]: https://github.com/cascade-protocol/x402-proxy/compare/v0.9.0...v0.9.1
290
302
  [0.9.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.6...v0.9.0
package/dist/bin/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
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";
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-CqUc-ZFn.js";
4
4
  import { n as setupCommand, t as runSetup } from "../setup-QtTFsCFs.js";
5
- import { n as statusCommand } from "../status-ZRhJKaXq.js";
5
+ import { n as statusCommand } from "../status-BZTToWE_.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";
@@ -398,7 +398,7 @@ Examples:
398
398
  };
399
399
  if (!url) {
400
400
  if (isConfigured()) {
401
- const { displayStatus } = await import("../status-Dt8be_kW.js");
401
+ const { displayStatus } = await import("../status-Bj3U-W2M.js");
402
402
  await displayStatus();
403
403
  console.log();
404
404
  console.log(pc.dim(" Commands:"));
@@ -463,7 +463,7 @@ Examples:
463
463
  verbose(`protocol: ${resolvedProtocol ?? "auto-detect"}, maxDeposit: ${maxDeposit}`);
464
464
  let preferredNetwork = config?.defaultNetwork;
465
465
  if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
466
- const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
466
+ const { fetchAllBalances } = await import("../wallet-4C9EL4Iv.js");
467
467
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
468
468
  const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
469
469
  const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
@@ -630,7 +630,7 @@ Examples:
630
630
  const hasSolana = accepts.some((a) => a.network.startsWith("solana:"));
631
631
  const hasMpp = detected.mpp;
632
632
  const hasOther = accepts.some((a) => !a.network.startsWith("eip155:") && !a.network.startsWith("solana:"));
633
- const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
633
+ const { fetchAllBalances } = await import("../wallet-4C9EL4Iv.js");
634
634
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
635
635
  const evmUsdc = hasEvm && balances.evm ? Number(balances.evm.usdc) : 0;
636
636
  const solUsdc = hasSolana && balances.sol ? Number(balances.sol.usdc) : 0;
@@ -850,7 +850,7 @@ Wallet is auto-generated on first run. No env vars needed.`
850
850
  async function startX402Proxy() {
851
851
  let preferredNetwork = config?.defaultNetwork;
852
852
  if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
853
- const { fetchAllBalances } = await import("../wallet-8evCw-5Z.js");
853
+ const { fetchAllBalances } = await import("../wallet-4C9EL4Iv.js");
854
854
  const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
855
855
  const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
856
856
  const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
@@ -870,7 +870,7 @@ Wallet is auto-generated on first run. No env vars needed.`
870
870
  }
871
871
  const remoteClient = new Client({
872
872
  name: "x402-proxy",
873
- version: "0.9.2"
873
+ version: "0.9.3"
874
874
  });
875
875
  const x402Mcp = new x402MCPClient(remoteClient, x402PaymentClient, {
876
876
  autoPayment: true,
@@ -908,7 +908,7 @@ Wallet is auto-generated on first run. No env vars needed.`
908
908
  }
909
909
  const localServer = new Server({
910
910
  name: "x402-proxy",
911
- version: "0.9.2"
911
+ version: "0.9.3"
912
912
  }, { capabilities: {
913
913
  tools: tools.length > 0 ? {} : void 0,
914
914
  resources: remoteResources.length > 0 ? {} : void 0
@@ -1003,7 +1003,7 @@ Wallet is auto-generated on first run. No env vars needed.`
1003
1003
  }));
1004
1004
  const remoteClient = new Client({
1005
1005
  name: "x402-proxy",
1006
- version: "0.9.2"
1006
+ version: "0.9.3"
1007
1007
  });
1008
1008
  await connectTransport(remoteClient);
1009
1009
  const mppClient = McpClient.wrap(remoteClient, { methods: wrappedMethods });
@@ -1018,7 +1018,7 @@ Wallet is auto-generated on first run. No env vars needed.`
1018
1018
  }
1019
1019
  const localServer = new Server({
1020
1020
  name: "x402-proxy",
1021
- version: "0.9.2"
1021
+ version: "0.9.3"
1022
1022
  }, { capabilities: {
1023
1023
  tools: tools.length > 0 ? {} : void 0,
1024
1024
  resources: remoteResources.length > 0 ? {} : void 0
@@ -1415,7 +1415,7 @@ const app = buildApplication(buildRouteMap({
1415
1415
  docs: { brief: "curl for x402 paid APIs" }
1416
1416
  }), {
1417
1417
  name: "x402-proxy",
1418
- versionInfo: { currentVersion: "0.9.2" },
1418
+ versionInfo: { currentVersion: "0.9.3" },
1419
1419
  scanner: { caseStyle: "allow-kebab-for-camel" }
1420
1420
  });
1421
1421
  //#endregion
@@ -1,10 +1,12 @@
1
1
  import os, { homedir } from "node:os";
2
2
  import path, { dirname, join } from "node:path";
3
- import { address, appendTransactionMessageInstructions, createKeyPairSignerFromBytes, createSolanaRpc, createTransactionMessage, getAddressEncoder, getBase64EncodedWireTransaction, getProgramDerivedAddress, partiallySignTransactionMessageWithSigners, pipe, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash } from "@solana/kit";
3
+ import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, address, appendTransactionMessageInstructions, createDefaultRpcTransport, createKeyPairSignerFromBytes, createSolanaRpc, createSolanaRpcFromTransport, createTransactionMessage, getAddressEncoder, getBase64EncodedWireTransaction, getProgramDerivedAddress, isSolanaError, mainnet, partiallySignTransactionMessageWithSigners, pipe, prependTransactionMessageInstruction, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash } from "@solana/kit";
4
4
  import { decodePaymentResponseHeader, wrapFetchWithPayment, x402Client } from "@x402/fetch";
5
- import { ExactSvmScheme } from "@x402/svm/exact/client";
6
5
  import fs, { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
7
6
  import "yaml";
7
+ import { getSetComputeUnitLimitInstruction, setTransactionMessageComputeUnitPrice } from "@solana-program/compute-budget";
8
+ import { TOKEN_PROGRAM_ADDRESS } from "@solana-program/token";
9
+ import { TOKEN_2022_PROGRAM_ADDRESS, fetchMint, findAssociatedTokenPda, getTransferCheckedInstruction } from "@solana-program/token-2022";
8
10
  import { ed25519 } from "@noble/curves/ed25519.js";
9
11
  import { base58 } from "@scure/base";
10
12
  import "@x402/evm";
@@ -81,6 +83,100 @@ function loadWalletFile() {
81
83
  return null;
82
84
  }
83
85
  }
86
+ //#endregion
87
+ //#region src/lib/optimized-svm-scheme.ts
88
+ const MEMO_PROGRAM_ADDRESS = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
89
+ const COMPUTE_UNIT_LIMIT = 2e4;
90
+ const COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
91
+ const USDC_MINT$1 = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
92
+ const USDC_DECIMALS$1 = 6;
93
+ const MAINNET_RPC_URLS = ["https://api.mainnet.solana.com", "https://public.rpc.solanavibestation.com"];
94
+ /**
95
+ * Create a failover transport that tries each RPC in order.
96
+ * On 429 from one endpoint, immediately tries the next instead of waiting.
97
+ * Each transport gets its own coalescing via createDefaultRpcTransport.
98
+ */
99
+ function createFailoverTransport(urls) {
100
+ const transports = urls.map((url) => createDefaultRpcTransport({ url }));
101
+ const failover = (async (config) => {
102
+ let lastError;
103
+ for (const transport of transports) try {
104
+ return await transport(config);
105
+ } catch (e) {
106
+ lastError = e;
107
+ if (isSolanaError(e, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR) && e.context.statusCode === 429) continue;
108
+ throw e;
109
+ }
110
+ throw lastError;
111
+ });
112
+ return failover;
113
+ }
114
+ function createRpcClient(customRpcUrl) {
115
+ return createSolanaRpcFromTransport(createFailoverTransport((customRpcUrl ? [customRpcUrl, ...MAINNET_RPC_URLS] : MAINNET_RPC_URLS).map((u) => mainnet(u))));
116
+ }
117
+ /**
118
+ * Optimized ExactSvmScheme that replaces upstream @x402/svm to prevent
119
+ * RPC rate-limit failures on parallel payments.
120
+ *
121
+ * Two optimizations over upstream:
122
+ * 1. Shared RPC client - @solana/kit's built-in request coalescing
123
+ * merges identical getLatestBlockhash calls in the same tick into 1.
124
+ * 2. Hardcoded USDC - skips fetchMint RPC call for USDC (immutable data).
125
+ */
126
+ var OptimizedSvmScheme = class {
127
+ scheme = "exact";
128
+ rpc;
129
+ constructor(signer, config) {
130
+ this.signer = signer;
131
+ this.rpc = createRpcClient(config?.rpcUrl);
132
+ }
133
+ async createPaymentPayload(x402Version, paymentRequirements) {
134
+ const rpc = this.rpc;
135
+ const asset = paymentRequirements.asset;
136
+ let tokenProgramAddress;
137
+ let decimals;
138
+ if (asset === USDC_MINT$1) {
139
+ tokenProgramAddress = TOKEN_PROGRAM_ADDRESS;
140
+ decimals = USDC_DECIMALS$1;
141
+ } else {
142
+ const tokenMint = await fetchMint(rpc, asset);
143
+ tokenProgramAddress = tokenMint.programAddress;
144
+ if (tokenProgramAddress !== TOKEN_PROGRAM_ADDRESS && tokenProgramAddress !== TOKEN_2022_PROGRAM_ADDRESS) throw new Error("Asset was not created by a known token program");
145
+ decimals = tokenMint.data.decimals;
146
+ }
147
+ const [sourceATA] = await findAssociatedTokenPda({
148
+ mint: asset,
149
+ owner: this.signer.address,
150
+ tokenProgram: tokenProgramAddress
151
+ });
152
+ const [destinationATA] = await findAssociatedTokenPda({
153
+ mint: asset,
154
+ owner: paymentRequirements.payTo,
155
+ tokenProgram: tokenProgramAddress
156
+ });
157
+ const transferIx = getTransferCheckedInstruction({
158
+ source: sourceATA,
159
+ mint: asset,
160
+ destination: destinationATA,
161
+ authority: this.signer,
162
+ amount: BigInt(paymentRequirements.amount),
163
+ decimals
164
+ }, { programAddress: tokenProgramAddress });
165
+ const feePayer = paymentRequirements.extra?.feePayer;
166
+ if (!feePayer) throw new Error("feePayer is required in paymentRequirements.extra for SVM transactions");
167
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
168
+ const nonce = crypto.getRandomValues(new Uint8Array(16));
169
+ const memoIx = {
170
+ programAddress: MEMO_PROGRAM_ADDRESS,
171
+ accounts: [],
172
+ data: new TextEncoder().encode(Array.from(nonce).map((b) => b.toString(16).padStart(2, "0")).join(""))
173
+ };
174
+ return {
175
+ x402Version,
176
+ payload: { transaction: getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageComputeUnitPrice(COMPUTE_UNIT_PRICE_MICROLAMPORTS, tx), (tx) => setTransactionMessageFeePayer(feePayer, tx), (tx) => prependTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: COMPUTE_UNIT_LIMIT }), tx), (tx) => appendTransactionMessageInstructions([transferIx, memoIx], tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)))) }
177
+ };
178
+ }
179
+ };
84
180
  function appendHistory(historyPath, record) {
85
181
  try {
86
182
  mkdirSync(dirname(historyPath), { recursive: true });
@@ -713,7 +809,7 @@ function createWalletCommand(ctx) {
713
809
  try {
714
810
  const snap = await getWalletSnapshot(ctx.rpcUrl, walletAddress, ctx.historyPath);
715
811
  const solscanUrl = `https://solscan.io/account/${walletAddress}`;
716
- const lines = [`x402-proxy v0.9.2`];
812
+ const lines = [`x402-proxy v0.9.3`];
717
813
  const defaultModel = ctx.allModels[0];
718
814
  if (defaultModel) lines.push("", `**Model** - ${defaultModel.name} (${defaultModel.provider})`);
719
815
  lines.push("", `**[Wallet](${solscanUrl})**`, `\`${walletAddress}\``);
@@ -1053,7 +1149,7 @@ function register(api) {
1053
1149
  return;
1054
1150
  }
1055
1151
  const client = new x402Client();
1056
- client.register(SOL_MAINNET, new ExactSvmScheme(signer, { rpcUrl }));
1152
+ client.register(SOL_MAINNET, new OptimizedSvmScheme(signer, { rpcUrl }));
1057
1153
  proxyRef = createX402ProxyHandler({ client });
1058
1154
  const upstreamOrigin = upstreamOrigins[0];
1059
1155
  if (upstreamOrigin) {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
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";
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-CqUc-ZFn.js";
4
4
  import { buildCommand } from "@stricli/core";
5
5
  import pc from "picocolors";
6
6
  //#region src/commands/status.ts
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { t as displayStatus } from "./status-BZTToWE_.js";
3
+ export { displayStatus };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { n as fetchAllBalances } from "./wallet-CqUc-ZFn.js";
3
+ export { fetchAllBalances };
@@ -9,11 +9,13 @@ import { ed25519 } from "@noble/curves/ed25519.js";
9
9
  import { base58 } from "@scure/base";
10
10
  import { toClientEvmSigner } from "@x402/evm";
11
11
  import { registerExactEvmScheme } from "@x402/evm/exact/client";
12
- import { registerExactSvmScheme } from "@x402/svm/exact/client";
13
12
  import { createPublicClient, http } from "viem";
14
13
  import { privateKeyToAccount } from "viem/accounts";
15
14
  import { base } from "viem/chains";
16
- import { address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit";
15
+ import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, address, appendTransactionMessageInstructions, createDefaultRpcTransport, createSolanaRpcFromTransport, createTransactionMessage, getAddressEncoder, getBase64EncodedWireTransaction, getProgramDerivedAddress, isSolanaError, mainnet, partiallySignTransactionMessageWithSigners, pipe, prependTransactionMessageInstruction, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash } from "@solana/kit";
16
+ import { getSetComputeUnitLimitInstruction, setTransactionMessageComputeUnitPrice } from "@solana-program/compute-budget";
17
+ import { TOKEN_PROGRAM_ADDRESS } from "@solana-program/token";
18
+ import { TOKEN_2022_PROGRAM_ADDRESS, fetchMint, findAssociatedTokenPda, getTransferCheckedInstruction } from "@solana-program/token-2022";
17
19
  //#region src/lib/output.ts
18
20
  function isTTY() {
19
21
  return !!process.stderr.isTTY;
@@ -152,6 +154,100 @@ function formatTxLine(r, opts) {
152
154
  return ` ${timeStr} ${r.ok ? "" : "✗ "}${parts.join(" · ")}`;
153
155
  }
154
156
  //#endregion
157
+ //#region src/lib/optimized-svm-scheme.ts
158
+ const MEMO_PROGRAM_ADDRESS = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
159
+ const COMPUTE_UNIT_LIMIT = 2e4;
160
+ const COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
161
+ const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
162
+ const USDC_DECIMALS = 6;
163
+ const MAINNET_RPC_URLS = ["https://api.mainnet.solana.com", "https://public.rpc.solanavibestation.com"];
164
+ /**
165
+ * Create a failover transport that tries each RPC in order.
166
+ * On 429 from one endpoint, immediately tries the next instead of waiting.
167
+ * Each transport gets its own coalescing via createDefaultRpcTransport.
168
+ */
169
+ function createFailoverTransport(urls) {
170
+ const transports = urls.map((url) => createDefaultRpcTransport({ url }));
171
+ const failover = (async (config) => {
172
+ let lastError;
173
+ for (const transport of transports) try {
174
+ return await transport(config);
175
+ } catch (e) {
176
+ lastError = e;
177
+ if (isSolanaError(e, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR) && e.context.statusCode === 429) continue;
178
+ throw e;
179
+ }
180
+ throw lastError;
181
+ });
182
+ return failover;
183
+ }
184
+ function createRpcClient(customRpcUrl) {
185
+ return createSolanaRpcFromTransport(createFailoverTransport((customRpcUrl ? [customRpcUrl, ...MAINNET_RPC_URLS] : MAINNET_RPC_URLS).map((u) => mainnet(u))));
186
+ }
187
+ /**
188
+ * Optimized ExactSvmScheme that replaces upstream @x402/svm to prevent
189
+ * RPC rate-limit failures on parallel payments.
190
+ *
191
+ * Two optimizations over upstream:
192
+ * 1. Shared RPC client - @solana/kit's built-in request coalescing
193
+ * merges identical getLatestBlockhash calls in the same tick into 1.
194
+ * 2. Hardcoded USDC - skips fetchMint RPC call for USDC (immutable data).
195
+ */
196
+ var OptimizedSvmScheme = class {
197
+ scheme = "exact";
198
+ rpc;
199
+ constructor(signer, config) {
200
+ this.signer = signer;
201
+ this.rpc = createRpcClient(config?.rpcUrl);
202
+ }
203
+ async createPaymentPayload(x402Version, paymentRequirements) {
204
+ const rpc = this.rpc;
205
+ const asset = paymentRequirements.asset;
206
+ let tokenProgramAddress;
207
+ let decimals;
208
+ if (asset === USDC_MINT) {
209
+ tokenProgramAddress = TOKEN_PROGRAM_ADDRESS;
210
+ decimals = USDC_DECIMALS;
211
+ } else {
212
+ const tokenMint = await fetchMint(rpc, asset);
213
+ tokenProgramAddress = tokenMint.programAddress;
214
+ if (tokenProgramAddress !== TOKEN_PROGRAM_ADDRESS && tokenProgramAddress !== TOKEN_2022_PROGRAM_ADDRESS) throw new Error("Asset was not created by a known token program");
215
+ decimals = tokenMint.data.decimals;
216
+ }
217
+ const [sourceATA] = await findAssociatedTokenPda({
218
+ mint: asset,
219
+ owner: this.signer.address,
220
+ tokenProgram: tokenProgramAddress
221
+ });
222
+ const [destinationATA] = await findAssociatedTokenPda({
223
+ mint: asset,
224
+ owner: paymentRequirements.payTo,
225
+ tokenProgram: tokenProgramAddress
226
+ });
227
+ const transferIx = getTransferCheckedInstruction({
228
+ source: sourceATA,
229
+ mint: asset,
230
+ destination: destinationATA,
231
+ authority: this.signer,
232
+ amount: BigInt(paymentRequirements.amount),
233
+ decimals
234
+ }, { programAddress: tokenProgramAddress });
235
+ const feePayer = paymentRequirements.extra?.feePayer;
236
+ if (!feePayer) throw new Error("feePayer is required in paymentRequirements.extra for SVM transactions");
237
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
238
+ const nonce = crypto.getRandomValues(new Uint8Array(16));
239
+ const memoIx = {
240
+ programAddress: MEMO_PROGRAM_ADDRESS,
241
+ accounts: [],
242
+ data: new TextEncoder().encode(Array.from(nonce).map((b) => b.toString(16).padStart(2, "0")).join(""))
243
+ };
244
+ return {
245
+ x402Version,
246
+ payload: { transaction: getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(pipe(createTransactionMessage({ version: 0 }), (tx) => setTransactionMessageComputeUnitPrice(COMPUTE_UNIT_PRICE_MICROLAMPORTS, tx), (tx) => setTransactionMessageFeePayer(feePayer, tx), (tx) => prependTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: COMPUTE_UNIT_LIMIT }), tx), (tx) => appendTransactionMessageInstructions([transferIx, memoIx], tx), (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)))) }
247
+ };
248
+ }
249
+ };
250
+ //#endregion
155
251
  //#region src/lib/resolve-wallet.ts
156
252
  /**
157
253
  * Resolve wallet keys following the priority cascade:
@@ -282,7 +378,8 @@ async function buildX402Client(wallet, opts) {
282
378
  }
283
379
  if (wallet.solanaKey) {
284
380
  const { createKeyPairSignerFromBytes } = await import("@solana/kit");
285
- registerExactSvmScheme(client, { signer: await createKeyPairSignerFromBytes(wallet.solanaKey) });
381
+ const signer = await createKeyPairSignerFromBytes(wallet.solanaKey);
382
+ client.register("solana:*", new OptimizedSvmScheme(signer));
286
383
  }
287
384
  client.registerPolicy(createAddressValidationPolicy());
288
385
  if (opts?.network) client.registerPolicy(createNetworkFilter(opts.network));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-proxy",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
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,
@@ -35,8 +35,12 @@
35
35
  "@scure/bip32": "^2.0.1",
36
36
  "@scure/bip39": "^2.0.1",
37
37
  "@sinclair/typebox": "^0.34.48",
38
+ "@solana-program/compute-budget": "^0.15.0",
39
+ "@solana-program/token": "^0.12.0",
40
+ "@solana-program/token-2022": "^0.9.0",
38
41
  "@solana/kit": "^6.5.0",
39
42
  "@stricli/core": "^1.2.6",
43
+ "@x402/core": "^2.8.0",
40
44
  "@x402/evm": "^2.8.0",
41
45
  "@x402/fetch": "^2.8.0",
42
46
  "@x402/mcp": "^2.8.0",
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as displayStatus } from "./status-ZRhJKaXq.js";
3
- export { displayStatus };
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import { n as fetchAllBalances } from "./wallet-Bs8cBOv7.js";
3
- export { fetchAllBalances };