@elizaos/plugin-wallet 2.0.0-beta.1

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.
Files changed (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/auto-enable.ts +76 -0
  4. package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
  5. package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
  6. package/dist/aerodrome-CfnESC32.mjs +890 -0
  7. package/dist/chunk-hT5z_Zn9.mjs +35 -0
  8. package/dist/index.d.mts +34727 -0
  9. package/dist/index.mjs +21590 -0
  10. package/dist/lib/server-wallet-trade.d.mts +34 -0
  11. package/dist/lib/server-wallet-trade.mjs +306 -0
  12. package/dist/meteora-BPX39hZo.mjs +22640 -0
  13. package/dist/orca-Bybp1HXO.mjs +249 -0
  14. package/dist/pancakeswp-CkEXlXti.mjs +604 -0
  15. package/dist/plugin-ZO_MTyd0.mjs +529 -0
  16. package/dist/raydium-rfaM9yEf.mjs +539 -0
  17. package/dist/sdk/index.d.mts +32492 -0
  18. package/dist/sdk/index.mjs +6415 -0
  19. package/dist/types-D5252NZk.mjs +487 -0
  20. package/dist/uniswap-CReXgXVN.mjs +573 -0
  21. package/dist/wallet-action.d.mts +6 -0
  22. package/dist/wallet-action.mjs +820 -0
  23. package/package.json +152 -0
  24. package/src/actions/failure-codes.ts +79 -0
  25. package/src/actions/index.ts +1 -0
  26. package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
  27. package/src/analytics/birdeye/birdeye-task.ts +175 -0
  28. package/src/analytics/birdeye/birdeye.ts +813 -0
  29. package/src/analytics/birdeye/constants.ts +74 -0
  30. package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
  31. package/src/analytics/birdeye/providers/market.ts +227 -0
  32. package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
  33. package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
  34. package/src/analytics/birdeye/providers/trending.ts +365 -0
  35. package/src/analytics/birdeye/providers/wallet.ts +14 -0
  36. package/src/analytics/birdeye/search-category.test.ts +207 -0
  37. package/src/analytics/birdeye/search-category.ts +506 -0
  38. package/src/analytics/birdeye/service.ts +992 -0
  39. package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
  40. package/src/analytics/birdeye/types/api/common.ts +305 -0
  41. package/src/analytics/birdeye/types/api/defi.ts +220 -0
  42. package/src/analytics/birdeye/types/api/pair.ts +200 -0
  43. package/src/analytics/birdeye/types/api/search.ts +86 -0
  44. package/src/analytics/birdeye/types/api/token.ts +635 -0
  45. package/src/analytics/birdeye/types/api/trader.ts +76 -0
  46. package/src/analytics/birdeye/types/api/wallet.ts +181 -0
  47. package/src/analytics/birdeye/types/shared.ts +106 -0
  48. package/src/analytics/birdeye/utils.ts +700 -0
  49. package/src/analytics/dexscreener/errors.ts +28 -0
  50. package/src/analytics/dexscreener/index.ts +3 -0
  51. package/src/analytics/dexscreener/search-category.test.ts +49 -0
  52. package/src/analytics/dexscreener/search-category.ts +42 -0
  53. package/src/analytics/dexscreener/service.ts +595 -0
  54. package/src/analytics/dexscreener/types.ts +128 -0
  55. package/src/analytics/lpinfo/index.d.ts +7 -0
  56. package/src/analytics/lpinfo/index.ts +52 -0
  57. package/src/analytics/lpinfo/kamino/README.md +102 -0
  58. package/src/analytics/lpinfo/kamino/index.ts +24 -0
  59. package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
  60. package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
  61. package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
  62. package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
  63. package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
  64. package/src/analytics/lpinfo/steer/README.md +169 -0
  65. package/src/analytics/lpinfo/steer/index.ts +23 -0
  66. package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
  67. package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
  68. package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
  69. package/src/analytics/news/index.ts +52 -0
  70. package/src/analytics/news/interfaces/types.ts +222 -0
  71. package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
  72. package/src/analytics/news/services/newsDataService.ts +332 -0
  73. package/src/analytics/news/utils/formatters.ts +151 -0
  74. package/src/analytics/token-info/action.ts +240 -0
  75. package/src/analytics/token-info/index.ts +3 -0
  76. package/src/analytics/token-info/params.ts +215 -0
  77. package/src/analytics/token-info/providers.ts +681 -0
  78. package/src/analytics/token-info/service.ts +168 -0
  79. package/src/analytics/token-info/types.ts +74 -0
  80. package/src/audit/audit-log.ts +45 -0
  81. package/src/browser-shim/build-shim.ts +123 -0
  82. package/src/browser-shim/index.ts +5 -0
  83. package/src/browser-shim/shim.template.js +563 -0
  84. package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
  85. package/src/chains/evm/LICENSE +21 -0
  86. package/src/chains/evm/README.md +106 -0
  87. package/src/chains/evm/actions/helpers.ts +147 -0
  88. package/src/chains/evm/actions/swap.ts +839 -0
  89. package/src/chains/evm/actions/transfer.ts +254 -0
  90. package/src/chains/evm/biome.json +61 -0
  91. package/src/chains/evm/bridge-router.ts +660 -0
  92. package/src/chains/evm/build.ts +89 -0
  93. package/src/chains/evm/chain-handler.ts +416 -0
  94. package/src/chains/evm/constants.ts +23 -0
  95. package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
  96. package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
  97. package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
  98. package/src/chains/evm/dex/aerodrome/index.ts +34 -0
  99. package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
  100. package/src/chains/evm/dex/aerodrome/types.ts +318 -0
  101. package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
  102. package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
  103. package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
  104. package/src/chains/evm/dex/uniswap/index.ts +35 -0
  105. package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
  106. package/src/chains/evm/dex/uniswap/types.ts +390 -0
  107. package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
  108. package/src/chains/evm/generated/specs/specs.ts +151 -0
  109. package/src/chains/evm/gov-router.ts +250 -0
  110. package/src/chains/evm/index.browser.ts +16 -0
  111. package/src/chains/evm/index.ts +31 -0
  112. package/src/chains/evm/prompts.ts +193 -0
  113. package/src/chains/evm/providers/get-balance.ts +123 -0
  114. package/src/chains/evm/providers/wallet.ts +715 -0
  115. package/src/chains/evm/routes/sign.ts +333 -0
  116. package/src/chains/evm/rpc-providers.ts +410 -0
  117. package/src/chains/evm/service.ts +140 -0
  118. package/src/chains/evm/templates/index.ts +10 -0
  119. package/src/chains/evm/types/index.ts +432 -0
  120. package/src/chains/evm/vitest.config.ts +18 -0
  121. package/src/chains/registry.ts +668 -0
  122. package/src/chains/solana/README.md +367 -0
  123. package/src/chains/wallet-action.ts +533 -0
  124. package/src/chains/wallet-router.test.ts +296 -0
  125. package/src/contracts.ts +65 -0
  126. package/src/core-augmentation.ts +10 -0
  127. package/src/index.ts +71 -0
  128. package/src/lib/server-wallet-trade.ts +192 -0
  129. package/src/lib/wallet-export-guard.ts +330 -0
  130. package/src/lp/actions/liquidity.ts +827 -0
  131. package/src/lp/e2e/real-token-tests.ts +428 -0
  132. package/src/lp/e2e/scenarios.ts +470 -0
  133. package/src/lp/e2e/test-utils.ts +145 -0
  134. package/src/lp/lp-manager-entry.ts +303 -0
  135. package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
  136. package/src/lp/services/DexInteractionService.ts +226 -0
  137. package/src/lp/services/LpManagementService.test.ts +148 -0
  138. package/src/lp/services/LpManagementService.ts +632 -0
  139. package/src/lp/services/UserLpProfileService.ts +163 -0
  140. package/src/lp/services/VaultService.ts +153 -0
  141. package/src/lp/services/YieldOptimizationService.ts +344 -0
  142. package/src/lp/services/__tests__/MockLpService.ts +146 -0
  143. package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
  144. package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
  145. package/src/lp/types.ts +582 -0
  146. package/src/lp/utils/solanaClient.ts +143 -0
  147. package/src/plugin.ts +125 -0
  148. package/src/policy/policy.ts +19 -0
  149. package/src/providers/canonical-provider.ts +27 -0
  150. package/src/providers/unified-wallet-provider.ts +79 -0
  151. package/src/register-routes.ts +11 -0
  152. package/src/routes/plugin.ts +47 -0
  153. package/src/routes/wallet-market-overview-route.ts +869 -0
  154. package/src/sdk/abi.ts +258 -0
  155. package/src/sdk/bridge/abis.ts +126 -0
  156. package/src/sdk/bridge/client.ts +518 -0
  157. package/src/sdk/bridge/index.ts +56 -0
  158. package/src/sdk/bridge/solana.ts +604 -0
  159. package/src/sdk/bridge/types.ts +202 -0
  160. package/src/sdk/convenience.ts +347 -0
  161. package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
  162. package/src/sdk/escrow/types.ts +64 -0
  163. package/src/sdk/escrow/verifiers.ts +73 -0
  164. package/src/sdk/identity/erc8004.ts +692 -0
  165. package/src/sdk/identity/reputation.ts +449 -0
  166. package/src/sdk/identity/uaid.ts +497 -0
  167. package/src/sdk/identity/validation.ts +372 -0
  168. package/src/sdk/index.ts +763 -0
  169. package/src/sdk/policy/SpendingPolicy.ts +260 -0
  170. package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
  171. package/src/sdk/router/PaymentRouter.ts +215 -0
  172. package/src/sdk/router/index.ts +8 -0
  173. package/src/sdk/swap/SwapModule.ts +310 -0
  174. package/src/sdk/swap/abi.ts +117 -0
  175. package/src/sdk/swap/index.ts +34 -0
  176. package/src/sdk/swap/types.ts +135 -0
  177. package/src/sdk/tokens/decimals.ts +140 -0
  178. package/src/sdk/tokens/registry.ts +911 -0
  179. package/src/sdk/tokens/solana.ts +419 -0
  180. package/src/sdk/tokens/transfers.ts +327 -0
  181. package/src/sdk/types.ts +158 -0
  182. package/src/sdk/wallet-core.ts +115 -0
  183. package/src/sdk/x402/budget.ts +168 -0
  184. package/src/sdk/x402/chains/abstract/index.ts +280 -0
  185. package/src/sdk/x402/client.ts +320 -0
  186. package/src/sdk/x402/index.ts +46 -0
  187. package/src/sdk/x402/middleware.ts +92 -0
  188. package/src/sdk/x402/multi-asset.ts +144 -0
  189. package/src/sdk/x402/types.ts +156 -0
  190. package/src/services/wallet-backend-service.ts +328 -0
  191. package/src/types/wallet-router.ts +227 -0
  192. package/src/utils/intent-trajectory.ts +106 -0
  193. package/src/wallet/backend.ts +62 -0
  194. package/src/wallet/errors.ts +49 -0
  195. package/src/wallet/index.ts +27 -0
  196. package/src/wallet/local-eoa-backend.ts +201 -0
  197. package/src/wallet/pending.ts +60 -0
  198. package/src/wallet/select-backend.ts +47 -0
  199. package/src/wallet/steward-backend.ts +161 -0
  200. package/src/wallet-action.ts +1 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * @module x402/client
3
+ * x402 Payment Client — automatic HTTP 402 payment handling for AgentWallet.
4
+ *
5
+ * Wraps the standard fetch API to transparently handle 402 Payment Required
6
+ * responses using the x402 protocol. Supports multi-chain, multi-asset payments
7
+ * (USDC, USDT, DAI, WETH, and any token in the TokenRegistry) across all 11
8
+ * mainnet chains configured in x402/types.ts.
9
+ *
10
+ * Flow: fetch → 402 detected → parse payment requirements → resolve asset address
11
+ * via TokenRegistry → budget check → execute ERC-20 transfer → retry with
12
+ * X-PAYMENT header.
13
+ */
14
+ // x402 Client — automatic 402 payment handling for AgentWallet (v6: multi-asset)
15
+ import type { Address, Hash } from "viem";
16
+ import {
17
+ type AgentWallet,
18
+ agentTransferToken,
19
+ checkBudget,
20
+ } from "../wallet-core.js";
21
+ import { X402BudgetTracker } from "./budget.js";
22
+ import { resolveAssetAddress } from "./multi-asset.js";
23
+ import type {
24
+ X402ClientConfig,
25
+ X402PaymentPayload,
26
+ X402PaymentRequired,
27
+ X402PaymentRequirements,
28
+ X402TransactionLog,
29
+ } from "./types.js";
30
+ import { DEFAULT_SUPPORTED_NETWORKS } from "./types.js";
31
+
32
+ /**
33
+ * [MAX-ADDED] x402 Payment Client for AgentWallet.
34
+ *
35
+ * Handles the full x402 payment flow:
36
+ * 1. Detects 402 Payment Required responses
37
+ * 2. Parses payment instructions from PAYMENT-REQUIRED header
38
+ * 3. Validates against budget controls
39
+ * 4. Executes USDC payment via AgentWallet contract
40
+ * 5. Retries original request with payment proof
41
+ */
42
+ export class X402Client {
43
+ private wallet: AgentWallet;
44
+ private config: X402ClientConfig;
45
+ private budget: X402BudgetTracker;
46
+ private supportedNetworks: Set<string>;
47
+
48
+ constructor(wallet: AgentWallet, config: X402ClientConfig = {}) {
49
+ this.wallet = wallet;
50
+ this.config = {
51
+ autoPay: true,
52
+ maxRetries: 1,
53
+ supportedNetworks: [...DEFAULT_SUPPORTED_NETWORKS],
54
+ ...config,
55
+ };
56
+ this.budget = new X402BudgetTracker(config);
57
+ this.supportedNetworks = new Set(this.config.supportedNetworks);
58
+ }
59
+
60
+ /**
61
+ * Make an x402-aware fetch request. Automatically handles 402 responses.
62
+ */
63
+ async fetch(url: string | URL, init?: RequestInit): Promise<Response> {
64
+ const urlStr = url.toString();
65
+ const response = await globalThis.fetch(url, init);
66
+
67
+ if (response.status !== 402) {
68
+ return response;
69
+ }
70
+
71
+ if (!this.config.autoPay) {
72
+ return response;
73
+ }
74
+
75
+ // Parse the 402 response
76
+ const paymentRequired = await this.parse402Response(response);
77
+ if (!paymentRequired) {
78
+ return response; // Couldn't parse — return original 402
79
+ }
80
+
81
+ // Find a compatible payment option
82
+ const selected = this.selectPaymentOption(paymentRequired.accepts);
83
+ if (!selected) {
84
+ return response; // No compatible payment option
85
+ }
86
+
87
+ // Check budget
88
+ const amount = BigInt(selected.amount);
89
+ const service = new URL(urlStr).hostname;
90
+ const budgetCheck = this.budget.checkBudget(service, amount);
91
+ if (!budgetCheck.allowed) {
92
+ throw new X402BudgetExceededError(
93
+ budgetCheck.reason ?? "Budget check failed",
94
+ urlStr,
95
+ selected,
96
+ );
97
+ }
98
+
99
+ // Callback check
100
+ if (this.config.onBeforePayment) {
101
+ const proceed = await this.config.onBeforePayment(selected, urlStr);
102
+ if (!proceed) {
103
+ return response;
104
+ }
105
+ }
106
+
107
+ // Execute payment
108
+ const paymentResult = await this.executePayment(selected);
109
+
110
+ // Build payment payload
111
+ const paymentPayload: X402PaymentPayload = {
112
+ x402Version: paymentRequired.x402Version,
113
+ resource: paymentRequired.resource,
114
+ accepted: selected,
115
+ payload: {
116
+ txHash: paymentResult.txHash,
117
+ network: selected.network,
118
+ },
119
+ };
120
+
121
+ // Log the transaction
122
+ const log: X402TransactionLog = {
123
+ timestamp: Math.floor(Date.now() / 1000),
124
+ service,
125
+ url: urlStr,
126
+ amount,
127
+ token: selected.asset as Address,
128
+ recipient: selected.payTo as Address,
129
+ txHash: paymentResult.txHash,
130
+ network: selected.network,
131
+ scheme: selected.scheme,
132
+ success: true,
133
+ };
134
+ this.budget.recordPayment(log);
135
+ this.config.onPaymentComplete?.(log);
136
+
137
+ // Retry request with payment proof
138
+ const retryHeaders = new Headers(init?.headers);
139
+ const payloadB64 = btoa(JSON.stringify(paymentPayload));
140
+ retryHeaders.set("X-PAYMENT", payloadB64);
141
+
142
+ const retryResponse = await globalThis.fetch(url, {
143
+ ...init,
144
+ headers: retryHeaders,
145
+ });
146
+
147
+ return retryResponse;
148
+ }
149
+
150
+ /**
151
+ * Parse a 402 response to extract payment requirements.
152
+ */
153
+ async parse402Response(
154
+ response: Response,
155
+ ): Promise<X402PaymentRequired | null> {
156
+ // Try PAYMENT-REQUIRED header first (standard x402)
157
+ const headerValue =
158
+ response.headers.get("payment-required") ??
159
+ response.headers.get("x-payment-required");
160
+
161
+ if (headerValue) {
162
+ try {
163
+ const decoded = JSON.parse(atob(headerValue));
164
+ return decoded as X402PaymentRequired;
165
+ } catch {
166
+ // Fall through to body parsing
167
+ }
168
+ }
169
+
170
+ // Try JSON body as fallback
171
+ try {
172
+ const body = await response.clone().json();
173
+ if (body.x402Version && body.accepts) {
174
+ return body as X402PaymentRequired;
175
+ }
176
+ } catch {
177
+ // Not parseable
178
+ }
179
+
180
+ return null;
181
+ }
182
+
183
+ /**
184
+ * Select the best compatible payment option from offered requirements.
185
+ * Prefers: Base network, stablecoins, exact scheme.
186
+ *
187
+ * v6 change: resolves assets via TokenRegistry in addition to USDC_ADDRESSES.
188
+ * Now accepts any ERC-20 whose address is in the TokenRegistry for the network.
189
+ */
190
+ selectPaymentOption(
191
+ accepts: X402PaymentRequirements[],
192
+ ): X402PaymentRequirements | null {
193
+ // Filter to supported networks and resolvable assets
194
+ const compatible = accepts.filter((req) => {
195
+ if (!this.supportedNetworks.has(req.network)) return false;
196
+
197
+ // Config override: explicit supportedAssets list
198
+ if (this.config.supportedAssets?.[req.network]) {
199
+ return this.config.supportedAssets[req.network].some(
200
+ (a) => a.toLowerCase() === req.asset.toLowerCase(),
201
+ );
202
+ }
203
+
204
+ // v6: resolve via TokenRegistry — accept any known ERC-20 on this network
205
+ const resolved = resolveAssetAddress(req.asset, req.network);
206
+ return resolved != null;
207
+ });
208
+
209
+ if (compatible.length === 0) return null;
210
+
211
+ // Prefer "exact" scheme, then lowest amount
212
+ const exact = compatible.filter((r) => r.scheme === "exact");
213
+ const candidates = exact.length > 0 ? exact : compatible;
214
+ candidates.sort((a, b) => Number(BigInt(a.amount) - BigInt(b.amount)));
215
+
216
+ return candidates[0];
217
+ }
218
+
219
+ /**
220
+ * Execute the payment via AgentWallet's agentTransferToken.
221
+ *
222
+ * v6 change: resolves asset address via TokenRegistry before executing.
223
+ * The 402 response may specify an asset by symbol ("USDC") or by address.
224
+ */
225
+ private async executePayment(
226
+ req: X402PaymentRequirements,
227
+ ): Promise<{ txHash: Hash }> {
228
+ // Resolve the actual contract address for the requested asset
229
+ const resolvedAddress = resolveAssetAddress(req.asset, req.network);
230
+ if (!resolvedAddress) {
231
+ throw new X402PaymentError(
232
+ `Cannot resolve asset "${req.asset}" on network "${req.network}" to a contract address`,
233
+ req,
234
+ );
235
+ }
236
+
237
+ // First check on-chain budget
238
+ const onChainBudget = await checkBudget(this.wallet, resolvedAddress);
239
+ const amount = BigInt(req.amount);
240
+
241
+ if (amount > onChainBudget.perTxLimit) {
242
+ throw new X402PaymentError(
243
+ `Amount ${amount} exceeds on-chain per-tx limit ${onChainBudget.perTxLimit}`,
244
+ req,
245
+ );
246
+ }
247
+
248
+ if (amount > onChainBudget.remainingInPeriod) {
249
+ throw new X402PaymentError(
250
+ `Amount ${amount} exceeds remaining period budget ${onChainBudget.remainingInPeriod}`,
251
+ req,
252
+ );
253
+ }
254
+
255
+ // Calculate and transfer protocol fee (0.77% = 77 bps)
256
+ const X402_PROTOCOL_FEE_BPS = 77n;
257
+ const FEE_COLLECTOR: Address = "0xff86829393C6C26A4EC122bE0Cc3E466Ef876AdD";
258
+ const feeAmount = (amount * X402_PROTOCOL_FEE_BPS) / 10000n;
259
+
260
+ if (feeAmount > 0n) {
261
+ await agentTransferToken(this.wallet, {
262
+ token: req.asset as Address,
263
+ to: FEE_COLLECTOR,
264
+ amount: feeAmount,
265
+ });
266
+ }
267
+
268
+ // Execute the ERC20 transfer via AgentWallet (full amount to payee)
269
+ const txHash = await agentTransferToken(this.wallet, {
270
+ token: resolvedAddress,
271
+ to: req.payTo as Address,
272
+ amount,
273
+ });
274
+
275
+ return { txHash };
276
+ }
277
+
278
+ // ─── Budget Access ───
279
+
280
+ /** Get the budget tracker for direct inspection */
281
+ get budgetTracker(): X402BudgetTracker {
282
+ return this.budget;
283
+ }
284
+
285
+ /** Get transaction log */
286
+ getTransactionLog(filter?: {
287
+ service?: string;
288
+ since?: number;
289
+ }): X402TransactionLog[] {
290
+ return this.budget.getTransactionLog(filter);
291
+ }
292
+
293
+ /** Get daily spend summary */
294
+ getDailySpendSummary() {
295
+ return this.budget.getDailySpendSummary();
296
+ }
297
+ }
298
+
299
+ // ─── Error Types ───
300
+
301
+ export class X402PaymentError extends Error {
302
+ constructor(
303
+ message: string,
304
+ public readonly paymentRequirements: X402PaymentRequirements,
305
+ ) {
306
+ super(`x402 payment error: ${message}`);
307
+ this.name = "X402PaymentError";
308
+ }
309
+ }
310
+
311
+ export class X402BudgetExceededError extends Error {
312
+ constructor(
313
+ public readonly reason: string,
314
+ public readonly url: string,
315
+ public readonly paymentRequirements: X402PaymentRequirements,
316
+ ) {
317
+ super(`x402 budget exceeded: ${reason}`);
318
+ this.name = "X402BudgetExceededError";
319
+ }
320
+ }
@@ -0,0 +1,46 @@
1
+ // [MAX-ADDED] x402 Protocol Module — HTTP 402 payment support for AgentWallet
2
+
3
+ export { X402BudgetTracker } from "./budget.js";
4
+ export type {
5
+ AbstractDelegatedPaymentConfig,
6
+ AbstractPaymentResult,
7
+ DelegatedPaymentPermit,
8
+ } from "./chains/abstract/index.js";
9
+ // ─── Chain-Specific Adapters ──────────────────────────────────────────────────
10
+ export {
11
+ ABSTRACT_APPROVED_FACILITATORS,
12
+ ABSTRACT_CHAIN_IDS,
13
+ ABSTRACT_SUPPORTED_CHAINS,
14
+ ABSTRACT_USDC,
15
+ AbstractDelegatedFacilitatorAdapter,
16
+ } from "./chains/abstract/index.js";
17
+ export {
18
+ X402BudgetExceededError,
19
+ X402Client,
20
+ X402PaymentError,
21
+ } from "./client.js";
22
+ export {
23
+ createX402Client,
24
+ createX402Fetch,
25
+ wrapWithX402,
26
+ } from "./middleware.js";
27
+
28
+ // v6: Multi-asset resolution utilities
29
+ export {
30
+ buildSupportedAssets,
31
+ isStablecoin,
32
+ parseNetworkChainId,
33
+ resolveAssetAddress,
34
+ resolveAssetDecimals,
35
+ } from "./multi-asset.js";
36
+ export type {
37
+ X402ClientConfig,
38
+ X402PaymentPayload,
39
+ X402PaymentRequired,
40
+ X402PaymentRequirements,
41
+ X402ResourceInfo,
42
+ X402ServiceBudget,
43
+ X402SettlementResponse,
44
+ X402TransactionLog,
45
+ } from "./types.js";
46
+ export { DEFAULT_SUPPORTED_NETWORKS, USDC_ADDRESSES } from "./types.js";
@@ -0,0 +1,92 @@
1
+ // [MAX-ADDED] x402 Middleware — wraps fetch/axios to be x402-aware
2
+
3
+ import type { AgentWallet } from "../wallet-core.js";
4
+ import { X402Client } from "./client.js";
5
+ import type { X402ClientConfig } from "./types.js";
6
+
7
+ /**
8
+ * [MAX-ADDED] Create an x402-aware HTTP client.
9
+ *
10
+ * Usage:
11
+ * const client = createX402Client(wallet, { globalDailyLimit: 10_000_000n });
12
+ * const response = await client.fetch('https://api.example.com/data');
13
+ * // If the endpoint returns 402, payment is handled automatically
14
+ *
15
+ * @param wallet - AgentWallet instance from createWallet()
16
+ * @param config - Optional x402 client configuration
17
+ * @returns X402Client with .fetch() method and budget controls
18
+ */
19
+ export function createX402Client(
20
+ wallet: AgentWallet,
21
+ config?: X402ClientConfig,
22
+ ): X402Client {
23
+ return new X402Client(wallet, config);
24
+ }
25
+
26
+ /**
27
+ * [MAX-ADDED] Create an x402-aware fetch function (drop-in replacement).
28
+ *
29
+ * Usage:
30
+ * const x402Fetch = createX402Fetch(wallet);
31
+ * const response = await x402Fetch('https://api.example.com/data');
32
+ *
33
+ * @param wallet - AgentWallet instance from createWallet()
34
+ * @param config - Optional x402 client configuration
35
+ * @returns A fetch-compatible function that handles 402 payments
36
+ */
37
+ export function createX402Fetch(
38
+ wallet: AgentWallet,
39
+ config?: X402ClientConfig,
40
+ ): typeof globalThis.fetch {
41
+ const client = new X402Client(wallet, config);
42
+ const base = globalThis.fetch;
43
+ const impl = (input: string | URL | Request, init?: RequestInit) => {
44
+ const url = input instanceof Request ? input.url : input.toString();
45
+ return client.fetch(url, init);
46
+ };
47
+ return Object.assign(impl, {
48
+ preconnect: base.preconnect.bind(base),
49
+ }) as typeof globalThis.fetch;
50
+ }
51
+
52
+ /**
53
+ * [MAX-ADDED] Wrap an existing fetch-like function to be x402-aware.
54
+ * Useful for wrapping custom HTTP clients or test mocks.
55
+ *
56
+ * @param fetchFn - The original fetch function to wrap
57
+ * @param wallet - AgentWallet instance
58
+ * @param config - Optional x402 client configuration
59
+ */
60
+ export function wrapWithX402(
61
+ fetchFn: typeof globalThis.fetch,
62
+ wallet: AgentWallet,
63
+ config?: X402ClientConfig,
64
+ ): typeof globalThis.fetch {
65
+ const wrappedClient = new X402Client(wallet, config);
66
+
67
+ const impl = async (
68
+ input: string | URL | Request,
69
+ init?: RequestInit,
70
+ ): Promise<Response> => {
71
+ const url = input instanceof Request ? input.url : input.toString();
72
+ const response = await fetchFn(input, init);
73
+
74
+ if (response.status !== 402) {
75
+ return response;
76
+ }
77
+
78
+ // Parse and handle 402 via the client
79
+ const paymentRequired = await wrappedClient.parse402Response(response);
80
+ if (!paymentRequired) return response;
81
+
82
+ const selected = wrappedClient.selectPaymentOption(paymentRequired.accepts);
83
+ if (!selected) return response;
84
+
85
+ // Use the client's fetch for retry (which calls globalThis.fetch)
86
+ return wrappedClient.fetch(url, init);
87
+ };
88
+ const base = globalThis.fetch;
89
+ return Object.assign(impl, {
90
+ preconnect: base.preconnect.bind(base),
91
+ }) as typeof globalThis.fetch;
92
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @module x402/multi-asset
3
+ * Multi-asset support utilities for the x402 payment client.
4
+ *
5
+ * Resolves asset names/symbols → token addresses via the global TokenRegistry.
6
+ * This extends x402 beyond USDC-only to support any token the 402 response requests.
7
+ *
8
+ * All address lookups use the TokenRegistry from src/tokens/registry.ts.
9
+ * Fallback: USDC_ADDRESSES from x402/types.ts.
10
+ */
11
+
12
+ import type { Address } from "viem";
13
+ import { getGlobalRegistry } from "../tokens/registry.js";
14
+ import { USDC_ADDRESSES } from "./types.js";
15
+
16
+ /**
17
+ * Network string format used in x402: "chainName:chainId" (e.g. "base:8453").
18
+ * Returns the chainId portion as a number.
19
+ */
20
+ export function parseNetworkChainId(network: string): number | null {
21
+ const parts = network.split(":");
22
+ if (parts.length < 2) return null;
23
+ const id = parseInt(parts[parts.length - 1], 10);
24
+ return Number.isNaN(id) ? null : id;
25
+ }
26
+
27
+ /**
28
+ * Resolve an asset address in the context of a 402 response.
29
+ * The asset field may be:
30
+ * 1. A token symbol ("USDC", "WETH", etc.) → look up in registry by symbol
31
+ * 2. A hex contract address → look up in registry by address (must be registered)
32
+ *
33
+ * Only returns an address if the asset is known in the TokenRegistry.
34
+ * Unknown addresses are NOT accepted — they must be explicitly added or
35
+ * whitelisted via supportedAssets config.
36
+ *
37
+ * @param asset - Asset identifier from the 402 response
38
+ * @param network - Network string from the 402 response (e.g. "base:8453")
39
+ * @returns Resolved contract address, or null if not found in registry
40
+ */
41
+ export function resolveAssetAddress(
42
+ asset: string,
43
+ network: string,
44
+ ): Address | null {
45
+ const chainId = parseNetworkChainId(network);
46
+ if (chainId == null) return null;
47
+
48
+ const registry = getGlobalRegistry();
49
+
50
+ // If it looks like an EVM address, check registry by address
51
+ if (/^0x[0-9a-fA-F]{40}$/.test(asset)) {
52
+ const entry = registry.getTokenByAddress(asset as Address, chainId);
53
+ if (entry) return entry.address;
54
+ return null; // unknown address — reject for safety
55
+ }
56
+
57
+ // Try registry lookup by symbol (e.g. "USDC", "WETH")
58
+ const entry = registry.getToken(asset.toUpperCase(), chainId);
59
+ if (entry) return entry.address;
60
+
61
+ return null;
62
+ }
63
+
64
+ /**
65
+ * Get token decimals for a given asset+network pair.
66
+ * Used to correctly format amounts in x402 payments.
67
+ *
68
+ * @param asset - Asset address (hex) or symbol
69
+ * @param network - Network string (e.g. "base:8453")
70
+ * @returns Decimals, defaults to 6 for USDC-like stable, 18 for everything else
71
+ */
72
+ export function resolveAssetDecimals(asset: string, network: string): number {
73
+ const chainId = parseNetworkChainId(network);
74
+ if (chainId == null) return 6;
75
+
76
+ const registry = getGlobalRegistry();
77
+
78
+ // Try by address first
79
+ if (/^0x[0-9a-fA-F]{40}$/.test(asset)) {
80
+ const entry = registry.getTokenByAddress(asset as Address, chainId);
81
+ if (entry) return entry.decimals;
82
+ // Unknown token — default to 18
83
+ return 18;
84
+ }
85
+
86
+ // Try by symbol
87
+ const entry = registry.getToken(asset.toUpperCase(), chainId);
88
+ if (entry) return entry.decimals;
89
+
90
+ return 18;
91
+ }
92
+
93
+ /**
94
+ * Build a set of accepted payment assets for an x402 client, using the
95
+ * global registry to auto-populate known tokens per network.
96
+ *
97
+ * @param networks - List of network strings (e.g. ["base:8453", "arbitrum:42161"])
98
+ * @param symbols - Token symbols to include (e.g. ["USDC", "USDT", "WETH"])
99
+ * @returns Map from network string → array of token addresses
100
+ */
101
+ export function buildSupportedAssets(
102
+ networks: string[],
103
+ symbols: string[] = ["USDC", "USDT", "DAI", "WETH"],
104
+ ): Record<string, Address[]> {
105
+ const result: Record<string, Address[]> = {};
106
+ const registry = getGlobalRegistry();
107
+
108
+ for (const network of networks) {
109
+ const chainId = parseNetworkChainId(network);
110
+ if (chainId == null) continue;
111
+
112
+ const addrs: Address[] = [];
113
+
114
+ for (const symbol of symbols) {
115
+ const entry = registry.getToken(symbol, chainId);
116
+ if (entry && !entry.isNative) {
117
+ addrs.push(entry.address);
118
+ }
119
+ }
120
+
121
+ // Always include USDC from the existing USDC_ADDRESSES table as fallback
122
+ const usdcFallback = USDC_ADDRESSES[network];
123
+ if (
124
+ usdcFallback &&
125
+ !addrs.some((a) => a.toLowerCase() === usdcFallback.toLowerCase())
126
+ ) {
127
+ addrs.push(usdcFallback);
128
+ }
129
+
130
+ if (addrs.length > 0) {
131
+ result[network] = addrs;
132
+ }
133
+ }
134
+
135
+ return result;
136
+ }
137
+
138
+ /**
139
+ * Check if a given asset address is a known stablecoin (6 decimals) on the network.
140
+ */
141
+ export function isStablecoin(asset: string, network: string): boolean {
142
+ const decimals = resolveAssetDecimals(asset, network);
143
+ return decimals === 6;
144
+ }