@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.
@@ -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
+