@veridex/agentic-payments 0.1.1-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 (73) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/MIGRATION.md +307 -0
  3. package/README.md +395 -0
  4. package/dist/index.d.mts +2327 -0
  5. package/dist/index.d.ts +2327 -0
  6. package/dist/index.js +5815 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +5759 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/examples/basic-agent.ts +126 -0
  11. package/examples/mcp-claude.ts +75 -0
  12. package/examples/ucp-checkout.ts +92 -0
  13. package/examples/x402-integration.ts +75 -0
  14. package/package.json +36 -0
  15. package/src/AgentWallet.ts +432 -0
  16. package/src/chains/AptosChainClient.ts +29 -0
  17. package/src/chains/ChainClient.ts +73 -0
  18. package/src/chains/ChainClientFactory.ts +113 -0
  19. package/src/chains/EVMChainClient.ts +39 -0
  20. package/src/chains/SolanaChainClient.ts +37 -0
  21. package/src/chains/StarknetChainClient.ts +36 -0
  22. package/src/chains/SuiChainClient.ts +28 -0
  23. package/src/index.ts +83 -0
  24. package/src/mcp/MCPServer.ts +73 -0
  25. package/src/mcp/schemas.ts +60 -0
  26. package/src/monitoring/AlertManager.ts +258 -0
  27. package/src/monitoring/AuditLogger.ts +86 -0
  28. package/src/monitoring/BalanceCache.ts +44 -0
  29. package/src/monitoring/ComplianceExporter.ts +52 -0
  30. package/src/oracle/PythFeeds.ts +60 -0
  31. package/src/oracle/PythOracle.ts +121 -0
  32. package/src/performance/ConnectionPool.ts +217 -0
  33. package/src/performance/NonceManager.ts +91 -0
  34. package/src/performance/ParallelRouteFinder.ts +438 -0
  35. package/src/performance/TransactionPoller.ts +201 -0
  36. package/src/performance/TransactionQueue.ts +565 -0
  37. package/src/performance/index.ts +46 -0
  38. package/src/react/hooks.ts +298 -0
  39. package/src/routing/BridgeOrchestrator.ts +18 -0
  40. package/src/routing/CrossChainRouter.ts +501 -0
  41. package/src/routing/DEXAggregator.ts +448 -0
  42. package/src/routing/FeeEstimator.ts +43 -0
  43. package/src/session/SessionKeyManager.ts +312 -0
  44. package/src/session/SessionStorage.ts +80 -0
  45. package/src/session/SpendingTracker.ts +71 -0
  46. package/src/types/agent.ts +105 -0
  47. package/src/types/errors.ts +115 -0
  48. package/src/types/mcp.ts +22 -0
  49. package/src/types/ucp.ts +47 -0
  50. package/src/types/x402.ts +170 -0
  51. package/src/ucp/CapabilityNegotiator.ts +44 -0
  52. package/src/ucp/CredentialProvider.ts +73 -0
  53. package/src/ucp/PaymentTokenizer.ts +169 -0
  54. package/src/ucp/TransportAdapter.ts +18 -0
  55. package/src/ucp/UCPClient.ts +143 -0
  56. package/src/x402/NonceManager.ts +26 -0
  57. package/src/x402/PaymentParser.ts +225 -0
  58. package/src/x402/PaymentSigner.ts +305 -0
  59. package/src/x402/X402Client.ts +364 -0
  60. package/src/x402/adapters/CronosFacilitatorAdapter.ts +109 -0
  61. package/tests/alerts.test.ts +208 -0
  62. package/tests/chains.test.ts +242 -0
  63. package/tests/integration.test.ts +315 -0
  64. package/tests/monitoring.test.ts +435 -0
  65. package/tests/performance.test.ts +303 -0
  66. package/tests/property.test.ts +186 -0
  67. package/tests/react-hooks.test.ts +262 -0
  68. package/tests/session.test.ts +376 -0
  69. package/tests/ucp.test.ts +253 -0
  70. package/tests/x402.test.ts +385 -0
  71. package/tsconfig.json +26 -0
  72. package/tsup.config.ts +10 -0
  73. package/vitest.config.ts +16 -0
@@ -0,0 +1,448 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module DEXAggregator
4
+ * @description
5
+ * DEX Integration Layer for Token Swapping & Cross-Chain Aggregation.
6
+ *
7
+ * Provides a unified interface for token swaps across different chains, abstracting
8
+ * specific DEX implementations (Uniswap, Jupiter, etc.).
9
+ *
10
+ * Key Features:
11
+ * - **Swap**: executes simulated or real swaps on EVM and Solana.
12
+ * - **Cross-Chain Route Finding**: Finds paths like (Swap -> Bridge -> Swap).
13
+ * - **CCTP Support**: Natively supports Circle's Cross-Chain Transfer Protocol for USDC.
14
+ *
15
+ * NOTE: All chain IDs in this module are Wormhole Chain IDs by default.
16
+ */
17
+
18
+ export interface SwapQuote {
19
+ id: string;
20
+ protocol: string;
21
+ fromToken: string;
22
+ toToken: string;
23
+ fromAmount: string;
24
+ toAmount: string;
25
+ toAmountMin: string;
26
+ priceImpact: number;
27
+ estimatedGasUSD: number;
28
+ route: SwapHop[];
29
+ expiresAt: number;
30
+ }
31
+
32
+ export interface SwapHop {
33
+ protocol: string;
34
+ poolAddress: string;
35
+ fromToken: string;
36
+ toToken: string;
37
+ fee: number;
38
+ }
39
+
40
+ export interface CrossChainQuote {
41
+ id: string;
42
+ sourceChain: number;
43
+ targetChain: number;
44
+ fromToken: string;
45
+ toToken: string;
46
+ fromAmount: string;
47
+ estimatedToAmount: string;
48
+ routings: {
49
+ sourceSwap?: SwapQuote;
50
+ bridge: {
51
+ protocol: 'wormhole' | 'cctp';
52
+ token: string;
53
+ amount: string;
54
+ feeUSD: number;
55
+ estimatedTimeSeconds: number;
56
+ };
57
+ targetSwap?: SwapQuote;
58
+ };
59
+ totalFeeUSD: number;
60
+ estimatedTimeSeconds: number;
61
+ }
62
+
63
+ export interface SwapResult {
64
+ txHash: string;
65
+ fromToken: string;
66
+ toToken: string;
67
+ fromAmount: string;
68
+ toAmount: string;
69
+ status: 'pending' | 'confirmed' | 'failed';
70
+ gasUsed?: string;
71
+ }
72
+
73
+ export interface DEXConfig {
74
+ /** Maximum slippage in basis points (default: 50 = 0.5%) */
75
+ maxSlippageBps: number;
76
+ /** Deadline for swap in seconds (default: 300 = 5 minutes) */
77
+ deadlineSeconds: number;
78
+ /** Preferred protocols in order of preference */
79
+ preferredProtocols: string[];
80
+ /** Chains enabled for swapping (Wormhole IDs) */
81
+ enabledChains: number[];
82
+ }
83
+
84
+ export interface TokenInfo {
85
+ address: string;
86
+ symbol: string;
87
+ decimals: number;
88
+ chainId: number;
89
+ }
90
+
91
+ const DEFAULT_CONFIG: DEXConfig = {
92
+ maxSlippageBps: 50, // 0.5%
93
+ deadlineSeconds: 300, // 5 minutes
94
+ preferredProtocols: ['uniswap_v3', 'jupiter', 'curve', 'uniswap_v2'],
95
+ enabledChains: [1, 2, 5, 6, 23, 24, 30], // Sol, Eth, Poly, Avax, Arb, Op, Base
96
+ };
97
+
98
+ // Common token addresses by Wormhole Chain ID
99
+ export const COMMON_TOKENS: Record<number, Record<string, string>> = {
100
+ 2: { // Ethereum
101
+ USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
102
+ USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
103
+ WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
104
+ },
105
+ 30: { // Base
106
+ USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
107
+ WETH: '0x4200000000000000000000000000000000000006',
108
+ },
109
+ 1: { // Solana
110
+ USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Native USDC
111
+ SOL: 'So11111111111111111111111111111111111111112',
112
+ },
113
+ 23: { // Arbitrum
114
+ USDC: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
115
+ WETH: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
116
+ },
117
+ 24: { // Optimism
118
+ USDC: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', // Bridged (Standard)
119
+ USDC_NATIVE: '0x0b2C639c533813f4Aa9D7837CAf992c92bdE5162', // Native
120
+ WETH: '0x4200000000000000000000000000000000000006',
121
+ },
122
+ 5: { // Polygon
123
+ USDC: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // Bridged
124
+ USDC_NATIVE: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
125
+ WETH: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
126
+ },
127
+ };
128
+
129
+ // Map chain IDs to CCTP Domain presence (Wormhole IDs)
130
+ export const CCTP_SUPPORTED_CHAINS = [1, 2, 5, 23, 24, 30, 21, 6]; // Sol, Eth, Poly, Arb, Op, Base, Sui, Avax
131
+
132
+ export class DEXAggregator {
133
+ private config: DEXConfig;
134
+ private quoteCache: Map<string, { quote: SwapQuote; expiresAt: number }> = new Map();
135
+
136
+ constructor(config: Partial<DEXConfig> = {}) {
137
+ this.config = { ...DEFAULT_CONFIG, ...config };
138
+ }
139
+
140
+ /**
141
+ * Get best swap quote for a single chain.
142
+ */
143
+ async getBestQuote(
144
+ chainId: number,
145
+ fromToken: string,
146
+ toToken: string,
147
+ amount: string
148
+ ): Promise<SwapQuote | null> {
149
+ if (this.areAddressesEqual(chainId, fromToken, toToken)) return null; // No swap needed
150
+
151
+ const quotes = await this.getQuotes(chainId, fromToken, toToken, amount);
152
+ return quotes.length > 0 ? quotes[0] : null;
153
+ }
154
+
155
+ /**
156
+ * Get swap quotes from multiple protocols.
157
+ */
158
+ async getQuotes(
159
+ chainId: number,
160
+ fromToken: string,
161
+ toToken: string,
162
+ amount: string
163
+ ): Promise<SwapQuote[]> {
164
+ // Allow enabled chains
165
+ if (!this.config.enabledChains.includes(chainId)) {
166
+ // throw new Error(`Chain ${chainId} not enabled for swapping`);
167
+ return [];
168
+ }
169
+
170
+ // Use cache if valid
171
+ const cacheKey = `${chainId}:${fromToken}:${toToken}:${amount}`;
172
+ const cached = this.quoteCache.get(cacheKey);
173
+ if (cached && cached.expiresAt > Date.now()) {
174
+ return [cached.quote];
175
+ }
176
+
177
+ // In a real implementation, we would query 1inch, ParaSwap, Jupiter (Solana), etc.
178
+ // Here we simulate a quote request
179
+ const simulatedQuote = await this.simulateQuote(chainId, fromToken, toToken, amount);
180
+ if (simulatedQuote) {
181
+ this.quoteCache.set(cacheKey, {
182
+ quote: simulatedQuote,
183
+ expiresAt: Date.now() + 15000 // 15s cache
184
+ });
185
+ return [simulatedQuote];
186
+ }
187
+
188
+ return [];
189
+ }
190
+
191
+ /**
192
+ * Find optimized cross-chain route including swaps.
193
+ * Supports CCTP and standard bridging.
194
+ */
195
+ async findCrossChainRoute(
196
+ sourceChain: number,
197
+ sourceToken: string,
198
+ targetChain: number,
199
+ targetToken: string,
200
+ amount: string
201
+ ): Promise<CrossChainQuote | null> {
202
+ // 1. Identify Bridge Token
203
+ // Ideally we check common bridge tokens: USDC, ETH, SOL
204
+
205
+ // Priority: USDC (for CCTP) > Native > Others
206
+ const isUSDCSource = this.isUSDC(sourceChain, sourceToken);
207
+ const isUSDCTarget = this.isUSDC(targetChain, targetToken);
208
+
209
+ // Default to USDC-First approach if available on that chain
210
+ let bridgeTokenSymbol = 'USDC';
211
+ if (!isUSDCSource && !this.getTokenAddress(sourceChain, 'USDC')) {
212
+ // Fallback to WETH if USDC not present
213
+ bridgeTokenSymbol = 'WETH';
214
+ }
215
+
216
+ const sourceBridgeToken = this.getTokenAddress(sourceChain, bridgeTokenSymbol) || sourceToken;
217
+ const targetBridgeToken = this.getTokenAddress(targetChain, bridgeTokenSymbol) || targetToken;
218
+
219
+ // Step 1: Source Swap (if needed)
220
+ let sourceSwap: SwapQuote | undefined;
221
+ let bridgeAmount = amount;
222
+
223
+ if (!this.areAddressesEqual(sourceChain, sourceToken, sourceBridgeToken)) {
224
+ const quote = await this.getBestQuote(sourceChain, sourceToken, sourceBridgeToken, amount);
225
+ if (!quote) return null; // Cannot swap to bridge token
226
+ sourceSwap = quote;
227
+ bridgeAmount = quote.toAmount;
228
+ }
229
+
230
+ // Step 2: Bridge Logic
231
+ // If connecting to/from USDC and supported, use CCTP
232
+ const bridgeProtocol = (bridgeTokenSymbol === 'USDC' && this.supportsCCTP(sourceChain, targetChain))
233
+ ? 'cctp' : 'wormhole';
234
+
235
+ // Estimate bridge fees & time
236
+ const bridgeFee = this.estimateBridgeCost(bridgeProtocol, sourceChain, targetChain);
237
+ const bridgeTime = this.estimateBridgeTime(bridgeProtocol, sourceChain, targetChain);
238
+
239
+ // CCTP is burn/mint (no value loss other than gas, handled in feeUSD)
240
+ const destBridgeAmount = bridgeAmount;
241
+
242
+ // Step 3: Target Swap (if needed)
243
+ let targetSwap: SwapQuote | undefined;
244
+ let finalAmount = destBridgeAmount;
245
+
246
+ if (!this.areAddressesEqual(targetChain, targetBridgeToken, targetToken)) {
247
+ const quote = await this.getBestQuote(targetChain, targetBridgeToken, targetToken, destBridgeAmount);
248
+ if (!quote) return null; // Cannot swap from bridge token
249
+ targetSwap = quote;
250
+ finalAmount = quote.toAmount;
251
+ }
252
+
253
+ const totalFeeUSD = (sourceSwap?.estimatedGasUSD || 0) +
254
+ bridgeFee +
255
+ (targetSwap?.estimatedGasUSD || 0);
256
+
257
+ const totalTime = (sourceSwap ? 15 : 0) + bridgeTime + (targetSwap ? 15 : 0);
258
+
259
+ return {
260
+ id: `route_${Date.now()}`,
261
+ sourceChain,
262
+ targetChain,
263
+ fromToken: sourceToken,
264
+ toToken: targetToken,
265
+ fromAmount: amount,
266
+ estimatedToAmount: finalAmount,
267
+ routings: {
268
+ sourceSwap,
269
+ bridge: {
270
+ protocol: bridgeProtocol,
271
+ token: bridgeTokenSymbol,
272
+ amount: bridgeAmount,
273
+ feeUSD: bridgeFee,
274
+ estimatedTimeSeconds: bridgeTime
275
+ },
276
+ targetSwap
277
+ },
278
+ totalFeeUSD,
279
+ estimatedTimeSeconds: totalTime
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Check if CCTP is supported between chains.
285
+ */
286
+ supportsCCTP(sourceChain: number, targetChain: number): boolean {
287
+ return CCTP_SUPPORTED_CHAINS.includes(sourceChain) &&
288
+ CCTP_SUPPORTED_CHAINS.includes(targetChain);
289
+ }
290
+
291
+ /**
292
+ * Check if token is USDC.
293
+ */
294
+ isUSDC(chain: number, token: string): boolean {
295
+ const addr = this.getTokenAddress(chain, 'USDC') || this.getTokenAddress(chain, 'USDC_NATIVE');
296
+ return addr ? this.areAddressesEqual(chain, addr, token) : false;
297
+ }
298
+
299
+ /**
300
+ * Execute a swap (Simulation).
301
+ */
302
+ async executeSwap(
303
+ quote: SwapQuote,
304
+ signer: { signTransaction: (tx: unknown) => Promise<string> }
305
+ ): Promise<SwapResult> {
306
+ if (Date.now() > quote.expiresAt) {
307
+ throw new Error('Quote expired');
308
+ }
309
+
310
+ // Simulated result
311
+ const txHash = '0x' + Array.from({ length: 64 }, () =>
312
+ Math.floor(Math.random() * 16).toString(16)
313
+ ).join('');
314
+
315
+ return {
316
+ txHash,
317
+ fromToken: quote.fromToken,
318
+ toToken: quote.toToken,
319
+ fromAmount: quote.fromAmount,
320
+ toAmount: quote.toAmount,
321
+ status: 'confirmed',
322
+ };
323
+ }
324
+
325
+ /**
326
+ * Get supported tokens for a chain.
327
+ */
328
+ getSupportedTokens(chainId: number): string[] {
329
+ return Object.keys(COMMON_TOKENS[chainId] || {});
330
+ }
331
+
332
+ /**
333
+ * Check if a swap route exists.
334
+ */
335
+ async hasRoute(
336
+ chainId: number,
337
+ fromToken: string,
338
+ toToken: string
339
+ ): Promise<boolean> {
340
+ try {
341
+ const quote = await this.getBestQuote(chainId, fromToken, toToken, '1000000');
342
+ return quote !== null;
343
+ } catch {
344
+ return false;
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Get estimated output for a swap.
350
+ */
351
+ async getEstimatedOutput(
352
+ chainId: number,
353
+ fromToken: string,
354
+ toToken: string,
355
+ amount: string
356
+ ): Promise<{ output: string; priceImpact: number } | null> {
357
+ const quote = await this.getBestQuote(chainId, fromToken, toToken, amount);
358
+ if (!quote) return null;
359
+
360
+ return {
361
+ output: quote.toAmount,
362
+ priceImpact: quote.priceImpact,
363
+ };
364
+ }
365
+
366
+ /**
367
+ * Clear quote cache.
368
+ */
369
+ clearCache(): void {
370
+ this.quoteCache.clear();
371
+ }
372
+
373
+ // Helper to find common bridge token address
374
+ getTokenAddress(chain: number, symbol: string): string | undefined {
375
+ return COMMON_TOKENS[chain]?.[symbol];
376
+ }
377
+
378
+ // Private helper for address comparison handling case sensitivity
379
+ private areAddressesEqual(chain: number, a: string, b: string): boolean {
380
+ if (chain === 1 || chain === 21 || chain === 22) {
381
+ // Solana, Sui, Aptos are simple strings (Native addresses are typically Case Sensitive in Base58)
382
+ return a === b;
383
+ }
384
+ // EVM is case insensitive
385
+ return a.toLowerCase() === b.toLowerCase();
386
+ }
387
+
388
+ // Simulation helpers
389
+ private async simulateQuote(chain: number, from: string, to: string, amount: string): Promise<SwapQuote | null> {
390
+ const amountBigInt = BigInt(amount);
391
+ const slippage = this.config.maxSlippageBps / 10000;
392
+
393
+ // Simulate price impact
394
+ // Cap at 3%
395
+ const priceImpact = Math.min(Number(amountBigInt) / 1e12, 0.03);
396
+
397
+ const outputMultiplier = from === to ? 1 : 0.997; // 0.3% fee
398
+ const toAmount = BigInt(Math.floor(Number(amountBigInt) * outputMultiplier * (1 - priceImpact)));
399
+ const toAmountMin = BigInt(Math.floor(Number(toAmount) * (1 - slippage)));
400
+
401
+ const protocol = (chain === 1) ? 'jupiter' : 'uniswap_v3';
402
+
403
+ const estimatedGasUSD = (chain === 1) ? 0.001 : 0.5;
404
+
405
+ return {
406
+ id: `sim_quote_${Date.now()}`,
407
+ protocol,
408
+ fromToken: from,
409
+ toToken: to,
410
+ fromAmount: amount,
411
+ toAmount: toAmount.toString(),
412
+ toAmountMin: toAmountMin.toString(),
413
+ priceImpact,
414
+ estimatedGasUSD,
415
+ route: [{
416
+ protocol,
417
+ poolAddress: '0x' + '0'.repeat(40),
418
+ fromToken: from,
419
+ toToken: to,
420
+ fee: 3000
421
+ }],
422
+ expiresAt: Date.now() + 60000
423
+ };
424
+ }
425
+
426
+ private estimateBridgeCost(protocol: string, source: number, dest: number): number {
427
+ if (protocol === 'cctp') return 0.2; // CCTP is cheap
428
+ return 1.5; // Wormhole Standard
429
+ }
430
+
431
+ private estimateBridgeTime(protocol: string, source: number, dest: number): number {
432
+ if (protocol === 'cctp') return 600; // ~10-20 mins
433
+ return 120; // Wormhole Standard
434
+ }
435
+ }
436
+
437
+ // Singleton instance
438
+ let defaultAggregator: DEXAggregator | null = null;
439
+ export function getDEXAggregator(): DEXAggregator {
440
+ if (!defaultAggregator) {
441
+ defaultAggregator = new DEXAggregator();
442
+ }
443
+ return defaultAggregator;
444
+ }
445
+
446
+ export function createDEXAggregator(config?: Partial<DEXConfig>): DEXAggregator {
447
+ return new DEXAggregator(config);
448
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module FeeEstimator
4
+ * @description
5
+ * Cross-chain fee estimation service.
6
+ *
7
+ * Accurately calculating the cost of a cross-chain transaction is complex because it involves:
8
+ * - Source chain gas fees.
9
+ * - Wormhole/Relayer fees (in source token).
10
+ * - Target chain redemption fees.
11
+ *
12
+ * This module connects to the Veridex Relayer API to get real-time fee quotes.
13
+ */
14
+ import { createRelayerClient, RelayerClient } from '@veridex/sdk';
15
+
16
+ export class FeeEstimator {
17
+ private relayerClient?: RelayerClient;
18
+
19
+ constructor(relayerUrl?: string, relayerApiKey?: string) {
20
+ if (relayerUrl) {
21
+ this.relayerClient = createRelayerClient({
22
+ baseUrl: relayerUrl,
23
+ apiKey: relayerApiKey
24
+ });
25
+ }
26
+ }
27
+
28
+ async estimateFee(sourceChain: number, targetChain: number): Promise<number> {
29
+ if (sourceChain === targetChain) return 0.01;
30
+
31
+ if (this.relayerClient) {
32
+ try {
33
+ const quote = await this.relayerClient.getFeeQuote(sourceChain, targetChain);
34
+ // Convert bigint fee to USD (simplified)
35
+ return Number(quote.feeInSourceToken) / 1e18;
36
+ } catch (e) {
37
+ console.error('Failed to get real fee quote', e);
38
+ }
39
+ }
40
+
41
+ return 0.50; // Fallback $0.50 for cross-chain
42
+ }
43
+ }