pnpfucius 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 +396 -0
- package/bin/claude-predict.js +5 -0
- package/bin/pnpfucius.js +8 -0
- package/package.json +71 -0
- package/src/agent.js +1037 -0
- package/src/ai/index.js +6 -0
- package/src/ai/market-generator.js +186 -0
- package/src/ai/resolver.js +172 -0
- package/src/ai/scorer.js +184 -0
- package/src/analytics/aggregator.js +198 -0
- package/src/cli.js +948 -0
- package/src/collateral/privacy-tokens.js +183 -0
- package/src/config.js +128 -0
- package/src/daemon/index.js +321 -0
- package/src/daemon/lifecycle.js +168 -0
- package/src/daemon/scheduler.js +252 -0
- package/src/events/emitter.js +147 -0
- package/src/helius/client.js +221 -0
- package/src/helius/transaction-tracker.js +192 -0
- package/src/helius/webhooks.js +233 -0
- package/src/index.js +139 -0
- package/src/monitoring/news-monitor.js +262 -0
- package/src/monitoring/news-scorer.js +236 -0
- package/src/predict/agent.js +291 -0
- package/src/predict/prompts.js +69 -0
- package/src/predict/slash-commands.js +361 -0
- package/src/predict/tools/analytics-tools.js +83 -0
- package/src/predict/tools/bash-tool.js +87 -0
- package/src/predict/tools/file-tools.js +140 -0
- package/src/predict/tools/index.js +120 -0
- package/src/predict/tools/market-tools.js +851 -0
- package/src/predict/tools/news-tools.js +130 -0
- package/src/predict/ui/renderer.js +215 -0
- package/src/predict/ui/welcome.js +146 -0
- package/src/privacy-markets.js +194 -0
- package/src/storage/market-store.js +418 -0
- package/src/utils/spinner.js +172 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Helius API client for enhanced Solana interactions
|
|
2
|
+
// Provides DAS API, enhanced transactions, and webhook management
|
|
3
|
+
|
|
4
|
+
const HELIUS_API_BASE = 'https://api.helius.xyz/v0';
|
|
5
|
+
|
|
6
|
+
export class HeliusClient {
|
|
7
|
+
constructor(apiKey, network = 'devnet') {
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
throw new Error('Helius API key is required');
|
|
10
|
+
}
|
|
11
|
+
this.apiKey = apiKey;
|
|
12
|
+
this.network = network;
|
|
13
|
+
this.rpcUrl = `https://${network === 'mainnet' ? 'mainnet' : 'devnet'}.helius-rpc.com/?api-key=${apiKey}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// DAS API Methods
|
|
17
|
+
|
|
18
|
+
async getAssetsByOwner(ownerAddress, options = {}) {
|
|
19
|
+
const response = await this.dasRequest('getAssetsByOwner', {
|
|
20
|
+
ownerAddress,
|
|
21
|
+
page: options.page || 1,
|
|
22
|
+
limit: options.limit || 50,
|
|
23
|
+
sortBy: options.sortBy || { sortBy: 'created', sortDirection: 'desc' },
|
|
24
|
+
options: {
|
|
25
|
+
showFungible: options.showFungible || false,
|
|
26
|
+
showNativeBalance: options.showNativeBalance || false
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return response.result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async searchAssets(params) {
|
|
33
|
+
const response = await this.dasRequest('searchAssets', params);
|
|
34
|
+
return response.result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getSignaturesForAsset(assetId, options = {}) {
|
|
38
|
+
const response = await this.dasRequest('getSignaturesForAsset', {
|
|
39
|
+
id: assetId,
|
|
40
|
+
page: options.page || 1,
|
|
41
|
+
limit: options.limit || 100
|
|
42
|
+
});
|
|
43
|
+
return response.result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async getAsset(assetId) {
|
|
47
|
+
const response = await this.dasRequest('getAsset', { id: assetId });
|
|
48
|
+
return response.result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Enhanced Transactions API
|
|
52
|
+
|
|
53
|
+
async getEnhancedTransactions(signatures) {
|
|
54
|
+
if (!Array.isArray(signatures)) {
|
|
55
|
+
signatures = [signatures];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const response = await fetch(`${HELIUS_API_BASE}/transactions?api-key=${this.apiKey}`, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json' },
|
|
61
|
+
body: JSON.stringify({ transactions: signatures })
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const error = await response.text();
|
|
66
|
+
throw new Error(`Helius API error: ${error}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return response.json();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getEnhancedTransactionsByAddress(address, options = {}) {
|
|
73
|
+
const params = new URLSearchParams({
|
|
74
|
+
'api-key': this.apiKey
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (options.type) params.append('type', options.type);
|
|
78
|
+
if (options.before) params.append('before', options.before);
|
|
79
|
+
if (options.until) params.append('until', options.until);
|
|
80
|
+
|
|
81
|
+
const response = await fetch(
|
|
82
|
+
`${HELIUS_API_BASE}/addresses/${address}/transactions?${params}`,
|
|
83
|
+
{ method: 'GET' }
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const error = await response.text();
|
|
88
|
+
throw new Error(`Helius API error: ${error}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return response.json();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Webhook Management
|
|
95
|
+
|
|
96
|
+
async createWebhook(config) {
|
|
97
|
+
const webhookType = this.network === 'mainnet' ? 'enhanced' : 'enhancedDevnet';
|
|
98
|
+
|
|
99
|
+
const response = await fetch(`${HELIUS_API_BASE}/webhooks?api-key=${this.apiKey}`, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: { 'Content-Type': 'application/json' },
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
webhookURL: config.url,
|
|
104
|
+
transactionTypes: config.transactionTypes || ['ANY'],
|
|
105
|
+
accountAddresses: config.addresses || [],
|
|
106
|
+
webhookType: config.type || webhookType,
|
|
107
|
+
authHeader: config.authToken || undefined
|
|
108
|
+
})
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
const error = await response.text();
|
|
113
|
+
throw new Error(`Failed to create webhook: ${error}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return response.json();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async listWebhooks() {
|
|
120
|
+
const response = await fetch(`${HELIUS_API_BASE}/webhooks?api-key=${this.apiKey}`, {
|
|
121
|
+
method: 'GET'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
const error = await response.text();
|
|
126
|
+
throw new Error(`Failed to list webhooks: ${error}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return response.json();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async getWebhook(webhookId) {
|
|
133
|
+
const response = await fetch(`${HELIUS_API_BASE}/webhooks/${webhookId}?api-key=${this.apiKey}`, {
|
|
134
|
+
method: 'GET'
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
const error = await response.text();
|
|
139
|
+
throw new Error(`Failed to get webhook: ${error}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return response.json();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async updateWebhook(webhookId, config) {
|
|
146
|
+
const response = await fetch(`${HELIUS_API_BASE}/webhooks/${webhookId}?api-key=${this.apiKey}`, {
|
|
147
|
+
method: 'PUT',
|
|
148
|
+
headers: { 'Content-Type': 'application/json' },
|
|
149
|
+
body: JSON.stringify(config)
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
const error = await response.text();
|
|
154
|
+
throw new Error(`Failed to update webhook: ${error}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return response.json();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async deleteWebhook(webhookId) {
|
|
161
|
+
const response = await fetch(`${HELIUS_API_BASE}/webhooks/${webhookId}?api-key=${this.apiKey}`, {
|
|
162
|
+
method: 'DELETE'
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return response.ok;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Priority Fee API
|
|
169
|
+
|
|
170
|
+
async getPriorityFeeEstimate(params = {}) {
|
|
171
|
+
const response = await fetch(`${HELIUS_API_BASE}/priority-fee?api-key=${this.apiKey}`, {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: { 'Content-Type': 'application/json' },
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
accountKeys: params.accountKeys || [],
|
|
176
|
+
options: {
|
|
177
|
+
priorityLevel: params.priorityLevel || 'Medium'
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
const error = await response.text();
|
|
184
|
+
throw new Error(`Failed to get priority fee: ${error}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return response.json();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Internal helper for DAS API requests
|
|
191
|
+
|
|
192
|
+
async dasRequest(method, params) {
|
|
193
|
+
const response = await fetch(this.rpcUrl, {
|
|
194
|
+
method: 'POST',
|
|
195
|
+
headers: { 'Content-Type': 'application/json' },
|
|
196
|
+
body: JSON.stringify({
|
|
197
|
+
jsonrpc: '2.0',
|
|
198
|
+
id: '1',
|
|
199
|
+
method,
|
|
200
|
+
params
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
const error = await response.text();
|
|
206
|
+
throw new Error(`DAS API error: ${error}`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = await response.json();
|
|
210
|
+
|
|
211
|
+
if (result.error) {
|
|
212
|
+
throw new Error(`DAS API error: ${result.error.message}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function createHeliusClient(apiKey, network) {
|
|
220
|
+
return new HeliusClient(apiKey, network);
|
|
221
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Transaction confirmation tracking with enhanced Helius methods
|
|
2
|
+
// Provides reliable transaction confirmation with retries and status updates
|
|
3
|
+
|
|
4
|
+
import { Connection } from '@solana/web3.js';
|
|
5
|
+
|
|
6
|
+
export class TransactionTracker {
|
|
7
|
+
constructor(config = {}) {
|
|
8
|
+
this.rpcUrl = config.rpcUrl;
|
|
9
|
+
this.heliusClient = config.heliusClient;
|
|
10
|
+
this.connection = new Connection(this.rpcUrl, 'confirmed');
|
|
11
|
+
this.maxRetries = config.maxRetries || 30;
|
|
12
|
+
this.retryDelay = config.retryDelay || 2000;
|
|
13
|
+
this.onStatusChange = config.onStatusChange || null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async confirmTransaction(signature, options = {}) {
|
|
17
|
+
const maxRetries = options.maxRetries || this.maxRetries;
|
|
18
|
+
const retryDelay = options.retryDelay || this.retryDelay;
|
|
19
|
+
const commitment = options.commitment || 'confirmed';
|
|
20
|
+
|
|
21
|
+
this.emitStatus(signature, 'pending', 'Waiting for confirmation...');
|
|
22
|
+
|
|
23
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
24
|
+
try {
|
|
25
|
+
const status = await this.connection.getSignatureStatus(signature, {
|
|
26
|
+
searchTransactionHistory: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (status && status.value) {
|
|
30
|
+
const { confirmationStatus, err } = status.value;
|
|
31
|
+
|
|
32
|
+
if (err) {
|
|
33
|
+
this.emitStatus(signature, 'failed', `Transaction failed: ${JSON.stringify(err)}`);
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
signature,
|
|
37
|
+
error: err,
|
|
38
|
+
confirmationStatus
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (confirmationStatus === 'finalized') {
|
|
43
|
+
this.emitStatus(signature, 'finalized', 'Transaction finalized');
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
signature,
|
|
47
|
+
confirmationStatus: 'finalized',
|
|
48
|
+
slot: status.value.slot
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (confirmationStatus === 'confirmed' && commitment === 'confirmed') {
|
|
53
|
+
this.emitStatus(signature, 'confirmed', 'Transaction confirmed');
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
signature,
|
|
57
|
+
confirmationStatus: 'confirmed',
|
|
58
|
+
slot: status.value.slot
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.emitStatus(signature, 'processing', `Status: ${confirmationStatus} (attempt ${attempt}/${maxRetries})`);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
this.emitStatus(signature, 'retrying', `Retry ${attempt}/${maxRetries}: ${error.message}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (attempt < maxRetries) {
|
|
69
|
+
await this.sleep(retryDelay);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.emitStatus(signature, 'timeout', 'Confirmation timeout');
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
signature,
|
|
77
|
+
error: 'Confirmation timeout',
|
|
78
|
+
confirmationStatus: 'unknown'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async getTransactionDetails(signature) {
|
|
83
|
+
// Try enhanced Helius API first for rich transaction data
|
|
84
|
+
if (this.heliusClient) {
|
|
85
|
+
try {
|
|
86
|
+
const enhanced = await this.heliusClient.getEnhancedTransactions([signature]);
|
|
87
|
+
if (enhanced && enhanced.length > 0) {
|
|
88
|
+
return {
|
|
89
|
+
enhanced: true,
|
|
90
|
+
data: enhanced[0]
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// Fall back to standard RPC
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Standard RPC fallback
|
|
99
|
+
const tx = await this.connection.getTransaction(signature, {
|
|
100
|
+
maxSupportedTransactionVersion: 0
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
enhanced: false,
|
|
105
|
+
data: tx
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async waitForTransaction(signature, options = {}) {
|
|
110
|
+
const timeout = options.timeout || 60000;
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
|
|
113
|
+
while (Date.now() - startTime < timeout) {
|
|
114
|
+
const result = await this.confirmTransaction(signature, {
|
|
115
|
+
maxRetries: 1,
|
|
116
|
+
...options
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (result.success || result.error) {
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await this.sleep(1000);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
signature,
|
|
129
|
+
error: 'Transaction wait timeout'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async trackMultipleTransactions(signatures, options = {}) {
|
|
134
|
+
const results = new Map();
|
|
135
|
+
const pending = new Set(signatures);
|
|
136
|
+
const maxWait = options.maxWait || 120000;
|
|
137
|
+
const startTime = Date.now();
|
|
138
|
+
|
|
139
|
+
while (pending.size > 0 && Date.now() - startTime < maxWait) {
|
|
140
|
+
const statuses = await this.connection.getSignatureStatuses(
|
|
141
|
+
Array.from(pending),
|
|
142
|
+
{ searchTransactionHistory: true }
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < statuses.value.length; i++) {
|
|
146
|
+
const sig = Array.from(pending)[i];
|
|
147
|
+
const status = statuses.value[i];
|
|
148
|
+
|
|
149
|
+
if (status) {
|
|
150
|
+
if (status.err) {
|
|
151
|
+
results.set(sig, { success: false, error: status.err });
|
|
152
|
+
pending.delete(sig);
|
|
153
|
+
} else if (status.confirmationStatus === 'finalized' ||
|
|
154
|
+
status.confirmationStatus === 'confirmed') {
|
|
155
|
+
results.set(sig, { success: true, status: status.confirmationStatus });
|
|
156
|
+
pending.delete(sig);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (pending.size > 0) {
|
|
162
|
+
await this.sleep(2000);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Mark remaining as timeout
|
|
167
|
+
for (const sig of pending) {
|
|
168
|
+
results.set(sig, { success: false, error: 'timeout' });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return results;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
emitStatus(signature, status, message) {
|
|
175
|
+
if (this.onStatusChange) {
|
|
176
|
+
this.onStatusChange({
|
|
177
|
+
signature,
|
|
178
|
+
status,
|
|
179
|
+
message,
|
|
180
|
+
timestamp: Date.now()
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
sleep(ms) {
|
|
186
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function createTransactionTracker(config) {
|
|
191
|
+
return new TransactionTracker(config);
|
|
192
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// Helius webhook server for receiving real-time blockchain events
|
|
2
|
+
// Express server with endpoints for market event notifications
|
|
3
|
+
|
|
4
|
+
import express from 'express';
|
|
5
|
+
import { agentEvents, AgentEvents } from '../events/emitter.js';
|
|
6
|
+
|
|
7
|
+
export class WebhookServer {
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
this.port = config.port || 3000;
|
|
10
|
+
this.authToken = config.authToken || process.env.WEBHOOK_AUTH_TOKEN;
|
|
11
|
+
this.app = express();
|
|
12
|
+
this.server = null;
|
|
13
|
+
this.eventHandlers = new Map();
|
|
14
|
+
|
|
15
|
+
this.setupMiddleware();
|
|
16
|
+
this.setupRoutes();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setupMiddleware() {
|
|
20
|
+
this.app.use(express.json({ limit: '10mb' }));
|
|
21
|
+
|
|
22
|
+
// Auth middleware for webhook endpoints
|
|
23
|
+
this.app.use('/webhook', (req, res, next) => {
|
|
24
|
+
if (this.authToken) {
|
|
25
|
+
const auth = req.headers['authorization'];
|
|
26
|
+
if (auth !== this.authToken) {
|
|
27
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
next();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Request logging
|
|
34
|
+
this.app.use((req, res, next) => {
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
res.on('finish', () => {
|
|
37
|
+
const duration = Date.now() - start;
|
|
38
|
+
if (req.path.startsWith('/webhook')) {
|
|
39
|
+
agentEvents.emitTyped(AgentEvents.WEBHOOK_RECEIVED, {
|
|
40
|
+
path: req.path,
|
|
41
|
+
method: req.method,
|
|
42
|
+
statusCode: res.statusCode,
|
|
43
|
+
duration
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
next();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setupRoutes() {
|
|
52
|
+
// Helius webhook endpoint
|
|
53
|
+
this.app.post('/webhook/helius', async (req, res) => {
|
|
54
|
+
try {
|
|
55
|
+
const events = Array.isArray(req.body) ? req.body : [req.body];
|
|
56
|
+
const processed = [];
|
|
57
|
+
|
|
58
|
+
for (const event of events) {
|
|
59
|
+
try {
|
|
60
|
+
await this.processHeliusEvent(event);
|
|
61
|
+
processed.push({ success: true, signature: event.signature });
|
|
62
|
+
} catch (error) {
|
|
63
|
+
processed.push({ success: false, error: error.message });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
res.status(200).json({
|
|
68
|
+
success: true,
|
|
69
|
+
processed: processed.length,
|
|
70
|
+
results: processed
|
|
71
|
+
});
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Webhook processing error:', error);
|
|
74
|
+
res.status(500).json({ error: error.message });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Health check endpoint
|
|
79
|
+
this.app.get('/health', (req, res) => {
|
|
80
|
+
res.json({
|
|
81
|
+
status: 'ok',
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
uptime: process.uptime()
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Analytics endpoint for dashboard
|
|
88
|
+
this.app.get('/api/stats', async (req, res) => {
|
|
89
|
+
try {
|
|
90
|
+
const handler = this.eventHandlers.get('getStats');
|
|
91
|
+
if (handler) {
|
|
92
|
+
const stats = await handler();
|
|
93
|
+
res.json(stats);
|
|
94
|
+
} else {
|
|
95
|
+
res.json({ message: 'Stats handler not configured' });
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
res.status(500).json({ error: error.message });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Recent markets endpoint
|
|
103
|
+
this.app.get('/api/markets', async (req, res) => {
|
|
104
|
+
try {
|
|
105
|
+
const handler = this.eventHandlers.get('getMarkets');
|
|
106
|
+
if (handler) {
|
|
107
|
+
const limit = parseInt(req.query.limit) || 20;
|
|
108
|
+
const status = req.query.status || null;
|
|
109
|
+
const markets = await handler({ limit, status });
|
|
110
|
+
res.json(markets);
|
|
111
|
+
} else {
|
|
112
|
+
res.json([]);
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
res.status(500).json({ error: error.message });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// 404 handler
|
|
120
|
+
this.app.use((req, res) => {
|
|
121
|
+
res.status(404).json({ error: 'Not found' });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async processHeliusEvent(event) {
|
|
126
|
+
// Extract event type and process accordingly
|
|
127
|
+
const eventType = event.type || 'UNKNOWN';
|
|
128
|
+
const signature = event.signature;
|
|
129
|
+
|
|
130
|
+
// Emit for any listeners
|
|
131
|
+
agentEvents.emitTyped(AgentEvents.HELIUS_EVENT, {
|
|
132
|
+
type: eventType,
|
|
133
|
+
signature,
|
|
134
|
+
data: event
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Handle specific event types
|
|
138
|
+
switch (eventType) {
|
|
139
|
+
case 'CREATE_MARKET':
|
|
140
|
+
await this.handleMarketCreation(event);
|
|
141
|
+
break;
|
|
142
|
+
case 'SWAP':
|
|
143
|
+
await this.handleSwap(event);
|
|
144
|
+
break;
|
|
145
|
+
case 'TRANSFER':
|
|
146
|
+
await this.handleTransfer(event);
|
|
147
|
+
break;
|
|
148
|
+
default:
|
|
149
|
+
// Generic event handling
|
|
150
|
+
const handler = this.eventHandlers.get(eventType);
|
|
151
|
+
if (handler) {
|
|
152
|
+
await handler(event);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return { processed: true, type: eventType };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async handleMarketCreation(event) {
|
|
160
|
+
const handler = this.eventHandlers.get('marketCreated');
|
|
161
|
+
if (handler) {
|
|
162
|
+
await handler(event);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async handleSwap(event) {
|
|
167
|
+
const handler = this.eventHandlers.get('swap');
|
|
168
|
+
if (handler) {
|
|
169
|
+
await handler(event);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async handleTransfer(event) {
|
|
174
|
+
const handler = this.eventHandlers.get('transfer');
|
|
175
|
+
if (handler) {
|
|
176
|
+
await handler(event);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Register custom event handlers
|
|
181
|
+
on(eventType, handler) {
|
|
182
|
+
this.eventHandlers.set(eventType, handler);
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Remove event handler
|
|
187
|
+
off(eventType) {
|
|
188
|
+
this.eventHandlers.delete(eventType);
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async start() {
|
|
193
|
+
return new Promise((resolve, reject) => {
|
|
194
|
+
try {
|
|
195
|
+
this.server = this.app.listen(this.port, () => {
|
|
196
|
+
console.log(`Webhook server listening on port ${this.port}`);
|
|
197
|
+
agentEvents.emitTyped(AgentEvents.WEBHOOK_SERVER_STARTED, {
|
|
198
|
+
port: this.port
|
|
199
|
+
});
|
|
200
|
+
resolve(this.port);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
this.server.on('error', (error) => {
|
|
204
|
+
reject(error);
|
|
205
|
+
});
|
|
206
|
+
} catch (error) {
|
|
207
|
+
reject(error);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async stop() {
|
|
213
|
+
return new Promise((resolve) => {
|
|
214
|
+
if (this.server) {
|
|
215
|
+
this.server.close(() => {
|
|
216
|
+
console.log('Webhook server stopped');
|
|
217
|
+
agentEvents.emitTyped(AgentEvents.WEBHOOK_SERVER_STOPPED, {});
|
|
218
|
+
resolve();
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
resolve();
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
getExpressApp() {
|
|
227
|
+
return this.app;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function createWebhookServer(config) {
|
|
232
|
+
return new WebhookServer(config);
|
|
233
|
+
}
|