@sip-protocol/sdk 0.7.2 → 0.7.3
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/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2926 -341
- package/dist/browser.mjs +48 -2
- package/dist/chunk-2XIVXWHA.mjs +1930 -0
- package/dist/chunk-3M3HNQCW.mjs +18253 -0
- package/dist/chunk-7RFRWDCW.mjs +1504 -0
- package/dist/chunk-F6F73W35.mjs +16166 -0
- package/dist/chunk-OFDBEIEK.mjs +16166 -0
- package/dist/chunk-SF7YSLF5.mjs +1515 -0
- package/dist/chunk-WWUSGOXE.mjs +17129 -0
- package/dist/index-8MQz13eJ.d.mts +13746 -0
- package/dist/index-B71aXVzk.d.ts +13264 -0
- package/dist/index-DIBZHOOQ.d.ts +13746 -0
- package/dist/index-pOIIuwfV.d.mts +13264 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2911 -326
- package/dist/index.mjs +48 -2
- package/dist/solana-4O4K45VU.mjs +46 -0
- package/dist/solana-NDABAZ6P.mjs +56 -0
- package/dist/solana-ZYO63LY5.mjs +46 -0
- package/package.json +2 -2
- package/src/chains/solana/index.ts +24 -0
- package/src/chains/solana/providers/generic.ts +160 -0
- package/src/chains/solana/providers/helius.ts +249 -0
- package/src/chains/solana/providers/index.ts +54 -0
- package/src/chains/solana/providers/interface.ts +178 -0
- package/src/chains/solana/providers/webhook.ts +519 -0
- package/src/chains/solana/scan.ts +88 -8
- package/src/chains/solana/types.ts +20 -1
- package/src/compliance/index.ts +14 -0
- package/src/compliance/range-sas.ts +591 -0
- package/src/index.ts +99 -0
- package/src/privacy-backends/index.ts +86 -0
- package/src/privacy-backends/interface.ts +263 -0
- package/src/privacy-backends/privacycash-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +460 -0
- package/src/privacy-backends/registry.ts +278 -0
- package/src/privacy-backends/router.ts +346 -0
- package/src/privacy-backends/sip-native.ts +253 -0
- package/src/proofs/noir.ts +1 -1
- package/src/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy Scoring Module
|
|
3
|
+
*
|
|
4
|
+
* Calculates overall privacy score and generates recommendations
|
|
5
|
+
* based on individual analysis results.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
PrivacyScore,
|
|
12
|
+
PrivacyScoreBreakdown,
|
|
13
|
+
PrivacyRecommendation,
|
|
14
|
+
RiskLevel,
|
|
15
|
+
AddressReuseResult,
|
|
16
|
+
ClusterResult,
|
|
17
|
+
ExchangeExposureResult,
|
|
18
|
+
TemporalPatternResult,
|
|
19
|
+
SocialLinkResult,
|
|
20
|
+
SIPProtectionComparison,
|
|
21
|
+
} from './types'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maximum points per category
|
|
25
|
+
*/
|
|
26
|
+
const MAX_POINTS = {
|
|
27
|
+
addressReuse: 25,
|
|
28
|
+
clusterExposure: 25,
|
|
29
|
+
exchangeExposure: 20,
|
|
30
|
+
temporalPatterns: 15,
|
|
31
|
+
socialLinks: 15,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Total maximum score
|
|
36
|
+
*/
|
|
37
|
+
const TOTAL_MAX_SCORE = Object.values(MAX_POINTS).reduce((a, b) => a + b, 0)
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Risk level thresholds
|
|
41
|
+
*/
|
|
42
|
+
const RISK_THRESHOLDS = {
|
|
43
|
+
critical: 30,
|
|
44
|
+
high: 50,
|
|
45
|
+
medium: 70,
|
|
46
|
+
low: 100,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Calculate privacy score from analysis results
|
|
51
|
+
*
|
|
52
|
+
* @param addressReuse - Address reuse analysis result
|
|
53
|
+
* @param cluster - Cluster detection result
|
|
54
|
+
* @param exchangeExposure - Exchange exposure result
|
|
55
|
+
* @param temporalPatterns - Temporal pattern result
|
|
56
|
+
* @param socialLinks - Social link result
|
|
57
|
+
* @param walletAddress - Wallet being analyzed
|
|
58
|
+
* @returns Complete privacy score
|
|
59
|
+
*/
|
|
60
|
+
export function calculatePrivacyScore(
|
|
61
|
+
addressReuse: AddressReuseResult,
|
|
62
|
+
cluster: ClusterResult,
|
|
63
|
+
exchangeExposure: ExchangeExposureResult,
|
|
64
|
+
temporalPatterns: TemporalPatternResult,
|
|
65
|
+
socialLinks: SocialLinkResult,
|
|
66
|
+
walletAddress: string
|
|
67
|
+
): PrivacyScore {
|
|
68
|
+
// Calculate category scores (higher = better)
|
|
69
|
+
const breakdown: PrivacyScoreBreakdown = {
|
|
70
|
+
addressReuse: MAX_POINTS.addressReuse - addressReuse.scoreDeduction,
|
|
71
|
+
clusterExposure: MAX_POINTS.clusterExposure - cluster.scoreDeduction,
|
|
72
|
+
exchangeExposure: MAX_POINTS.exchangeExposure - exchangeExposure.scoreDeduction,
|
|
73
|
+
temporalPatterns: MAX_POINTS.temporalPatterns - temporalPatterns.scoreDeduction,
|
|
74
|
+
socialLinks: MAX_POINTS.socialLinks - socialLinks.scoreDeduction,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Calculate overall score
|
|
78
|
+
const totalScore =
|
|
79
|
+
breakdown.addressReuse +
|
|
80
|
+
breakdown.clusterExposure +
|
|
81
|
+
breakdown.exchangeExposure +
|
|
82
|
+
breakdown.temporalPatterns +
|
|
83
|
+
breakdown.socialLinks
|
|
84
|
+
|
|
85
|
+
// Normalize to 0-100
|
|
86
|
+
const overall = Math.round((totalScore / TOTAL_MAX_SCORE) * 100)
|
|
87
|
+
|
|
88
|
+
// Determine risk level
|
|
89
|
+
let risk: RiskLevel = 'low'
|
|
90
|
+
if (overall < RISK_THRESHOLDS.critical) {
|
|
91
|
+
risk = 'critical'
|
|
92
|
+
} else if (overall < RISK_THRESHOLDS.high) {
|
|
93
|
+
risk = 'high'
|
|
94
|
+
} else if (overall < RISK_THRESHOLDS.medium) {
|
|
95
|
+
risk = 'medium'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Generate recommendations
|
|
99
|
+
const recommendations = generateRecommendations(
|
|
100
|
+
addressReuse,
|
|
101
|
+
cluster,
|
|
102
|
+
exchangeExposure,
|
|
103
|
+
temporalPatterns,
|
|
104
|
+
socialLinks
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
overall,
|
|
109
|
+
breakdown,
|
|
110
|
+
risk,
|
|
111
|
+
recommendations,
|
|
112
|
+
analyzedAt: Date.now(),
|
|
113
|
+
walletAddress,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Generate actionable recommendations based on analysis results
|
|
119
|
+
*/
|
|
120
|
+
function generateRecommendations(
|
|
121
|
+
addressReuse: AddressReuseResult,
|
|
122
|
+
cluster: ClusterResult,
|
|
123
|
+
exchangeExposure: ExchangeExposureResult,
|
|
124
|
+
temporalPatterns: TemporalPatternResult,
|
|
125
|
+
socialLinks: SocialLinkResult
|
|
126
|
+
): PrivacyRecommendation[] {
|
|
127
|
+
const recommendations: PrivacyRecommendation[] = []
|
|
128
|
+
|
|
129
|
+
// Address reuse recommendations
|
|
130
|
+
if (addressReuse.scoreDeduction > 0) {
|
|
131
|
+
const severity = getSeverity(addressReuse.scoreDeduction, MAX_POINTS.addressReuse)
|
|
132
|
+
recommendations.push({
|
|
133
|
+
id: 'address-reuse-001',
|
|
134
|
+
severity,
|
|
135
|
+
category: 'addressReuse',
|
|
136
|
+
title: `Address reused ${addressReuse.totalReuseCount} times`,
|
|
137
|
+
description:
|
|
138
|
+
'Reusing the same address for multiple transactions creates linkability ' +
|
|
139
|
+
'between your transactions, allowing observers to track your activity.',
|
|
140
|
+
action:
|
|
141
|
+
'Use SIP stealth addresses for each transaction. Each payment uses a unique ' +
|
|
142
|
+
'one-time address that cannot be linked to your main address.',
|
|
143
|
+
potentialGain: addressReuse.scoreDeduction,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Cluster exposure recommendations
|
|
148
|
+
if (cluster.scoreDeduction > 0) {
|
|
149
|
+
const severity = getSeverity(cluster.scoreDeduction, MAX_POINTS.clusterExposure)
|
|
150
|
+
recommendations.push({
|
|
151
|
+
id: 'cluster-001',
|
|
152
|
+
severity,
|
|
153
|
+
category: 'clusterExposure',
|
|
154
|
+
title: `${cluster.linkedAddressCount} addresses linked to your wallet`,
|
|
155
|
+
description:
|
|
156
|
+
'Transaction analysis has linked multiple addresses to your wallet through ' +
|
|
157
|
+
'common input ownership patterns. This expands your privacy exposure.',
|
|
158
|
+
action:
|
|
159
|
+
'Use SIP for all transactions to prevent cluster analysis. Stealth addresses ' +
|
|
160
|
+
'break the link between your spending and receiving addresses.',
|
|
161
|
+
potentialGain: cluster.scoreDeduction,
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Exchange exposure recommendations
|
|
166
|
+
if (exchangeExposure.scoreDeduction > 0) {
|
|
167
|
+
const cexes = exchangeExposure.exchanges.filter((e) => e.kycRequired)
|
|
168
|
+
const severity = getSeverity(exchangeExposure.scoreDeduction, MAX_POINTS.exchangeExposure)
|
|
169
|
+
|
|
170
|
+
if (cexes.length > 0) {
|
|
171
|
+
recommendations.push({
|
|
172
|
+
id: 'exchange-cex-001',
|
|
173
|
+
severity,
|
|
174
|
+
category: 'exchangeExposure',
|
|
175
|
+
title: `Interacted with ${cexes.length} KYC exchange(s)`,
|
|
176
|
+
description:
|
|
177
|
+
`Deposits to ${cexes.map((e) => e.name).join(', ')} link your on-chain ` +
|
|
178
|
+
'activity to your verified identity. This is one of the biggest privacy risks.',
|
|
179
|
+
action:
|
|
180
|
+
'Use SIP viewing keys for selective disclosure. You can prove compliance ' +
|
|
181
|
+
'to exchanges without exposing your full transaction history.',
|
|
182
|
+
potentialGain: Math.min(cexes.length * 8, MAX_POINTS.exchangeExposure),
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const dexes = exchangeExposure.exchanges.filter((e) => !e.kycRequired)
|
|
187
|
+
if (dexes.length > 0) {
|
|
188
|
+
recommendations.push({
|
|
189
|
+
id: 'exchange-dex-001',
|
|
190
|
+
severity: 'low',
|
|
191
|
+
category: 'exchangeExposure',
|
|
192
|
+
title: `Used ${dexes.length} DEX(es) without privacy`,
|
|
193
|
+
description:
|
|
194
|
+
'DEX swaps are public and can be traced. While no KYC is required, ' +
|
|
195
|
+
'your swap patterns can reveal trading strategies.',
|
|
196
|
+
action:
|
|
197
|
+
'Use SIP for private swaps. Amounts and swap details are hidden while ' +
|
|
198
|
+
'still using your preferred DEX.',
|
|
199
|
+
potentialGain: Math.min(dexes.length * 2, 6),
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Temporal pattern recommendations
|
|
205
|
+
if (temporalPatterns.scoreDeduction > 0) {
|
|
206
|
+
const severity = getSeverity(temporalPatterns.scoreDeduction, MAX_POINTS.temporalPatterns)
|
|
207
|
+
|
|
208
|
+
for (const pattern of temporalPatterns.patterns) {
|
|
209
|
+
if (pattern.type === 'regular-schedule') {
|
|
210
|
+
recommendations.push({
|
|
211
|
+
id: 'temporal-schedule-001',
|
|
212
|
+
severity,
|
|
213
|
+
category: 'temporalPatterns',
|
|
214
|
+
title: 'Regular transaction schedule detected',
|
|
215
|
+
description:
|
|
216
|
+
`${pattern.description}. Predictable patterns make your activity ` +
|
|
217
|
+
'easier to track and attribute.',
|
|
218
|
+
action:
|
|
219
|
+
'Vary your transaction timing. Consider using scheduled private ' +
|
|
220
|
+
'transactions through SIP to obscure timing patterns.',
|
|
221
|
+
potentialGain: 5,
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (pattern.type === 'timezone-inference') {
|
|
226
|
+
recommendations.push({
|
|
227
|
+
id: 'temporal-timezone-001',
|
|
228
|
+
severity: 'medium',
|
|
229
|
+
category: 'temporalPatterns',
|
|
230
|
+
title: 'Timezone can be inferred from activity',
|
|
231
|
+
description:
|
|
232
|
+
`${pattern.description}. This narrows down your geographic location ` +
|
|
233
|
+
'based on when you transact.',
|
|
234
|
+
action:
|
|
235
|
+
'Use time-delayed transactions or vary your active hours. ' +
|
|
236
|
+
'SIP can queue transactions for random future execution.',
|
|
237
|
+
potentialGain: 5,
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Social link recommendations
|
|
244
|
+
if (socialLinks.scoreDeduction > 0) {
|
|
245
|
+
const severity = getSeverity(socialLinks.scoreDeduction, MAX_POINTS.socialLinks)
|
|
246
|
+
|
|
247
|
+
if (socialLinks.isDoxxed) {
|
|
248
|
+
recommendations.push({
|
|
249
|
+
id: 'social-doxxed-001',
|
|
250
|
+
severity: 'critical',
|
|
251
|
+
category: 'socialLinks',
|
|
252
|
+
title: 'Wallet publicly linked to your identity',
|
|
253
|
+
description:
|
|
254
|
+
'Your wallet address is publicly associated with your real identity ' +
|
|
255
|
+
'through ENS/SNS names or social profiles. All transactions are attributable to you.',
|
|
256
|
+
action:
|
|
257
|
+
'Use a fresh wallet with SIP for private transactions. Your viewing keys ' +
|
|
258
|
+
'let you prove ownership when needed without constant exposure.',
|
|
259
|
+
potentialGain: 15,
|
|
260
|
+
})
|
|
261
|
+
} else if (socialLinks.partialExposure) {
|
|
262
|
+
recommendations.push({
|
|
263
|
+
id: 'social-partial-001',
|
|
264
|
+
severity,
|
|
265
|
+
category: 'socialLinks',
|
|
266
|
+
title: 'Partial identity exposure detected',
|
|
267
|
+
description:
|
|
268
|
+
'Some identifying information is linked to your wallet, such as ' +
|
|
269
|
+
'ENS names or labeled addresses on block explorers.',
|
|
270
|
+
action:
|
|
271
|
+
'Consider using a separate wallet for private activities. ' +
|
|
272
|
+
'SIP stealth addresses prevent linking to your main identity.',
|
|
273
|
+
potentialGain: socialLinks.scoreDeduction,
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Sort by potential gain (most impactful first)
|
|
279
|
+
recommendations.sort((a, b) => b.potentialGain - a.potentialGain)
|
|
280
|
+
|
|
281
|
+
return recommendations
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Determine severity based on score deduction percentage
|
|
286
|
+
*/
|
|
287
|
+
function getSeverity(deduction: number, maxPoints: number): RiskLevel {
|
|
288
|
+
const percentage = deduction / maxPoints
|
|
289
|
+
|
|
290
|
+
if (percentage >= 0.8) return 'critical'
|
|
291
|
+
if (percentage >= 0.5) return 'high'
|
|
292
|
+
if (percentage >= 0.25) return 'medium'
|
|
293
|
+
return 'low'
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Calculate SIP protection comparison
|
|
298
|
+
*
|
|
299
|
+
* Projects how the privacy score would improve with SIP protection.
|
|
300
|
+
*/
|
|
301
|
+
export function calculateSIPComparison(
|
|
302
|
+
currentScore: PrivacyScore
|
|
303
|
+
): SIPProtectionComparison {
|
|
304
|
+
const improvements: SIPProtectionComparison['improvements'] = []
|
|
305
|
+
|
|
306
|
+
// With SIP stealth addresses, address reuse is impossible
|
|
307
|
+
const addressReuseImprovement = MAX_POINTS.addressReuse - currentScore.breakdown.addressReuse
|
|
308
|
+
if (addressReuseImprovement > 0) {
|
|
309
|
+
improvements.push({
|
|
310
|
+
category: 'addressReuse',
|
|
311
|
+
currentScore: currentScore.breakdown.addressReuse,
|
|
312
|
+
projectedScore: MAX_POINTS.addressReuse,
|
|
313
|
+
reason: 'Stealth addresses prevent any address reuse',
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// SIP breaks cluster analysis
|
|
318
|
+
const clusterImprovement = MAX_POINTS.clusterExposure - currentScore.breakdown.clusterExposure
|
|
319
|
+
if (clusterImprovement > 0) {
|
|
320
|
+
improvements.push({
|
|
321
|
+
category: 'clusterExposure',
|
|
322
|
+
currentScore: currentScore.breakdown.clusterExposure,
|
|
323
|
+
projectedScore: MAX_POINTS.clusterExposure,
|
|
324
|
+
reason: 'Stealth addresses cannot be linked via common input analysis',
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// SIP with viewing keys reduces exchange exposure impact
|
|
329
|
+
const exchangeImprovement = Math.min(
|
|
330
|
+
(MAX_POINTS.exchangeExposure - currentScore.breakdown.exchangeExposure) * 0.5,
|
|
331
|
+
10
|
|
332
|
+
)
|
|
333
|
+
if (exchangeImprovement > 0) {
|
|
334
|
+
improvements.push({
|
|
335
|
+
category: 'exchangeExposure',
|
|
336
|
+
currentScore: currentScore.breakdown.exchangeExposure,
|
|
337
|
+
projectedScore: currentScore.breakdown.exchangeExposure + Math.round(exchangeImprovement),
|
|
338
|
+
reason: 'Viewing keys allow selective disclosure without exposing full history',
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// SIP doesn't directly fix temporal patterns but can help with delayed execution
|
|
343
|
+
const temporalImprovement = Math.min(
|
|
344
|
+
(MAX_POINTS.temporalPatterns - currentScore.breakdown.temporalPatterns) * 0.3,
|
|
345
|
+
5
|
|
346
|
+
)
|
|
347
|
+
if (temporalImprovement > 0) {
|
|
348
|
+
improvements.push({
|
|
349
|
+
category: 'temporalPatterns',
|
|
350
|
+
currentScore: currentScore.breakdown.temporalPatterns,
|
|
351
|
+
projectedScore: currentScore.breakdown.temporalPatterns + Math.round(temporalImprovement),
|
|
352
|
+
reason: 'Private transactions reduce pattern correlation',
|
|
353
|
+
})
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Calculate projected score
|
|
357
|
+
const totalImprovement = improvements.reduce(
|
|
358
|
+
(sum, imp) => sum + (imp.projectedScore - imp.currentScore),
|
|
359
|
+
0
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
const projectedTotal =
|
|
363
|
+
(currentScore.overall / 100) * TOTAL_MAX_SCORE + totalImprovement
|
|
364
|
+
const projectedScore = Math.min(Math.round((projectedTotal / TOTAL_MAX_SCORE) * 100), 100)
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
currentScore: currentScore.overall,
|
|
368
|
+
projectedScore,
|
|
369
|
+
improvement: projectedScore - currentScore.overall,
|
|
370
|
+
improvements,
|
|
371
|
+
}
|
|
372
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surveillance Analysis Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for privacy scoring and wallet surveillance detection.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Risk level classification
|
|
11
|
+
*/
|
|
12
|
+
export type RiskLevel = 'critical' | 'high' | 'medium' | 'low'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Privacy score breakdown by category
|
|
16
|
+
*/
|
|
17
|
+
export interface PrivacyScoreBreakdown {
|
|
18
|
+
/** Address reuse score (0-25 points) */
|
|
19
|
+
addressReuse: number
|
|
20
|
+
/** Cluster exposure score (0-25 points) */
|
|
21
|
+
clusterExposure: number
|
|
22
|
+
/** Exchange exposure score (0-20 points) */
|
|
23
|
+
exchangeExposure: number
|
|
24
|
+
/** Temporal pattern score (0-15 points) */
|
|
25
|
+
temporalPatterns: number
|
|
26
|
+
/** Social linking score (0-15 points) */
|
|
27
|
+
socialLinks: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Recommendation for improving privacy
|
|
32
|
+
*/
|
|
33
|
+
export interface PrivacyRecommendation {
|
|
34
|
+
/** Unique identifier */
|
|
35
|
+
id: string
|
|
36
|
+
/** Severity of the issue */
|
|
37
|
+
severity: RiskLevel
|
|
38
|
+
/** Category this recommendation addresses */
|
|
39
|
+
category: keyof PrivacyScoreBreakdown
|
|
40
|
+
/** Human-readable title */
|
|
41
|
+
title: string
|
|
42
|
+
/** Detailed description of the issue */
|
|
43
|
+
description: string
|
|
44
|
+
/** Suggested action to improve */
|
|
45
|
+
action: string
|
|
46
|
+
/** Points that would be gained by fixing */
|
|
47
|
+
potentialGain: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Complete privacy analysis result
|
|
52
|
+
*/
|
|
53
|
+
export interface PrivacyScore {
|
|
54
|
+
/** Overall privacy score (0-100) */
|
|
55
|
+
overall: number
|
|
56
|
+
/** Score breakdown by category */
|
|
57
|
+
breakdown: PrivacyScoreBreakdown
|
|
58
|
+
/** Risk classification */
|
|
59
|
+
risk: RiskLevel
|
|
60
|
+
/** Actionable recommendations sorted by impact */
|
|
61
|
+
recommendations: PrivacyRecommendation[]
|
|
62
|
+
/** Analysis timestamp */
|
|
63
|
+
analyzedAt: number
|
|
64
|
+
/** Wallet address analyzed */
|
|
65
|
+
walletAddress: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Address reuse detection result
|
|
70
|
+
*/
|
|
71
|
+
export interface AddressReuseResult {
|
|
72
|
+
/** Number of times address was reused for receiving */
|
|
73
|
+
receiveReuseCount: number
|
|
74
|
+
/** Number of times address was reused for sending */
|
|
75
|
+
sendReuseCount: number
|
|
76
|
+
/** Total reuse instances */
|
|
77
|
+
totalReuseCount: number
|
|
78
|
+
/** Score deduction (0-25) */
|
|
79
|
+
scoreDeduction: number
|
|
80
|
+
/** Specific addresses that were reused */
|
|
81
|
+
reusedAddresses: Array<{
|
|
82
|
+
address: string
|
|
83
|
+
useCount: number
|
|
84
|
+
type: 'receive' | 'send' | 'both'
|
|
85
|
+
}>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Cluster detection result (Common Input Ownership Heuristic)
|
|
90
|
+
*/
|
|
91
|
+
export interface ClusterResult {
|
|
92
|
+
/** Number of linked addresses detected */
|
|
93
|
+
linkedAddressCount: number
|
|
94
|
+
/** Confidence score (0-1) */
|
|
95
|
+
confidence: number
|
|
96
|
+
/** Score deduction (0-25) */
|
|
97
|
+
scoreDeduction: number
|
|
98
|
+
/** Detected address clusters */
|
|
99
|
+
clusters: Array<{
|
|
100
|
+
addresses: string[]
|
|
101
|
+
linkType: 'common-input' | 'change-address' | 'consolidation'
|
|
102
|
+
transactionCount: number
|
|
103
|
+
}>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Known exchange information
|
|
108
|
+
*/
|
|
109
|
+
export interface KnownExchange {
|
|
110
|
+
name: string
|
|
111
|
+
addresses: string[]
|
|
112
|
+
type: 'cex' | 'dex'
|
|
113
|
+
kycRequired: boolean
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Exchange exposure detection result
|
|
118
|
+
*/
|
|
119
|
+
export interface ExchangeExposureResult {
|
|
120
|
+
/** Number of unique exchanges interacted with */
|
|
121
|
+
exchangeCount: number
|
|
122
|
+
/** Total deposits to exchanges */
|
|
123
|
+
depositCount: number
|
|
124
|
+
/** Total withdrawals from exchanges */
|
|
125
|
+
withdrawalCount: number
|
|
126
|
+
/** Score deduction (0-20) */
|
|
127
|
+
scoreDeduction: number
|
|
128
|
+
/** Detected exchange interactions */
|
|
129
|
+
exchanges: Array<{
|
|
130
|
+
name: string
|
|
131
|
+
type: 'cex' | 'dex'
|
|
132
|
+
kycRequired: boolean
|
|
133
|
+
deposits: number
|
|
134
|
+
withdrawals: number
|
|
135
|
+
firstInteraction: number
|
|
136
|
+
lastInteraction: number
|
|
137
|
+
}>
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Temporal pattern detection result
|
|
142
|
+
*/
|
|
143
|
+
export interface TemporalPatternResult {
|
|
144
|
+
/** Patterns detected */
|
|
145
|
+
patterns: Array<{
|
|
146
|
+
type: 'regular-schedule' | 'timezone-inference' | 'activity-burst'
|
|
147
|
+
description: string
|
|
148
|
+
confidence: number
|
|
149
|
+
evidence: {
|
|
150
|
+
dayOfWeek?: number[]
|
|
151
|
+
hourOfDay?: number[]
|
|
152
|
+
frequency?: string
|
|
153
|
+
}
|
|
154
|
+
}>
|
|
155
|
+
/** Inferred timezone (if detectable) */
|
|
156
|
+
inferredTimezone?: string
|
|
157
|
+
/** Score deduction (0-15) */
|
|
158
|
+
scoreDeduction: number
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Social profile linking result
|
|
163
|
+
*/
|
|
164
|
+
export interface SocialLinkResult {
|
|
165
|
+
/** Whether wallet is doxxed (publicly linked to identity) */
|
|
166
|
+
isDoxxed: boolean
|
|
167
|
+
/** Partial identity exposure */
|
|
168
|
+
partialExposure: boolean
|
|
169
|
+
/** Score deduction (0-15) */
|
|
170
|
+
scoreDeduction: number
|
|
171
|
+
/** Detected links */
|
|
172
|
+
links: Array<{
|
|
173
|
+
platform: 'sns' | 'ens' | 'twitter' | 'arkham' | 'other'
|
|
174
|
+
identifier: string
|
|
175
|
+
confidence: number
|
|
176
|
+
}>
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Transaction for analysis
|
|
181
|
+
*/
|
|
182
|
+
export interface AnalyzableTransaction {
|
|
183
|
+
/** Transaction signature/hash */
|
|
184
|
+
signature: string
|
|
185
|
+
/** Block slot/number */
|
|
186
|
+
slot: number
|
|
187
|
+
/** Unix timestamp */
|
|
188
|
+
timestamp: number
|
|
189
|
+
/** Sender address (null if contract call) */
|
|
190
|
+
sender: string | null
|
|
191
|
+
/** Recipient address (null if contract call) */
|
|
192
|
+
recipient: string | null
|
|
193
|
+
/** Amount transferred (in smallest unit) */
|
|
194
|
+
amount: bigint
|
|
195
|
+
/** Token mint (null for native) */
|
|
196
|
+
mint: string | null
|
|
197
|
+
/** Fee paid */
|
|
198
|
+
fee: bigint
|
|
199
|
+
/** All addresses involved in transaction */
|
|
200
|
+
involvedAddresses: string[]
|
|
201
|
+
/** Transaction type */
|
|
202
|
+
type: 'transfer' | 'swap' | 'stake' | 'other'
|
|
203
|
+
/** Whether this was successful */
|
|
204
|
+
success: boolean
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* SIP protection comparison
|
|
209
|
+
*/
|
|
210
|
+
export interface SIPProtectionComparison {
|
|
211
|
+
/** Current score without SIP */
|
|
212
|
+
currentScore: number
|
|
213
|
+
/** Projected score with SIP */
|
|
214
|
+
projectedScore: number
|
|
215
|
+
/** Improvement points */
|
|
216
|
+
improvement: number
|
|
217
|
+
/** Specific improvements by category */
|
|
218
|
+
improvements: Array<{
|
|
219
|
+
category: keyof PrivacyScoreBreakdown
|
|
220
|
+
currentScore: number
|
|
221
|
+
projectedScore: number
|
|
222
|
+
reason: string
|
|
223
|
+
}>
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Full analysis result with all details
|
|
228
|
+
*/
|
|
229
|
+
export interface FullAnalysisResult {
|
|
230
|
+
/** Privacy score summary */
|
|
231
|
+
privacyScore: PrivacyScore
|
|
232
|
+
/** Address reuse details */
|
|
233
|
+
addressReuse: AddressReuseResult
|
|
234
|
+
/** Cluster detection details */
|
|
235
|
+
cluster: ClusterResult
|
|
236
|
+
/** Exchange exposure details */
|
|
237
|
+
exchangeExposure: ExchangeExposureResult
|
|
238
|
+
/** Temporal patterns details */
|
|
239
|
+
temporalPatterns: TemporalPatternResult
|
|
240
|
+
/** Social links details */
|
|
241
|
+
socialLinks: SocialLinkResult
|
|
242
|
+
/** SIP protection comparison */
|
|
243
|
+
sipComparison: SIPProtectionComparison
|
|
244
|
+
/** Raw transaction data analyzed */
|
|
245
|
+
transactionCount: number
|
|
246
|
+
/** Analysis duration in ms */
|
|
247
|
+
analysisDurationMs: number
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Analyzer configuration
|
|
252
|
+
*/
|
|
253
|
+
export interface SurveillanceAnalyzerConfig {
|
|
254
|
+
/** Helius API key */
|
|
255
|
+
heliusApiKey: string
|
|
256
|
+
/** Solana cluster */
|
|
257
|
+
cluster?: 'mainnet-beta' | 'devnet'
|
|
258
|
+
/** Maximum transactions to analyze (default: 1000) */
|
|
259
|
+
maxTransactions?: number
|
|
260
|
+
/** Include social link detection (requires external APIs) */
|
|
261
|
+
includeSocialLinks?: boolean
|
|
262
|
+
/** Custom exchange address list */
|
|
263
|
+
customExchangeAddresses?: KnownExchange[]
|
|
264
|
+
}
|