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.
- package/README.md +195 -0
- package/dist/app.d.ts +3 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +130 -0
- package/dist/app.js.map +1 -0
- package/dist/config/env.d.ts +47 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +63 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/pricing.d.ts +12 -0
- package/dist/config/pricing.d.ts.map +1 -0
- package/dist/config/pricing.js +99 -0
- package/dist/config/pricing.js.map +1 -0
- package/dist/mcp.d.ts +35 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +150 -0
- package/dist/mcp.js.map +1 -0
- package/dist/middleware/validation.d.ts +6 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +40 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/middleware/x402.d.ts +33 -0
- package/dist/middleware/x402.d.ts.map +1 -0
- package/dist/middleware/x402.js +294 -0
- package/dist/middleware/x402.js.map +1 -0
- package/dist/plugins/defi/routes.d.ts +12 -0
- package/dist/plugins/defi/routes.d.ts.map +1 -0
- package/dist/plugins/defi/routes.js +430 -0
- package/dist/plugins/defi/routes.js.map +1 -0
- package/dist/plugins/token/routes.d.ts +10 -0
- package/dist/plugins/token/routes.d.ts.map +1 -0
- package/dist/plugins/token/routes.js +111 -0
- package/dist/plugins/token/routes.js.map +1 -0
- package/dist/plugins/wallet/routes.d.ts +13 -0
- package/dist/plugins/wallet/routes.d.ts.map +1 -0
- package/dist/plugins/wallet/routes.js +235 -0
- package/dist/plugins/wallet/routes.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +38 -0
- package/dist/server.js.map +1 -0
- package/dist/services/cache.d.ts +25 -0
- package/dist/services/cache.d.ts.map +1 -0
- package/dist/services/cache.js +82 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/helius.d.ts +102 -0
- package/dist/services/helius.d.ts.map +1 -0
- package/dist/services/helius.js +456 -0
- package/dist/services/helius.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +15 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/retry.d.ts +9 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +45 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { validateSolanaAddress } from '../../middleware/validation.js';
|
|
2
|
+
import { helius } from '../../services/helius.js';
|
|
3
|
+
import { config } from '../../config/env.js';
|
|
4
|
+
import { cache } from '../../services/cache.js';
|
|
5
|
+
/**
|
|
6
|
+
* Wallet analytics plugin — all /api/v1/wallet/* routes
|
|
7
|
+
*
|
|
8
|
+
* Endpoints:
|
|
9
|
+
* GET /api/v1/wallet/:address/overview ($0.01)
|
|
10
|
+
* GET /api/v1/wallet/:address/portfolio ($0.05)
|
|
11
|
+
* GET /api/v1/wallet/:address/activity ($0.05)
|
|
12
|
+
* GET /api/v1/wallet/:address/risk ($0.10)
|
|
13
|
+
* GET /api/v1/wallet/:address/pnl ($0.15)
|
|
14
|
+
*/
|
|
15
|
+
export async function walletPlugin(app) {
|
|
16
|
+
const rateConfig = {
|
|
17
|
+
config: {
|
|
18
|
+
rateLimit: {
|
|
19
|
+
max: config.security.rateLimitMaxRequests,
|
|
20
|
+
timeWindow: config.security.rateLimitWindowMs,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
// ── Overview ──
|
|
25
|
+
app.get('/api/v1/wallet/:address/overview', { preHandler: validateSolanaAddress, ...rateConfig }, async (request, reply) => {
|
|
26
|
+
const { address } = request.params;
|
|
27
|
+
try {
|
|
28
|
+
const data = await helius.getWalletOverview(address);
|
|
29
|
+
return reply.send({
|
|
30
|
+
success: true,
|
|
31
|
+
wallet: address,
|
|
32
|
+
payment: request.payment,
|
|
33
|
+
data,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
app.log.error({ error, address }, 'Wallet overview failed');
|
|
38
|
+
return reply.code(500).send({
|
|
39
|
+
error: 'Internal Server Error',
|
|
40
|
+
message: 'Failed to fetch wallet overview',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// ── Portfolio ──
|
|
45
|
+
app.get('/api/v1/wallet/:address/portfolio', { preHandler: validateSolanaAddress, ...rateConfig }, async (request, reply) => {
|
|
46
|
+
const { address } = request.params;
|
|
47
|
+
try {
|
|
48
|
+
const data = await helius.getWalletPortfolio(address);
|
|
49
|
+
return reply.send({
|
|
50
|
+
success: true,
|
|
51
|
+
wallet: address,
|
|
52
|
+
payment: request.payment,
|
|
53
|
+
data,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
app.log.error({ error, address }, 'Wallet portfolio failed');
|
|
58
|
+
return reply.code(500).send({
|
|
59
|
+
error: 'Internal Server Error',
|
|
60
|
+
message: 'Failed to fetch portfolio',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// ── Activity ──
|
|
65
|
+
app.get('/api/v1/wallet/:address/activity', { preHandler: validateSolanaAddress, ...rateConfig }, async (request, reply) => {
|
|
66
|
+
const { address } = request.params;
|
|
67
|
+
try {
|
|
68
|
+
const data = await helius.getWalletActivity(address);
|
|
69
|
+
return reply.send({
|
|
70
|
+
success: true,
|
|
71
|
+
wallet: address,
|
|
72
|
+
payment: request.payment,
|
|
73
|
+
data,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
app.log.error({ error, address }, 'Wallet activity failed');
|
|
78
|
+
return reply.code(500).send({
|
|
79
|
+
error: 'Internal Server Error',
|
|
80
|
+
message: 'Failed to fetch activity',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
// ── Risk ──
|
|
85
|
+
app.get('/api/v1/wallet/:address/risk', { preHandler: validateSolanaAddress, ...rateConfig }, async (request, reply) => {
|
|
86
|
+
const { address } = request.params;
|
|
87
|
+
try {
|
|
88
|
+
const data = await helius.getWalletRisk(address);
|
|
89
|
+
return reply.send({
|
|
90
|
+
success: true,
|
|
91
|
+
wallet: address,
|
|
92
|
+
payment: request.payment,
|
|
93
|
+
data,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
app.log.error({ error, address }, 'Wallet risk failed');
|
|
98
|
+
return reply.code(500).send({
|
|
99
|
+
error: 'Internal Server Error',
|
|
100
|
+
message: 'Failed to fetch risk assessment',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// ── P&L ──
|
|
105
|
+
app.get('/api/v1/wallet/:address/pnl', { preHandler: validateSolanaAddress, ...rateConfig }, async (request, reply) => {
|
|
106
|
+
const { address } = request.params;
|
|
107
|
+
try {
|
|
108
|
+
const cacheKey = `wallet-pnl:${address}`;
|
|
109
|
+
const cached = await cache.get(cacheKey);
|
|
110
|
+
if (cached) {
|
|
111
|
+
return reply.send({ success: true, wallet: address, payment: request.payment, data: cached });
|
|
112
|
+
}
|
|
113
|
+
const heliusApiKey = config.solana.heliusApiKey;
|
|
114
|
+
if (!heliusApiKey) {
|
|
115
|
+
return reply.code(503).send({
|
|
116
|
+
error: 'Service Unavailable',
|
|
117
|
+
message: 'Helius API not configured',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Step 1: Get current portfolio state
|
|
121
|
+
const portfolio = await helius.getWalletPortfolio(address);
|
|
122
|
+
// Step 2: Get parsed transaction history to compute cost basis
|
|
123
|
+
// Use Helius Enhanced Transactions API for cleaner data
|
|
124
|
+
const rpcUrl = `https://api.helius.xyz/v0/addresses/${address}/transactions?api-key=${heliusApiKey}&limit=100`;
|
|
125
|
+
const txResponse = await fetch(rpcUrl);
|
|
126
|
+
if (!txResponse.ok) {
|
|
127
|
+
return reply.code(502).send({
|
|
128
|
+
error: 'Helius API Error',
|
|
129
|
+
message: 'Failed to fetch transaction history for P&L',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const transactions = await txResponse.json();
|
|
133
|
+
// Step 3: Walk transactions to compute per-token cost basis
|
|
134
|
+
const tokenFlows = {};
|
|
135
|
+
for (const tx of transactions) {
|
|
136
|
+
if (tx.transactionError)
|
|
137
|
+
continue;
|
|
138
|
+
for (const transfer of tx.tokenTransfers ?? []) {
|
|
139
|
+
const mint = transfer.mint;
|
|
140
|
+
if (!mint)
|
|
141
|
+
continue;
|
|
142
|
+
if (!tokenFlows[mint]) {
|
|
143
|
+
tokenFlows[mint] = { totalIn: 0, totalOut: 0, costBasisUSD: 0 };
|
|
144
|
+
}
|
|
145
|
+
const amount = transfer.tokenAmount ?? 0;
|
|
146
|
+
if (transfer.toUserAccount === address) {
|
|
147
|
+
// Inflow — tokens received
|
|
148
|
+
tokenFlows[mint].totalIn += amount;
|
|
149
|
+
}
|
|
150
|
+
else if (transfer.fromUserAccount === address) {
|
|
151
|
+
// Outflow — tokens sent
|
|
152
|
+
tokenFlows[mint].totalOut += amount;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Track SOL flows
|
|
156
|
+
for (const transfer of tx.nativeTransfers ?? []) {
|
|
157
|
+
const solMint = 'SOL';
|
|
158
|
+
if (!tokenFlows[solMint]) {
|
|
159
|
+
tokenFlows[solMint] = { totalIn: 0, totalOut: 0, costBasisUSD: 0 };
|
|
160
|
+
}
|
|
161
|
+
const amount = (transfer.amount ?? 0) / 1e9; // lamports to SOL
|
|
162
|
+
if (transfer.toUserAccount === address) {
|
|
163
|
+
tokenFlows[solMint].totalIn += amount;
|
|
164
|
+
}
|
|
165
|
+
else if (transfer.fromUserAccount === address) {
|
|
166
|
+
tokenFlows[solMint].totalOut += amount;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Step 4: Get current prices for all tokens in flows
|
|
171
|
+
const mintAddresses = Object.keys(tokenFlows).filter(m => m !== 'SOL');
|
|
172
|
+
let currentPrices = {};
|
|
173
|
+
if (mintAddresses.length > 0) {
|
|
174
|
+
const priceResponse = await fetch(`https://lite-api.jup.ag/price/v3?ids=${mintAddresses.join(',')}`);
|
|
175
|
+
const priceData = await priceResponse.json();
|
|
176
|
+
for (const [mint, data] of Object.entries(priceData)) {
|
|
177
|
+
if (data?.usdPrice)
|
|
178
|
+
currentPrices[mint] = data.usdPrice;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Add SOL price
|
|
182
|
+
const solPriceResponse = await fetch('https://lite-api.jup.ag/price/v3?ids=So11111111111111111111111111111111111111112');
|
|
183
|
+
const solPriceData = await solPriceResponse.json();
|
|
184
|
+
const solPrice = solPriceData['So11111111111111111111111111111111111111112']?.usdPrice ?? 0;
|
|
185
|
+
currentPrices['SOL'] = solPrice;
|
|
186
|
+
// Step 5: Compute P&L per token
|
|
187
|
+
const tokenPnL = [];
|
|
188
|
+
let totalUnrealizedUSD = 0;
|
|
189
|
+
let totalCurrentValueUSD = 0;
|
|
190
|
+
for (const [mint, flows] of Object.entries(tokenFlows)) {
|
|
191
|
+
const netTokens = flows.totalIn - flows.totalOut;
|
|
192
|
+
const currentPrice = currentPrices[mint] ?? 0;
|
|
193
|
+
const currentValue = netTokens * currentPrice;
|
|
194
|
+
// We can track flows but true cost basis requires swap price data
|
|
195
|
+
// which enhanced transactions don't always provide.
|
|
196
|
+
// Report holdings value and flow summary — agents can layer on cost basis.
|
|
197
|
+
if (Math.abs(netTokens) > 0.0001) {
|
|
198
|
+
tokenPnL.push({
|
|
199
|
+
mint,
|
|
200
|
+
netTokens: Number(netTokens.toFixed(6)),
|
|
201
|
+
totalIn: Number(flows.totalIn.toFixed(6)),
|
|
202
|
+
totalOut: Number(flows.totalOut.toFixed(6)),
|
|
203
|
+
currentPriceUSD: currentPrice,
|
|
204
|
+
currentValueUSD: Number(currentValue.toFixed(2)),
|
|
205
|
+
});
|
|
206
|
+
if (currentValue > 0) {
|
|
207
|
+
totalCurrentValueUSD += currentValue;
|
|
208
|
+
}
|
|
209
|
+
totalUnrealizedUSD += currentValue;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Sort by absolute value descending
|
|
213
|
+
tokenPnL.sort((a, b) => Math.abs(b.currentValueUSD) - Math.abs(a.currentValueUSD));
|
|
214
|
+
const pnl = {
|
|
215
|
+
address,
|
|
216
|
+
portfolioValueUSD: portfolio.totalValueUSD ?? 0,
|
|
217
|
+
tokenFlows: tokenPnL,
|
|
218
|
+
totalCurrentValueFromFlows: Number(totalCurrentValueUSD.toFixed(2)),
|
|
219
|
+
transactionsAnalyzed: transactions.length,
|
|
220
|
+
note: 'P&L is computed from the last 100 transactions. Cost basis requires full history and swap price data for precision.',
|
|
221
|
+
timestamp: new Date().toISOString(),
|
|
222
|
+
};
|
|
223
|
+
await cache.set(cacheKey, pnl, 180); // 3 min cache
|
|
224
|
+
return reply.send({ success: true, wallet: address, payment: request.payment, data: pnl });
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
app.log.error({ error, address }, 'Wallet P&L failed');
|
|
228
|
+
return reply.code(500).send({
|
|
229
|
+
error: 'Internal Server Error',
|
|
230
|
+
message: 'Failed to compute wallet P&L',
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/plugins/wallet/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createApp } from './app.js';
|
|
2
|
+
import { config } from './config/env.js';
|
|
3
|
+
import { cache } from './services/cache.js';
|
|
4
|
+
import { helius } from './services/helius.js';
|
|
5
|
+
import { logger } from './utils/logger.js';
|
|
6
|
+
async function start() {
|
|
7
|
+
// Initialize services
|
|
8
|
+
await cache.connect();
|
|
9
|
+
await helius.warmup();
|
|
10
|
+
// Create and start server
|
|
11
|
+
const app = await createApp();
|
|
12
|
+
try {
|
|
13
|
+
await app.listen({ port: config.server.port, host: config.server.host });
|
|
14
|
+
logger.info({
|
|
15
|
+
port: config.server.port,
|
|
16
|
+
mode: config.payment.mode,
|
|
17
|
+
network: config.solana.network,
|
|
18
|
+
}, 'obol running');
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
logger.fatal({ error }, 'Server failed to start');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// Graceful shutdown
|
|
25
|
+
const shutdown = async (signal) => {
|
|
26
|
+
logger.info({ signal }, 'Shutting down');
|
|
27
|
+
await app.close();
|
|
28
|
+
await cache.disconnect();
|
|
29
|
+
process.exit(0);
|
|
30
|
+
};
|
|
31
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
32
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
33
|
+
}
|
|
34
|
+
start().catch((error) => {
|
|
35
|
+
logger.fatal({ error }, 'Startup failed');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,KAAK,UAAU,KAAK;IAClB,sBAAsB;IACtB,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACtB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IAEtB,0BAA0B;IAC1B,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI;YACxB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;YACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;SAC/B,EAAE,cAAc,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,oBAAoB;IACpB,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC;QACzC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACtB,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Upstash Redis cache — handles response caching and payment receipt storage */
|
|
2
|
+
declare class CacheService {
|
|
3
|
+
private client;
|
|
4
|
+
private connected;
|
|
5
|
+
connect(): Promise<void>;
|
|
6
|
+
disconnect(): Promise<void>;
|
|
7
|
+
get<T>(key: string): Promise<T | null>;
|
|
8
|
+
set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
9
|
+
exists(key: string): Promise<boolean>;
|
|
10
|
+
/** Record a payment receipt (for analytics and replay prevention) */
|
|
11
|
+
recordPayment(memo: string, receipt: PaymentReceipt): Promise<void>;
|
|
12
|
+
/** Check if a payment memo has already been used (replay prevention) */
|
|
13
|
+
isPaymentUsed(memo: string): Promise<boolean>;
|
|
14
|
+
get isConnected(): boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface PaymentReceipt {
|
|
17
|
+
txSignature: string;
|
|
18
|
+
fromAddress: string;
|
|
19
|
+
amount: number;
|
|
20
|
+
endpoint: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const cache: CacheService;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAIA,iFAAiF;AACjF,cAAM,YAAY;IAChB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,SAAS,CAAS;IAEpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAUtC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAapE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS3C,qEAAqE;IAC/D,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzE,wEAAwE;IAClE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInD,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,KAAK,cAAqB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Redis } from '@upstash/redis';
|
|
2
|
+
import { config } from '../config/env.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
/** Upstash Redis cache — handles response caching and payment receipt storage */
|
|
5
|
+
class CacheService {
|
|
6
|
+
client = null;
|
|
7
|
+
connected = false;
|
|
8
|
+
async connect() {
|
|
9
|
+
if (!config.redis.restUrl || !config.redis.restToken) {
|
|
10
|
+
logger.warn('Redis not configured — running without cache');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
this.client = new Redis({
|
|
15
|
+
url: config.redis.restUrl,
|
|
16
|
+
token: config.redis.restToken,
|
|
17
|
+
});
|
|
18
|
+
const result = await this.client.ping();
|
|
19
|
+
if (result === 'PONG') {
|
|
20
|
+
this.connected = true;
|
|
21
|
+
logger.info('Redis connected');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logger.error({ error }, 'Redis connection failed');
|
|
26
|
+
this.client = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async disconnect() {
|
|
30
|
+
this.client = null;
|
|
31
|
+
this.connected = false;
|
|
32
|
+
}
|
|
33
|
+
async get(key) {
|
|
34
|
+
if (!this.client || !this.connected)
|
|
35
|
+
return null;
|
|
36
|
+
try {
|
|
37
|
+
return await this.client.get(key);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
logger.error({ error, key }, 'Cache get error');
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async set(key, value, ttlSeconds) {
|
|
45
|
+
if (!this.client || !this.connected)
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
if (ttlSeconds) {
|
|
49
|
+
await this.client.setex(key, ttlSeconds, value);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await this.client.set(key, value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
logger.error({ error, key }, 'Cache set error');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async exists(key) {
|
|
60
|
+
if (!this.client || !this.connected)
|
|
61
|
+
return false;
|
|
62
|
+
try {
|
|
63
|
+
return (await this.client.exists(key)) === 1;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Record a payment receipt (for analytics and replay prevention) */
|
|
70
|
+
async recordPayment(memo, receipt) {
|
|
71
|
+
await this.set(`payment:${memo}`, receipt, 86400); // 24h TTL
|
|
72
|
+
}
|
|
73
|
+
/** Check if a payment memo has already been used (replay prevention) */
|
|
74
|
+
async isPaymentUsed(memo) {
|
|
75
|
+
return this.exists(`payment:${memo}`);
|
|
76
|
+
}
|
|
77
|
+
get isConnected() {
|
|
78
|
+
return this.connected;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export const cache = new CacheService();
|
|
82
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
export interface TokenAccount {
|
|
3
|
+
mint: string;
|
|
4
|
+
address: string;
|
|
5
|
+
owner: string;
|
|
6
|
+
amount: string;
|
|
7
|
+
decimals: number;
|
|
8
|
+
uiAmount: number;
|
|
9
|
+
symbol?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
logoURI?: string;
|
|
12
|
+
priceUSD?: number;
|
|
13
|
+
valueUSD?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface NFT {
|
|
16
|
+
mint: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
symbol?: string;
|
|
19
|
+
collection?: string;
|
|
20
|
+
imageUrl?: string;
|
|
21
|
+
verified: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface WalletOverview {
|
|
24
|
+
address: string;
|
|
25
|
+
solBalance: number;
|
|
26
|
+
solBalanceUSD: number;
|
|
27
|
+
totalValueUSD: number;
|
|
28
|
+
tokenCount: number;
|
|
29
|
+
nftCount: number;
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
topTokens: TokenAccount[];
|
|
32
|
+
}
|
|
33
|
+
export interface WalletPortfolio {
|
|
34
|
+
address: string;
|
|
35
|
+
totalValueUSD: number;
|
|
36
|
+
solBalance: number;
|
|
37
|
+
solBalanceUSD: number;
|
|
38
|
+
tokens: TokenAccount[];
|
|
39
|
+
nfts: NFT[];
|
|
40
|
+
breakdown: {
|
|
41
|
+
sol: number;
|
|
42
|
+
tokens: number;
|
|
43
|
+
nfts: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface WalletTransaction {
|
|
47
|
+
signature: string;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
type: string;
|
|
50
|
+
status: 'success' | 'failed';
|
|
51
|
+
fee: number;
|
|
52
|
+
description: string;
|
|
53
|
+
}
|
|
54
|
+
export interface WalletActivity {
|
|
55
|
+
address: string;
|
|
56
|
+
transactionCount: number;
|
|
57
|
+
firstTransaction?: string;
|
|
58
|
+
lastTransaction?: string;
|
|
59
|
+
recentTransactions: WalletTransaction[];
|
|
60
|
+
}
|
|
61
|
+
export interface RiskFactor {
|
|
62
|
+
type: string;
|
|
63
|
+
severity: 'low' | 'medium' | 'high';
|
|
64
|
+
description: string;
|
|
65
|
+
impact: number;
|
|
66
|
+
}
|
|
67
|
+
export interface WalletRisk {
|
|
68
|
+
address: string;
|
|
69
|
+
riskScore: number;
|
|
70
|
+
riskLevel: 'low' | 'medium' | 'high';
|
|
71
|
+
factors: RiskFactor[];
|
|
72
|
+
warnings: string[];
|
|
73
|
+
}
|
|
74
|
+
declare class HeliusService {
|
|
75
|
+
private connection;
|
|
76
|
+
private apiKey;
|
|
77
|
+
private baseUrl;
|
|
78
|
+
constructor();
|
|
79
|
+
getConnection(): Connection;
|
|
80
|
+
private get rpcUrl();
|
|
81
|
+
/** DAS API call helper */
|
|
82
|
+
private dasCall;
|
|
83
|
+
getSOLBalance(address: string): Promise<number>;
|
|
84
|
+
getSOLPrice(): Promise<number>;
|
|
85
|
+
getTokenAccounts(address: string): Promise<TokenAccount[]>;
|
|
86
|
+
private enrichTokenMetadata;
|
|
87
|
+
getTokenPrices(mints: string[]): Promise<Map<string, number>>;
|
|
88
|
+
getNFTCount(address: string): Promise<number>;
|
|
89
|
+
getNFTs(address: string, limit?: number): Promise<NFT[]>;
|
|
90
|
+
isWalletActive(address: string): Promise<boolean>;
|
|
91
|
+
getWalletActivity(address: string, limit?: number): Promise<WalletActivity>;
|
|
92
|
+
getWalletOverview(address: string): Promise<WalletOverview>;
|
|
93
|
+
getWalletPortfolio(address: string): Promise<WalletPortfolio>;
|
|
94
|
+
getWalletRisk(address: string): Promise<WalletRisk>;
|
|
95
|
+
private getFirstTransaction;
|
|
96
|
+
/** Warmup connections and caches */
|
|
97
|
+
warmup(): Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
/** Singleton */
|
|
100
|
+
export declare const helius: HeliusService;
|
|
101
|
+
export {};
|
|
102
|
+
//# sourceMappingURL=helius.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helius.d.ts","sourceRoot":"","sources":["../../src/services/helius.ts"],"names":[],"mappings":"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"}
|