@pioneer-platform/pioneer-discovery-service 0.2.0 → 0.2.2
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/CHANGELOG.md +14 -0
- package/DAPP-INVESTIGATION.md +459 -0
- package/IMPLEMENTATION-PLAN.md +296 -0
- package/PRICE-DISCOVERY.md +319 -0
- package/README.md +10 -4
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +79 -5
- package/dist/agent/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/workers/dapp-investigator.worker.d.ts +110 -0
- package/dist/workers/dapp-investigator.worker.d.ts.map +1 -0
- package/dist/workers/dapp-investigator.worker.js +277 -0
- package/dist/workers/dapp-investigator.worker.js.map +1 -0
- package/dist/workers/price-discovery.worker.d.ts +57 -0
- package/dist/workers/price-discovery.worker.d.ts.map +1 -0
- package/dist/workers/price-discovery.worker.js +372 -0
- package/dist/workers/price-discovery.worker.js.map +1 -0
- package/package.json +1 -1
- package/src/agent/index.ts +95 -5
- package/src/types/index.ts +1 -1
- package/src/workers/dapp-investigator.worker.ts +379 -0
- package/src/workers/price-discovery.worker.ts +397 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DApp Investigator Worker
|
|
3
|
+
*
|
|
4
|
+
* Deep investigation of dApps including:
|
|
5
|
+
* 1. Contract verification and audits
|
|
6
|
+
* 2. Social media presence validation
|
|
7
|
+
* 3. Community sentiment analysis
|
|
8
|
+
* 4. TVL and usage metrics
|
|
9
|
+
* 5. Security incident history
|
|
10
|
+
* 6. Team transparency check
|
|
11
|
+
*
|
|
12
|
+
* This runs as part of the discovery service to provide comprehensive dApp analysis
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import axios from 'axios';
|
|
16
|
+
import type { DappDiscoveryRecord, DappAnalysis } from '../types';
|
|
17
|
+
|
|
18
|
+
const log = require('@pioneer-platform/loggerdog')();
|
|
19
|
+
const TAG = ' | dapp-investigator | ';
|
|
20
|
+
|
|
21
|
+
interface DAppInvestigationResult {
|
|
22
|
+
dappId: string;
|
|
23
|
+
dappName: string;
|
|
24
|
+
investigationComplete: boolean;
|
|
25
|
+
findings: {
|
|
26
|
+
contractVerification?: {
|
|
27
|
+
verified: boolean;
|
|
28
|
+
auditor?: string;
|
|
29
|
+
auditDate?: string;
|
|
30
|
+
auditUrl?: string;
|
|
31
|
+
};
|
|
32
|
+
socialPresence?: {
|
|
33
|
+
twitter?: {
|
|
34
|
+
handle?: string;
|
|
35
|
+
followers?: number;
|
|
36
|
+
verified?: boolean;
|
|
37
|
+
lastPost?: string;
|
|
38
|
+
};
|
|
39
|
+
discord?: {
|
|
40
|
+
serverSize?: number;
|
|
41
|
+
active?: boolean;
|
|
42
|
+
};
|
|
43
|
+
github?: {
|
|
44
|
+
repos?: number;
|
|
45
|
+
stars?: number;
|
|
46
|
+
lastCommit?: string;
|
|
47
|
+
contributors?: number;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
metrics?: {
|
|
51
|
+
tvl?: number;
|
|
52
|
+
dailyActiveUsers?: number;
|
|
53
|
+
transactionVolume?: number;
|
|
54
|
+
source?: string;
|
|
55
|
+
};
|
|
56
|
+
security?: {
|
|
57
|
+
incidents?: Array<{
|
|
58
|
+
date: string;
|
|
59
|
+
type: string;
|
|
60
|
+
severity: string;
|
|
61
|
+
description: string;
|
|
62
|
+
}>;
|
|
63
|
+
bugBounty?: boolean;
|
|
64
|
+
bugBountyUrl?: string;
|
|
65
|
+
};
|
|
66
|
+
team?: {
|
|
67
|
+
public?: boolean;
|
|
68
|
+
kyc?: boolean;
|
|
69
|
+
experience?: string;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
riskScore: number; // 0-100, higher = more risky
|
|
73
|
+
recommendWhitelist: boolean;
|
|
74
|
+
investigatedAt: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Free data sources for dApp investigation
|
|
78
|
+
const DAPP_DATA_SOURCES = {
|
|
79
|
+
defillama: 'https://api.llama.fi',
|
|
80
|
+
coingecko: 'https://api.coingecko.com/api/v3',
|
|
81
|
+
github: 'https://api.github.com',
|
|
82
|
+
etherscan: 'https://api.etherscan.io/api',
|
|
83
|
+
bscscan: 'https://api.bscscan.com/api',
|
|
84
|
+
polygonscan: 'https://api.polygonscan.com/api',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export class DAppInvestigatorWorker {
|
|
88
|
+
/**
|
|
89
|
+
* Main investigation run
|
|
90
|
+
*/
|
|
91
|
+
async run(dapps: DappDiscoveryRecord[]): Promise<DAppInvestigationResult[]> {
|
|
92
|
+
const tag = TAG + 'run | ';
|
|
93
|
+
log.info(tag, `🔍 Starting deep investigation of ${dapps.length} dApps...`);
|
|
94
|
+
|
|
95
|
+
const results: DAppInvestigationResult[] = [];
|
|
96
|
+
|
|
97
|
+
for (const dapp of dapps) {
|
|
98
|
+
try {
|
|
99
|
+
log.debug(tag, `Investigating: ${dapp.name}`);
|
|
100
|
+
const result = await this.investigateDApp(dapp);
|
|
101
|
+
results.push(result);
|
|
102
|
+
|
|
103
|
+
// Log findings
|
|
104
|
+
if (result.riskScore > 70) {
|
|
105
|
+
log.warn(tag, `⚠️ HIGH RISK: ${dapp.name} (score: ${result.riskScore})`);
|
|
106
|
+
} else if (result.recommendWhitelist) {
|
|
107
|
+
log.info(tag, `✅ WHITELIST RECOMMENDED: ${dapp.name}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Rate limiting delay
|
|
111
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
112
|
+
} catch (error) {
|
|
113
|
+
log.error(tag, `Failed to investigate ${dapp.name}:`, error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
log.info(tag, `✅ Investigation complete: ${results.length} dApps analyzed`);
|
|
118
|
+
return results;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Investigate a single dApp comprehensively
|
|
123
|
+
*/
|
|
124
|
+
private async investigateDApp(dapp: DappDiscoveryRecord): Promise<DAppInvestigationResult> {
|
|
125
|
+
const tag = TAG + 'investigateDApp | ';
|
|
126
|
+
|
|
127
|
+
const result: DAppInvestigationResult = {
|
|
128
|
+
dappId: dapp.id,
|
|
129
|
+
dappName: dapp.name,
|
|
130
|
+
investigationComplete: false,
|
|
131
|
+
findings: {},
|
|
132
|
+
riskScore: 50, // Start neutral
|
|
133
|
+
recommendWhitelist: false,
|
|
134
|
+
investigatedAt: Date.now(),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Phase 1: Check contract verification
|
|
139
|
+
result.findings.contractVerification = await this.checkContractVerification(dapp);
|
|
140
|
+
|
|
141
|
+
// Phase 2: Analyze social presence
|
|
142
|
+
result.findings.socialPresence = await this.analyzeSocialPresence(dapp);
|
|
143
|
+
|
|
144
|
+
// Phase 3: Fetch metrics (TVL, users, volume)
|
|
145
|
+
result.findings.metrics = await this.fetchDAppMetrics(dapp);
|
|
146
|
+
|
|
147
|
+
// Phase 4: Check security history
|
|
148
|
+
result.findings.security = await this.checkSecurityHistory(dapp);
|
|
149
|
+
|
|
150
|
+
// Phase 5: Team transparency check
|
|
151
|
+
result.findings.team = await this.checkTeamTransparency(dapp);
|
|
152
|
+
|
|
153
|
+
// Calculate final risk score
|
|
154
|
+
result.riskScore = this.calculateRiskScore(result.findings);
|
|
155
|
+
|
|
156
|
+
// Whitelist recommendation
|
|
157
|
+
result.recommendWhitelist = this.shouldWhitelist(result);
|
|
158
|
+
|
|
159
|
+
result.investigationComplete = true;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
log.error(tag, `Error during investigation of ${dapp.name}:`, error);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if contracts are verified on block explorers
|
|
169
|
+
*/
|
|
170
|
+
private async checkContractVerification(dapp: DappDiscoveryRecord): Promise<any> {
|
|
171
|
+
const tag = TAG + 'checkContractVerification | ';
|
|
172
|
+
|
|
173
|
+
// TODO: Extract contract addresses from dapp data
|
|
174
|
+
// TODO: Query Etherscan/BSCScan/Polygonscan APIs
|
|
175
|
+
|
|
176
|
+
log.debug(tag, `Checking contract verification for ${dapp.name}`);
|
|
177
|
+
|
|
178
|
+
// Placeholder implementation
|
|
179
|
+
return {
|
|
180
|
+
verified: false,
|
|
181
|
+
// auditor: 'CertiK',
|
|
182
|
+
// auditDate: '2024-01-01',
|
|
183
|
+
// auditUrl: 'https://certik.com/audit/...'
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Analyze social media presence
|
|
189
|
+
*/
|
|
190
|
+
private async analyzeSocialPresence(dapp: DappDiscoveryRecord): Promise<any> {
|
|
191
|
+
const tag = TAG + 'analyzeSocialPresence | ';
|
|
192
|
+
|
|
193
|
+
const presence: any = {};
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
// Check if URL contains social links
|
|
197
|
+
// TODO: Crawl dapp website for social links
|
|
198
|
+
// TODO: Verify Twitter/Discord/GitHub presence
|
|
199
|
+
|
|
200
|
+
// GitHub check (if we can find a repo)
|
|
201
|
+
if (dapp.url && dapp.url.includes('github.com')) {
|
|
202
|
+
try {
|
|
203
|
+
const repoPath = new URL(dapp.url).pathname;
|
|
204
|
+
const response = await axios.get(`${DAPP_DATA_SOURCES.github}/repos${repoPath}`, {
|
|
205
|
+
timeout: 5000,
|
|
206
|
+
headers: {
|
|
207
|
+
'User-Agent': 'Pioneer-Discovery-Service',
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
presence.github = {
|
|
212
|
+
repos: 1,
|
|
213
|
+
stars: response.data.stargazers_count,
|
|
214
|
+
lastCommit: response.data.pushed_at,
|
|
215
|
+
contributors: null, // Would need separate API call
|
|
216
|
+
};
|
|
217
|
+
} catch (error) {
|
|
218
|
+
log.debug(tag, `GitHub check failed for ${dapp.name}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
log.debug(tag, `Social presence analysis for ${dapp.name}:`, presence);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
log.debug(tag, `Error analyzing social presence for ${dapp.name}:`, error);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return presence;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Fetch dApp metrics from DeFiLlama and other sources
|
|
232
|
+
*/
|
|
233
|
+
private async fetchDAppMetrics(dapp: DappDiscoveryRecord): Promise<any> {
|
|
234
|
+
const tag = TAG + 'fetchDAppMetrics | ';
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
// Try DeFiLlama first
|
|
238
|
+
const response = await axios.get(`${DAPP_DATA_SOURCES.defillama}/protocols`, {
|
|
239
|
+
timeout: 5000,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Find matching protocol
|
|
243
|
+
const protocols = response.data;
|
|
244
|
+
const match = protocols.find((p: any) =>
|
|
245
|
+
p.name.toLowerCase() === dapp.name.toLowerCase() ||
|
|
246
|
+
p.url?.toLowerCase().includes(dapp.url.toLowerCase())
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
if (match) {
|
|
250
|
+
log.info(tag, `Found DeFiLlama data for ${dapp.name}`);
|
|
251
|
+
return {
|
|
252
|
+
tvl: match.tvl,
|
|
253
|
+
dailyActiveUsers: null, // Not available from DeFiLlama
|
|
254
|
+
transactionVolume: null,
|
|
255
|
+
source: 'DeFiLlama',
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
log.debug(tag, `No DeFiLlama data found for ${dapp.name}`);
|
|
260
|
+
} catch (error) {
|
|
261
|
+
log.debug(tag, `Error fetching metrics for ${dapp.name}:`, error);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return {};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Check security incident history
|
|
269
|
+
*/
|
|
270
|
+
private async checkSecurityHistory(dapp: DappDiscoveryRecord): Promise<any> {
|
|
271
|
+
const tag = TAG + 'checkSecurityHistory | ';
|
|
272
|
+
|
|
273
|
+
// TODO: Query security databases:
|
|
274
|
+
// - Rekt News API
|
|
275
|
+
// - Immunefi (bug bounties)
|
|
276
|
+
// - CertiK Security Oracle
|
|
277
|
+
// - SlowMist
|
|
278
|
+
|
|
279
|
+
log.debug(tag, `Checking security history for ${dapp.name}`);
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
incidents: [],
|
|
283
|
+
bugBounty: false,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Check team transparency
|
|
289
|
+
*/
|
|
290
|
+
private async checkTeamTransparency(dapp: DappDiscoveryRecord): Promise<any> {
|
|
291
|
+
const tag = TAG + 'checkTeamTransparency | ';
|
|
292
|
+
|
|
293
|
+
// TODO: Check:
|
|
294
|
+
// - Team page on website
|
|
295
|
+
// - LinkedIn profiles
|
|
296
|
+
// - Previous projects
|
|
297
|
+
// - KYC badges (CertiK, etc.)
|
|
298
|
+
|
|
299
|
+
log.debug(tag, `Checking team transparency for ${dapp.name}`);
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
public: false,
|
|
303
|
+
kyc: false,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Calculate overall risk score (0-100)
|
|
309
|
+
*/
|
|
310
|
+
private calculateRiskScore(findings: DAppInvestigationResult['findings']): number {
|
|
311
|
+
let score = 50; // Start neutral
|
|
312
|
+
|
|
313
|
+
// Contract verification: -20 points if verified
|
|
314
|
+
if (findings.contractVerification?.verified) {
|
|
315
|
+
score -= 20;
|
|
316
|
+
} else {
|
|
317
|
+
score += 10; // +10 if not verified
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Social presence: -10 points if strong
|
|
321
|
+
const social = findings.socialPresence;
|
|
322
|
+
if (social?.twitter?.verified || (social?.github?.stars && social.github.stars > 100)) {
|
|
323
|
+
score -= 10;
|
|
324
|
+
} else if (!social || Object.keys(social).length === 0) {
|
|
325
|
+
score += 15; // +15 if no social presence
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// TVL: -15 points if high TVL
|
|
329
|
+
if (findings.metrics?.tvl && findings.metrics.tvl > 1000000) {
|
|
330
|
+
score -= 15;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Security incidents: +25 per incident
|
|
334
|
+
const incidents = findings.security?.incidents?.length || 0;
|
|
335
|
+
score += incidents * 25;
|
|
336
|
+
|
|
337
|
+
// Bug bounty: -5 points
|
|
338
|
+
if (findings.security?.bugBounty) {
|
|
339
|
+
score -= 5;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Team transparency: -10 points if public
|
|
343
|
+
if (findings.team?.public) {
|
|
344
|
+
score -= 10;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// KYC: -10 points
|
|
348
|
+
if (findings.team?.kyc) {
|
|
349
|
+
score -= 10;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Clamp to 0-100
|
|
353
|
+
return Math.max(0, Math.min(100, score));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Determine if dApp should be whitelisted
|
|
358
|
+
*/
|
|
359
|
+
private shouldWhitelist(result: DAppInvestigationResult): boolean {
|
|
360
|
+
// Whitelist criteria:
|
|
361
|
+
// - Risk score < 30
|
|
362
|
+
// - Contract verified OR high TVL
|
|
363
|
+
// - Some social presence
|
|
364
|
+
// - No major security incidents
|
|
365
|
+
|
|
366
|
+
if (result.riskScore >= 30) return false;
|
|
367
|
+
|
|
368
|
+
const verified = result.findings.contractVerification?.verified || false;
|
|
369
|
+
const highTVL = (result.findings.metrics?.tvl || 0) > 1000000;
|
|
370
|
+
const hasSocial = !!(result.findings.socialPresence && Object.keys(result.findings.socialPresence).length > 0);
|
|
371
|
+
const noIncidents = (result.findings.security?.incidents?.length || 0) === 0;
|
|
372
|
+
|
|
373
|
+
return (verified || highTVL) && hasSocial && noIncidents;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Export singleton instance
|
|
378
|
+
export const dappInvestigatorWorker = new DAppInvestigatorWorker();
|
|
379
|
+
|