obol-mcp 2.0.0

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 (58) hide show
  1. package/README.md +195 -0
  2. package/dist/app.d.ts +3 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +130 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/config/env.d.ts +47 -0
  7. package/dist/config/env.d.ts.map +1 -0
  8. package/dist/config/env.js +63 -0
  9. package/dist/config/env.js.map +1 -0
  10. package/dist/config/pricing.d.ts +12 -0
  11. package/dist/config/pricing.d.ts.map +1 -0
  12. package/dist/config/pricing.js +99 -0
  13. package/dist/config/pricing.js.map +1 -0
  14. package/dist/mcp.d.ts +35 -0
  15. package/dist/mcp.d.ts.map +1 -0
  16. package/dist/mcp.js +150 -0
  17. package/dist/mcp.js.map +1 -0
  18. package/dist/middleware/validation.d.ts +6 -0
  19. package/dist/middleware/validation.d.ts.map +1 -0
  20. package/dist/middleware/validation.js +40 -0
  21. package/dist/middleware/validation.js.map +1 -0
  22. package/dist/middleware/x402.d.ts +33 -0
  23. package/dist/middleware/x402.d.ts.map +1 -0
  24. package/dist/middleware/x402.js +294 -0
  25. package/dist/middleware/x402.js.map +1 -0
  26. package/dist/plugins/defi/routes.d.ts +12 -0
  27. package/dist/plugins/defi/routes.d.ts.map +1 -0
  28. package/dist/plugins/defi/routes.js +430 -0
  29. package/dist/plugins/defi/routes.js.map +1 -0
  30. package/dist/plugins/token/routes.d.ts +10 -0
  31. package/dist/plugins/token/routes.d.ts.map +1 -0
  32. package/dist/plugins/token/routes.js +111 -0
  33. package/dist/plugins/token/routes.js.map +1 -0
  34. package/dist/plugins/wallet/routes.d.ts +13 -0
  35. package/dist/plugins/wallet/routes.d.ts.map +1 -0
  36. package/dist/plugins/wallet/routes.js +235 -0
  37. package/dist/plugins/wallet/routes.js.map +1 -0
  38. package/dist/server.d.ts +2 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +38 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/services/cache.d.ts +25 -0
  43. package/dist/services/cache.d.ts.map +1 -0
  44. package/dist/services/cache.js +82 -0
  45. package/dist/services/cache.js.map +1 -0
  46. package/dist/services/helius.d.ts +102 -0
  47. package/dist/services/helius.d.ts.map +1 -0
  48. package/dist/services/helius.js +456 -0
  49. package/dist/services/helius.js.map +1 -0
  50. package/dist/utils/logger.d.ts +3 -0
  51. package/dist/utils/logger.d.ts.map +1 -0
  52. package/dist/utils/logger.js +15 -0
  53. package/dist/utils/logger.js.map +1 -0
  54. package/dist/utils/retry.d.ts +9 -0
  55. package/dist/utils/retry.d.ts.map +1 -0
  56. package/dist/utils/retry.js +45 -0
  57. package/dist/utils/retry.js.map +1 -0
  58. package/package.json +81 -0
package/dist/mcp.js ADDED
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Obol MCP Server
4
+ *
5
+ * Exposes Obol's Solana data endpoints as MCP tools that any
6
+ * AI agent can discover and call. Runs over stdio transport.
7
+ *
8
+ * The MCP server proxies requests to either:
9
+ * - A live Obol instance (default: production)
10
+ * - A local dev instance
11
+ *
12
+ * In MCP mode, the server operates in "proxy" payment mode:
13
+ * - If OBOL_URL points to a mock-mode instance, data is free
14
+ * - If OBOL_URL points to an onchain instance, the MCP server
15
+ * can optionally include a payment signature via AGENT_PRIVATE_KEY
16
+ *
17
+ * Usage:
18
+ * npx tsx src/mcp.ts # stdio transport
19
+ * OBOL_URL=http://localhost:3000 npx tsx src/mcp.ts # local dev
20
+ *
21
+ * Claude Desktop config (~/.claude/claude_desktop_config.json):
22
+ * {
23
+ * "mcpServers": {
24
+ * "obol": {
25
+ * "command": "npx",
26
+ * "args": ["tsx", "/path/to/obol/src/mcp.ts"],
27
+ * "env": {
28
+ * "OBOL_URL": "https://obol-production.up.railway.app"
29
+ * }
30
+ * }
31
+ * }
32
+ * }
33
+ */
34
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
35
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
36
+ import { z } from 'zod';
37
+ const OBOL_URL = process.env.OBOL_URL ?? 'https://obol-production.up.railway.app';
38
+ // ── Helpers ──
39
+ async function obolFetch(path, options) {
40
+ const url = `${OBOL_URL}${path}`;
41
+ // For MCP, we call the API without payment headers.
42
+ // If the server is in mock mode, it returns data.
43
+ // If in onchain mode, it returns 402 with pricing info.
44
+ const res = await fetch(url, {
45
+ method: options?.method ?? 'GET',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: options?.body ? JSON.stringify(options.body) : undefined,
48
+ });
49
+ const data = await res.json();
50
+ return { status: res.status, data };
51
+ }
52
+ function formatResult(result) {
53
+ if (result.status === 402) {
54
+ return JSON.stringify({
55
+ error: 'Payment required',
56
+ message: 'This endpoint requires USDC payment via x402. The Obol instance is running in onchain mode.',
57
+ paymentInfo: result.data,
58
+ }, null, 2);
59
+ }
60
+ return JSON.stringify(result.data, null, 2);
61
+ }
62
+ // ── Server ──
63
+ const server = new McpServer({
64
+ name: 'obol',
65
+ version: '2.0.0',
66
+ });
67
+ // ── Wallet Tools ──
68
+ server.tool('obol_wallet_overview', 'Get a Solana wallet overview — SOL balance, token count, total value. Costs $0.01 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
69
+ const result = await obolFetch(`/api/v1/wallet/${address}/overview`);
70
+ return { content: [{ type: 'text', text: formatResult(result) }] };
71
+ });
72
+ server.tool('obol_wallet_portfolio', 'Get full wallet portfolio — all token holdings with prices, NFTs, and breakdown. Costs $0.05 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
73
+ const result = await obolFetch(`/api/v1/wallet/${address}/portfolio`);
74
+ return { content: [{ type: 'text', text: formatResult(result) }] };
75
+ });
76
+ server.tool('obol_wallet_activity', 'Get wallet transaction history with categorization (swaps, transfers, etc). Costs $0.05 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
77
+ const result = await obolFetch(`/api/v1/wallet/${address}/activity`);
78
+ return { content: [{ type: 'text', text: formatResult(result) }] };
79
+ });
80
+ server.tool('obol_wallet_risk', 'Multi-factor risk assessment for a Solana wallet — age, diversification, activity patterns. Costs $0.10 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
81
+ const result = await obolFetch(`/api/v1/wallet/${address}/risk`);
82
+ return { content: [{ type: 'text', text: formatResult(result) }] };
83
+ });
84
+ server.tool('obol_wallet_pnl', 'Wallet P&L analysis — token flows, current values, transaction history analysis. Costs $0.15 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
85
+ const result = await obolFetch(`/api/v1/wallet/${address}/pnl`);
86
+ return { content: [{ type: 'text', text: formatResult(result) }] };
87
+ });
88
+ // ── Token Tools ──
89
+ server.tool('obol_token_price', 'Get real-time token price via Jupiter. Costs $0.005 USDC.', { mint: z.string().describe('Token mint address (e.g., USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)') }, async ({ mint }) => {
90
+ const result = await obolFetch(`/api/v1/token/${mint}/price`);
91
+ return { content: [{ type: 'text', text: formatResult(result) }] };
92
+ });
93
+ server.tool('obol_token_metadata', 'Get token metadata — name, symbol, supply, decimals. Costs $0.01 USDC.', { mint: z.string().describe('Token mint address') }, async ({ mint }) => {
94
+ const result = await obolFetch(`/api/v1/token/${mint}/metadata`);
95
+ return { content: [{ type: 'text', text: formatResult(result) }] };
96
+ });
97
+ // ── DeFi Tools ──
98
+ server.tool('obol_swap_quote', 'Get a Jupiter swap quote with route planning and price impact. Costs $0.005 USDC.', {
99
+ inputMint: z.string().describe('Input token mint address (e.g., SOL: So11111111111111111111111111111111111111112)'),
100
+ outputMint: z.string().describe('Output token mint address'),
101
+ amount: z.string().describe('Amount in atomic units (e.g., 1000000000 for 1 SOL)'),
102
+ slippageBps: z.string().optional().describe('Slippage tolerance in basis points (default: 50 = 0.5%)'),
103
+ }, async ({ inputMint, outputMint, amount, slippageBps }) => {
104
+ const params = new URLSearchParams({ inputMint, outputMint, amount });
105
+ if (slippageBps)
106
+ params.set('slippageBps', slippageBps);
107
+ const result = await obolFetch(`/api/v1/defi/swap/quote?${params}`);
108
+ return { content: [{ type: 'text', text: formatResult(result) }] };
109
+ });
110
+ server.tool('obol_swap_execute', 'Build a Jupiter swap transaction for signing. Returns a serialized transaction the agent must sign and submit. Costs $0.25 USDC.', {
111
+ inputMint: z.string().describe('Input token mint address'),
112
+ outputMint: z.string().describe('Output token mint address'),
113
+ amount: z.string().describe('Amount in atomic units'),
114
+ userPublicKey: z.string().describe('The wallet public key that will sign and submit the transaction'),
115
+ slippageBps: z.string().optional().describe('Slippage in basis points (default: 50)'),
116
+ priorityFee: z.string().optional().describe('Priority fee in lamports (default: auto)'),
117
+ }, async ({ inputMint, outputMint, amount, userPublicKey, slippageBps, priorityFee }) => {
118
+ const result = await obolFetch('/api/v1/defi/swap/execute', {
119
+ method: 'POST',
120
+ body: { inputMint, outputMint, amount, userPublicKey, slippageBps, priorityFee },
121
+ });
122
+ return { content: [{ type: 'text', text: formatResult(result) }] };
123
+ });
124
+ server.tool('obol_defi_positions', 'Get DeFi positions for a wallet — LSTs, LP tokens, lending positions, categorized by protocol. Costs $0.10 USDC.', { address: z.string().describe('Solana wallet address') }, async ({ address }) => {
125
+ const result = await obolFetch(`/api/v1/defi/positions/${address}`);
126
+ return { content: [{ type: 'text', text: formatResult(result) }] };
127
+ });
128
+ server.tool('obol_lst_yields', 'Compare LST yields across Solana — jitoSOL, mSOL, bSOL, jupSOL, hSOL, and more. APYs from Sanctum, exchange rates from Jupiter. Costs $0.02 USDC.', {}, async () => {
129
+ const result = await obolFetch('/api/v1/defi/lst/yields');
130
+ return { content: [{ type: 'text', text: formatResult(result) }] };
131
+ });
132
+ // ── Free Tools ──
133
+ server.tool('obol_health', 'Check Obol API health and status. Free.', {}, async () => {
134
+ const result = await obolFetch('/health');
135
+ return { content: [{ type: 'text', text: formatResult(result) }] };
136
+ });
137
+ server.tool('obol_info', 'Get Obol API info — all available endpoints, pricing, and payment mode. Free.', {}, async () => {
138
+ const result = await obolFetch('/');
139
+ return { content: [{ type: 'text', text: formatResult(result) }] };
140
+ });
141
+ // ── Start ──
142
+ async function main() {
143
+ const transport = new StdioServerTransport();
144
+ await server.connect(transport);
145
+ }
146
+ main().catch(err => {
147
+ console.error('Obol MCP server error:', err);
148
+ process.exit(1);
149
+ });
150
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,wCAAwC,CAAC;AAElF,gBAAgB;AAEhB,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,OAA6C;IAClF,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC;IAEjC,oDAAoD;IACpD,kDAAkD;IAClD,wDAAwD;IACxD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,KAAK;QAChC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,YAAY,CAAC,MAAyC;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,KAAK,EAAE,kBAAkB;YACzB,OAAO,EAAE,6FAA6F;YACtG,WAAW,EAAE,MAAM,CAAC,IAAI;SACzB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,eAAe;AAEf,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,qBAAqB;AAErB,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,yFAAyF,EACzF,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,OAAO,WAAW,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,oGAAoG,EACpG,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,OAAO,YAAY,CAAC,CAAC;IACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,+FAA+F,EAC/F,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,OAAO,WAAW,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,+GAA+G,EAC/G,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,OAAO,OAAO,CAAC,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,oGAAoG,EACpG,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,OAAO,MAAM,CAAC,CAAC;IAChE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,oBAAoB;AAEpB,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,2DAA2D,EAC3D,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+EAA+E,CAAC,EAAE,EAC9G,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;IACjB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,iBAAiB,IAAI,QAAQ,CAAC,CAAC;IAC9D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,wEAAwE,EACxE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,EACnD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;IACjB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,iBAAiB,IAAI,WAAW,CAAC,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,mBAAmB;AAEnB,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,mFAAmF,EACnF;IACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mFAAmF,CAAC;IACnH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;IAClF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;CACvG,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE;IACvD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,IAAI,WAAW;QAAE,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;IACpE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,kIAAkI,EAClI;IACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IAC1D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IACrD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;IACrG,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IACrF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;CACxF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE;IACnF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,2BAA2B,EAAE;QAC1D,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE;KACjF,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,kHAAkH,EAClH,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACzD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;IACpE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,mJAAmJ,EACnJ,EAAE,EACF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,yBAAyB,CAAC,CAAC;IAC1D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,mBAAmB;AAEnB,MAAM,CAAC,IAAI,CACT,aAAa,EACb,yCAAyC,EACzC,EAAE,EACF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,WAAW,EACX,+EAA+E,EAC/E,EAAE,EACF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC,CACF,CAAC;AAEF,cAAc;AAEd,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyRequest, FastifyReply } from 'fastify';
2
+ /** Validate :address param is a valid Solana public key */
3
+ export declare function validateSolanaAddress(request: FastifyRequest, reply: FastifyReply): Promise<void>;
4
+ /** Validate :mint param is a valid Solana public key (token mint) */
5
+ export declare function validateMintAddress(request: FastifyRequest, reply: FastifyReply): Promise<void>;
6
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5D,2DAA2D;AAC3D,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,qEAAqE;AACrE,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
@@ -0,0 +1,40 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ /** Validate :address param is a valid Solana public key */
3
+ export async function validateSolanaAddress(request, reply) {
4
+ const { address } = request.params;
5
+ if (!address) {
6
+ return reply.code(400).send({
7
+ error: 'Bad Request',
8
+ message: 'Missing wallet address',
9
+ });
10
+ }
11
+ try {
12
+ new PublicKey(address);
13
+ }
14
+ catch {
15
+ return reply.code(400).send({
16
+ error: 'Bad Request',
17
+ message: `Invalid Solana address: ${address}`,
18
+ });
19
+ }
20
+ }
21
+ /** Validate :mint param is a valid Solana public key (token mint) */
22
+ export async function validateMintAddress(request, reply) {
23
+ const { mint } = request.params;
24
+ if (!mint) {
25
+ return reply.code(400).send({
26
+ error: 'Bad Request',
27
+ message: 'Missing token mint address',
28
+ });
29
+ }
30
+ try {
31
+ new PublicKey(mint);
32
+ }
33
+ catch {
34
+ return reply.code(400).send({
35
+ error: 'Bad Request',
36
+ message: `Invalid token mint: ${mint}`,
37
+ });
38
+ }
39
+ }
40
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAuB,EACvB,KAAmB;IAEnB,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAA8B,CAAC;IAE3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,wBAAwB;SAClC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACH,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,2BAA2B,OAAO,EAAE;SAC9C,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAuB,EACvB,KAAmB;IAEnB,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAA2B,CAAC;IAErD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,4BAA4B;SACtC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACH,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,uBAAuB,IAAI,EAAE;SACvC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * x402 Payment Middleware for Fastify
3
+ *
4
+ * Built on the @x402/core SDK for protocol-compliant header encoding/decoding.
5
+ * Uses @x402/svm utilities for Solana-specific address validation.
6
+ *
7
+ * Architecture note:
8
+ * The full @x402 SDK uses a Facilitator model (verify + settle via a remote
9
+ * or local facilitator service). For Obol, we implement direct
10
+ * on-chain verification because we want zero third-party dependencies in
11
+ * the payment path. The SDK's header format and protocol types are used
12
+ * to ensure protocol compliance.
13
+ *
14
+ * When the x402 ecosystem matures further, we can swap in the SDK's
15
+ * x402HTTPResourceServer for full protocol support with one line change.
16
+ */
17
+ import type { FastifyRequest, FastifyReply } from 'fastify';
18
+ export interface PaymentInfo {
19
+ wallet: string;
20
+ amount: number;
21
+ currency: string;
22
+ verifiedAt: string;
23
+ txSignature?: string;
24
+ network?: string;
25
+ mode: 'mock' | 'onchain';
26
+ }
27
+ declare module 'fastify' {
28
+ interface FastifyRequest {
29
+ payment?: PaymentInfo;
30
+ }
31
+ }
32
+ export declare function x402PaymentMiddleware(request: FastifyRequest, reply: FastifyReply): Promise<void>;
33
+ //# sourceMappingURL=x402.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/middleware/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAuB5D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,OAAO,CAAC,EAAE,WAAW,CAAC;KACvB;CACF;AAmCD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAqQf"}
@@ -0,0 +1,294 @@
1
+ /**
2
+ * x402 Payment Middleware for Fastify
3
+ *
4
+ * Built on the @x402/core SDK for protocol-compliant header encoding/decoding.
5
+ * Uses @x402/svm utilities for Solana-specific address validation.
6
+ *
7
+ * Architecture note:
8
+ * The full @x402 SDK uses a Facilitator model (verify + settle via a remote
9
+ * or local facilitator service). For Obol, we implement direct
10
+ * on-chain verification because we want zero third-party dependencies in
11
+ * the payment path. The SDK's header format and protocol types are used
12
+ * to ensure protocol compliance.
13
+ *
14
+ * When the x402 ecosystem matures further, we can swap in the SDK's
15
+ * x402HTTPResourceServer for full protocol support with one line change.
16
+ */
17
+ import { PublicKey } from '@solana/web3.js';
18
+ import { config } from '../config/env.js';
19
+ import { getEndpointPrice, requiresPayment } from '../config/pricing.js';
20
+ import { cache } from '../services/cache.js';
21
+ import { helius } from '../services/helius.js';
22
+ import { logger } from '../utils/logger.js';
23
+ // SDK utilities for protocol compliance
24
+ import { validateSvmAddress, USDC_MAINNET_ADDRESS, SOLANA_MAINNET_CAIP2 } from '@x402/svm';
25
+ // ──────────────────────────────────────────────
26
+ // Constants
27
+ // ──────────────────────────────────────────────
28
+ const X402_VERSION = 2; // SDK v2 protocol
29
+ const MAX_TX_AGE_SECONDS = 300;
30
+ // ──────────────────────────────────────────────
31
+ // Helpers
32
+ // ──────────────────────────────────────────────
33
+ function usdcToAtomicUnits(usdcAmount) {
34
+ return Math.floor(usdcAmount * 1_000_000).toString();
35
+ }
36
+ function generateMemo() {
37
+ return `obol_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
38
+ }
39
+ /** Build a protocol-compliant payment requirement */
40
+ function buildPaymentRequirement(resource, priceUSDC) {
41
+ return {
42
+ scheme: 'exact',
43
+ network: SOLANA_MAINNET_CAIP2,
44
+ maxAmountRequired: usdcToAtomicUnits(priceUSDC),
45
+ resource,
46
+ description: `Obol: ${resource}`,
47
+ mimeType: 'application/json',
48
+ outputSchema: {},
49
+ payTo: config.payment.recipientAddress,
50
+ maxTimeoutSeconds: MAX_TX_AGE_SECONDS,
51
+ asset: USDC_MAINNET_ADDRESS,
52
+ extra: { memo: generateMemo() },
53
+ };
54
+ }
55
+ // ──────────────────────────────────────────────
56
+ // Middleware
57
+ // ──────────────────────────────────────────────
58
+ export async function x402PaymentMiddleware(request, reply) {
59
+ const { url } = request;
60
+ if (!requiresPayment(url))
61
+ return;
62
+ let price;
63
+ try {
64
+ price = getEndpointPrice(url);
65
+ }
66
+ catch {
67
+ return reply.code(404).send({ error: 'Not Found', message: 'Endpoint not configured' });
68
+ }
69
+ // Check for payment header (SDK uses X-PAYMENT or PAYMENT-SIGNATURE)
70
+ const paymentHeader = (request.headers['x-payment'] ?? request.headers['payment-signature']);
71
+ if (!paymentHeader) {
72
+ const requirement = buildPaymentRequirement(url, price);
73
+ const paymentRequired = {
74
+ x402Version: X402_VERSION,
75
+ error: 'Payment Required',
76
+ accepts: [requirement],
77
+ };
78
+ logger.info({ url, price }, '402: Payment required');
79
+ // Set protocol-compliant header + JSON body
80
+ reply.header('X-PAYMENT-REQUIRED', Buffer.from(JSON.stringify(paymentRequired)).toString('base64'));
81
+ return reply.code(402).send(paymentRequired);
82
+ }
83
+ // Decode payment header (base64 JSON)
84
+ let payment;
85
+ try {
86
+ const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');
87
+ payment = JSON.parse(decoded);
88
+ }
89
+ catch {
90
+ return reply.code(400).send({
91
+ x402Version: X402_VERSION,
92
+ error: 'Invalid payment header — could not decode',
93
+ });
94
+ }
95
+ const payload = payment.payload;
96
+ if (!payload) {
97
+ return reply.code(400).send({
98
+ x402Version: X402_VERSION,
99
+ error: 'Invalid payment: missing payload',
100
+ });
101
+ }
102
+ // ── Mock mode ──
103
+ if (config.payment.mode === 'mock') {
104
+ logger.debug({ url }, 'Mock: auto-approving');
105
+ const walletId = payload.fromAddress ?? payload.transaction?.slice(0, 20) ?? 'mock-wallet';
106
+ request.payment = {
107
+ wallet: walletId,
108
+ amount: price,
109
+ currency: 'USDC',
110
+ verifiedAt: new Date().toISOString(),
111
+ mode: 'mock',
112
+ };
113
+ return;
114
+ }
115
+ // ── On-chain mode ──
116
+ // SDK v2 sends { payload: { transaction: "base64..." } }
117
+ // Legacy v1 sends { payload: { signature: "base58...", fromAddress: "..." } }
118
+ const txSignature = payload.signature ?? payload.transaction;
119
+ const fromAddress = payload.fromAddress;
120
+ if (!txSignature) {
121
+ return reply.code(400).send({
122
+ x402Version: X402_VERSION,
123
+ error: 'Missing transaction signature in payment payload',
124
+ });
125
+ }
126
+ // Validate sender address if provided
127
+ if (fromAddress && !validateSvmAddress(fromAddress)) {
128
+ return reply.code(400).send({
129
+ x402Version: X402_VERSION,
130
+ error: 'Invalid sender address',
131
+ });
132
+ }
133
+ // ── Replay prevention: check if this tx signature was already used ──
134
+ const txKey = `payment:tx:${txSignature}`;
135
+ if (await cache.exists(txKey)) {
136
+ logger.warn({ txSignature: String(txSignature).slice(0, 20) }, 'Replay rejected');
137
+ return reply.code(400).send({
138
+ x402Version: X402_VERSION,
139
+ error: 'Transaction already used for a previous payment',
140
+ });
141
+ }
142
+ // ── Fetch parsed transaction from Solana via Helius ──
143
+ let parsedTx;
144
+ try {
145
+ const conn = helius.getConnection();
146
+ parsedTx = await conn.getParsedTransaction(String(txSignature), {
147
+ maxSupportedTransactionVersion: 0,
148
+ commitment: 'confirmed',
149
+ });
150
+ }
151
+ catch (err) {
152
+ logger.error({ err, txSignature: String(txSignature).slice(0, 20) }, 'Failed to fetch transaction');
153
+ return reply.code(502).send({
154
+ x402Version: X402_VERSION,
155
+ error: 'Could not verify transaction — RPC error',
156
+ });
157
+ }
158
+ if (!parsedTx) {
159
+ return reply.code(400).send({
160
+ x402Version: X402_VERSION,
161
+ error: 'Transaction not found on-chain. It may not be confirmed yet — retry in a few seconds.',
162
+ });
163
+ }
164
+ // ── Verify transaction succeeded ──
165
+ if (parsedTx.meta?.err) {
166
+ return reply.code(400).send({
167
+ x402Version: X402_VERSION,
168
+ error: 'Transaction failed on-chain',
169
+ details: parsedTx.meta.err,
170
+ });
171
+ }
172
+ // ── Verify transaction age ──
173
+ const txTimestamp = parsedTx.blockTime;
174
+ if (txTimestamp) {
175
+ const ageSeconds = Math.floor(Date.now() / 1000) - txTimestamp;
176
+ if (ageSeconds > MAX_TX_AGE_SECONDS) {
177
+ return reply.code(400).send({
178
+ x402Version: X402_VERSION,
179
+ error: `Transaction too old (${ageSeconds}s). Must be under ${MAX_TX_AGE_SECONDS}s.`,
180
+ });
181
+ }
182
+ if (ageSeconds < -60) {
183
+ // Clock skew guard — reject transactions "from the future" beyond 60s tolerance
184
+ return reply.code(400).send({
185
+ x402Version: X402_VERSION,
186
+ error: 'Transaction timestamp is in the future',
187
+ });
188
+ }
189
+ }
190
+ // ── Find the USDC transfer to our merchant wallet ──
191
+ const requiredAtomicUnits = BigInt(usdcToAtomicUnits(price));
192
+ const recipientPubkey = config.payment.recipientAddress;
193
+ const usdcMint = USDC_MAINNET_ADDRESS;
194
+ let verifiedAmount = BigInt(0);
195
+ let verifiedSender = 'unknown';
196
+ const innerInstructions = parsedTx.meta?.innerInstructions ?? [];
197
+ const allInstructions = [
198
+ ...parsedTx.transaction.message.instructions,
199
+ ...innerInstructions.flatMap(ix => ix.instructions),
200
+ ];
201
+ for (const ix of allInstructions) {
202
+ // We need parsed instructions from the SPL Token program
203
+ if (!('parsed' in ix))
204
+ continue;
205
+ const parsed = ix;
206
+ if (parsed.program !== 'spl-token')
207
+ continue;
208
+ const { type, info } = parsed.parsed;
209
+ // Match transfer or transferChecked
210
+ if (type !== 'transfer' && type !== 'transferChecked')
211
+ continue;
212
+ const destination = info.destination ?? info.account;
213
+ const amount = info.amount ?? info.tokenAmount?.amount;
214
+ const mint = info.mint;
215
+ if (!destination || !amount)
216
+ continue;
217
+ // For transferChecked, mint is in the instruction — reject if wrong mint.
218
+ // For plain transfer, mint is absent — we verify via the token account below.
219
+ if (mint && mint !== usdcMint)
220
+ continue;
221
+ // For plain transfers without mint field, we MUST verify via token account.
222
+ // The token account lookup below enforces mint == USDC as a hard requirement.
223
+ // Resolve destination token account → check if owner is our merchant wallet
224
+ // The destination in SPL transfer is the token account, not the wallet.
225
+ // We check if the recipient token account belongs to our merchant.
226
+ try {
227
+ const destAccountInfo = await helius.getConnection().getParsedAccountInfo(new PublicKey(destination));
228
+ if (!destAccountInfo.value)
229
+ continue;
230
+ const accountData = destAccountInfo.value.data;
231
+ if (!('parsed' in accountData))
232
+ continue;
233
+ const tokenAccountInfo = accountData.parsed;
234
+ const owner = tokenAccountInfo.info?.owner;
235
+ const accountMint = tokenAccountInfo.info?.mint;
236
+ // Verify: token account is owned by our wallet AND it's USDC
237
+ // CRITICAL: both checks are mandatory — if either is missing, reject
238
+ if (owner !== recipientPubkey)
239
+ continue;
240
+ if (!accountMint || accountMint !== usdcMint)
241
+ continue;
242
+ verifiedAmount += BigInt(amount);
243
+ verifiedSender = info.authority ?? info.source ?? fromAddress ?? 'unknown';
244
+ }
245
+ catch {
246
+ // If we can't resolve the account, skip this instruction
247
+ continue;
248
+ }
249
+ }
250
+ if (verifiedAmount < requiredAtomicUnits) {
251
+ logger.warn({
252
+ txSignature: String(txSignature).slice(0, 20),
253
+ required: requiredAtomicUnits.toString(),
254
+ found: verifiedAmount.toString(),
255
+ }, 'Insufficient USDC payment');
256
+ return reply.code(402).send({
257
+ x402Version: X402_VERSION,
258
+ error: 'Insufficient payment',
259
+ required: requiredAtomicUnits.toString(),
260
+ received: verifiedAmount.toString(),
261
+ currency: 'USDC',
262
+ });
263
+ }
264
+ // ── Payment verified — record receipt and pass through ──
265
+ logger.info({
266
+ url,
267
+ txSignature: String(txSignature).slice(0, 20) + '...',
268
+ amount: price,
269
+ sender: verifiedSender,
270
+ }, 'Payment verified on-chain');
271
+ // Record by tx signature for replay prevention (24h TTL)
272
+ await cache.set(txKey, {
273
+ txSignature: String(txSignature),
274
+ fromAddress: verifiedSender,
275
+ amount: price,
276
+ endpoint: url,
277
+ timestamp: new Date().toISOString(),
278
+ }, 86400);
279
+ request.payment = {
280
+ wallet: verifiedSender,
281
+ amount: price,
282
+ currency: 'USDC',
283
+ verifiedAt: new Date().toISOString(),
284
+ txSignature: String(txSignature),
285
+ network: SOLANA_MAINNET_CAIP2,
286
+ mode: 'onchain',
287
+ };
288
+ reply.header('X-PAYMENT-RESPONSE', Buffer.from(JSON.stringify({
289
+ success: true,
290
+ txHash: txSignature,
291
+ networkId: SOLANA_MAINNET_CAIP2,
292
+ })).toString('base64'));
293
+ }
294
+ //# sourceMappingURL=x402.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x402.js","sourceRoot":"","sources":["../../src/middleware/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,wCAAwC;AACxC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE3F,iDAAiD;AACjD,YAAY;AACZ,iDAAiD;AAEjD,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,kBAAkB;AAC1C,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAsB/B,iDAAiD;AACjD,UAAU;AACV,iDAAiD;AAEjD,SAAS,iBAAiB,CAAC,UAAkB;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC;AACvD,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,qDAAqD;AACrD,SAAS,uBAAuB,CAAC,QAAgB,EAAE,SAAiB;IAClE,OAAO;QACL,MAAM,EAAE,OAAgB;QACxB,OAAO,EAAE,oBAAoB;QAC7B,iBAAiB,EAAE,iBAAiB,CAAC,SAAS,CAAC;QAC/C,QAAQ;QACR,WAAW,EAAE,SAAS,QAAQ,EAAE;QAChC,QAAQ,EAAE,kBAAkB;QAC5B,YAAY,EAAE,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB;QACtC,iBAAiB,EAAE,kBAAkB;QACrC,KAAK,EAAE,oBAAoB;QAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,aAAa;AACb,iDAAiD;AAEjD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAuB,EACvB,KAAmB;IAEnB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAExB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;QAAE,OAAO;IAElC,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,qEAAqE;IACrE,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAuB,CAAC;IAEnH,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,uBAAuB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACxD,MAAM,eAAe,GAAG;YACtB,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,kBAAkB;YACzB,OAAO,EAAE,CAAC,WAAW,CAAC;SACvB,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,uBAAuB,CAAC,CAAC;QAErD,4CAA4C;QAC5C,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpG,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC/C,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAgC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,2CAA2C;SACnD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAA8C,CAAC;IACvE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,kCAAkC;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB;IAClB,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAI,OAAO,CAAC,WAAsB,IAAK,OAAO,CAAC,WAAsB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,aAAa,CAAC;QACnH,OAAO,CAAC,OAAO,GAAG;YAChB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,IAAI,EAAE,MAAM;SACb,CAAC;QACF,OAAO;IACT,CAAC;IAED,sBAAsB;IACtB,yDAAyD;IACzD,8EAA8E;IAC9E,MAAM,WAAW,GAAI,OAAO,CAAC,SAAoB,IAAK,OAAO,CAAC,WAAsB,CAAC;IACrF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAiC,CAAC;IAE9D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,kDAAkD;SAC1D,CAAC,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,IAAI,WAAW,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,wBAAwB;SAChC,CAAC,CAAC;IACL,CAAC;IAED,uEAAuE;IACvE,MAAM,KAAK,GAAG,cAAc,WAAW,EAAE,CAAC;IAC1C,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;QAClF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,iDAAiD;SACzD,CAAC,CAAC;IACL,CAAC;IAED,wDAAwD;IACxD,IAAI,QAA0C,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QACpC,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE;YAC9D,8BAA8B,EAAE,CAAC;YACjC,UAAU,EAAE,WAAW;SACxB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,6BAA6B,CAAC,CAAC;QACpG,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,0CAA0C;SAClD,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,uFAAuF;SAC/F,CAAC,CAAC;IACL,CAAC;IAED,qCAAqC;IACrC,IAAI,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,6BAA6B;YACpC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,+BAA+B;IAC/B,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC;IACvC,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,WAAW,CAAC;QAC/D,IAAI,UAAU,GAAG,kBAAkB,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,WAAW,EAAE,YAAY;gBACzB,KAAK,EAAE,wBAAwB,UAAU,qBAAqB,kBAAkB,IAAI;aACrF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,UAAU,GAAG,CAAC,EAAE,EAAE,CAAC;YACrB,gFAAgF;YAChF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,WAAW,EAAE,YAAY;gBACzB,KAAK,EAAE,wCAAwC;aAChD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,MAAM,mBAAmB,GAAG,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACxD,MAAM,QAAQ,GAAG,oBAAoB,CAAC;IAEtC,IAAI,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,cAAc,GAAG,SAAS,CAAC;IAE/B,MAAM,iBAAiB,GAAG,QAAQ,CAAC,IAAI,EAAE,iBAAiB,IAAI,EAAE,CAAC;IACjE,MAAM,eAAe,GAAG;QACtB,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY;QAC5C,GAAG,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC;KACpD,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,yDAAyD;QACzD,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;YAAE,SAAS;QAChC,MAAM,MAAM,GAAG,EAAuB,CAAC;QACvC,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW;YAAE,SAAS;QAE7C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,MAG7B,CAAC;QAEF,oCAAoC;QACpC,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,iBAAiB;YAAE,SAAS;QAEhE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAEvB,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM;YAAE,SAAS;QAEtC,0EAA0E;QAC1E,8EAA8E;QAC9E,IAAI,IAAI,IAAI,IAAI,KAAK,QAAQ;YAAE,SAAS;QAExC,4EAA4E;QAC5E,8EAA8E;QAE9E,4EAA4E;QAC5E,wEAAwE;QACxE,mEAAmE;QACnE,IAAI,CAAC;YACH,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC,oBAAoB,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;YACtG,IAAI,CAAC,eAAe,CAAC,KAAK;gBAAE,SAAS;YAErC,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC;YAC/C,IAAI,CAAC,CAAC,QAAQ,IAAI,WAAW,CAAC;gBAAE,SAAS;YAEzC,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAsD,CAAC;YAC5F,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC;YAC3C,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC;YAEhD,6DAA6D;YAC7D,qEAAqE;YACrE,IAAI,KAAK,KAAK,eAAe;gBAAE,SAAS;YACxC,IAAI,CAAC,WAAW,IAAI,WAAW,KAAK,QAAQ;gBAAE,SAAS;YAEvD,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;YACjC,cAAc,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,IAAI,WAAW,IAAI,SAAS,CAAC;QAC7E,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;YACzD,SAAS;QACX,CAAC;IACH,CAAC;IAED,IAAI,cAAc,GAAG,mBAAmB,EAAE,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC;YACV,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YAC7C,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,EAAE;YACxC,KAAK,EAAE,cAAc,CAAC,QAAQ,EAAE;SACjC,EAAE,2BAA2B,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,sBAAsB;YAC7B,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,EAAE;YACxC,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE;YACnC,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,2DAA2D;IAC3D,MAAM,CAAC,IAAI,CAAC;QACV,GAAG;QACH,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;QACrD,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,cAAc;KACvB,EAAE,2BAA2B,CAAC,CAAC;IAEhC,yDAAyD;IACzD,MAAM,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE;QACrB,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC;QAChC,WAAW,EAAE,cAAc;QAC3B,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,GAAG;QACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,EAAE,KAAK,CAAC,CAAC;IAEV,OAAO,CAAC,OAAO,GAAG;QAChB,MAAM,EAAE,cAAc;QACtB,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC;QAChC,OAAO,EAAE,oBAAoB;QAC7B,IAAI,EAAE,SAAS;KAChB,CAAC;IAEF,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5D,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,oBAAoB;KAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ /**
3
+ * DeFi plugin — all /api/v1/defi/* routes
4
+ *
5
+ * Endpoints:
6
+ * GET /api/v1/defi/swap/quote ($0.005) — Jupiter swap quote
7
+ * POST /api/v1/defi/swap/execute ($0.25) — Jupiter swap transaction builder
8
+ * GET /api/v1/defi/positions/:addr ($0.10) — DeFi positions aggregation
9
+ * GET /api/v1/defi/lst/yields ($0.02) — LST yield comparison
10
+ */
11
+ export declare function defiPlugin(app: FastifyInstance): Promise<void>;
12
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/plugins/defi/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAgB/C;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA+epE"}