solana-privacy-scanner-core 0.1.0 → 0.1.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/dist/index.cjs CHANGED
@@ -50,15 +50,14 @@ __export(index_exports, {
50
50
  });
51
51
  module.exports = __toCommonJS(index_exports);
52
52
 
53
- // src/rpc/client.js
53
+ // src/rpc/client.ts
54
54
  var import_web3 = require("@solana/web3.js");
55
55
  var RateLimiter = class {
56
- maxConcurrency;
57
- activeRequests = 0;
58
- queue = [];
59
56
  constructor(maxConcurrency) {
60
57
  this.maxConcurrency = maxConcurrency;
61
58
  }
59
+ activeRequests = 0;
60
+ queue = [];
62
61
  async acquire() {
63
62
  if (this.activeRequests < this.maxConcurrency) {
64
63
  this.activeRequests++;
@@ -92,14 +91,16 @@ var RPCClient = class {
92
91
  connection;
93
92
  config;
94
93
  rateLimiter;
95
- constructor(config) {
94
+ constructor(configOrUrl) {
95
+ const config = typeof configOrUrl === "string" ? { rpcUrl: configOrUrl } : configOrUrl;
96
+ const rpcUrl = config.rpcUrl.trim();
96
97
  this.config = {
97
98
  maxRetries: config.maxRetries ?? 3,
98
99
  retryDelay: config.retryDelay ?? 1e3,
99
100
  timeout: config.timeout ?? 3e4,
100
101
  maxConcurrency: config.maxConcurrency ?? 10,
101
102
  debug: config.debug ?? false,
102
- rpcUrl: config.rpcUrl
103
+ rpcUrl
103
104
  };
104
105
  const connectionConfig = {
105
106
  commitment: "confirmed",
@@ -130,7 +131,10 @@ var RPCClient = class {
130
131
  } catch (error) {
131
132
  lastError = error;
132
133
  if (this.config.debug) {
133
- console.error(`[RPCClient] Error in ${operationName} (attempt ${attempt + 1}/${this.config.maxRetries + 1}):`, error);
134
+ console.error(
135
+ `[RPCClient] Error in ${operationName} (attempt ${attempt + 1}/${this.config.maxRetries + 1}):`,
136
+ error
137
+ );
134
138
  }
135
139
  if (attempt < this.config.maxRetries) {
136
140
  const delay = this.config.retryDelay * Math.pow(2, attempt);
@@ -139,7 +143,9 @@ var RPCClient = class {
139
143
  }
140
144
  }
141
145
  this.rateLimiter.release();
142
- throw new Error(`RPC operation ${operationName} failed after ${this.config.maxRetries + 1} attempts: ${lastError?.message}`);
146
+ throw new Error(
147
+ `RPC operation ${operationName} failed after ${this.config.maxRetries + 1} attempts: ${lastError?.message}`
148
+ );
143
149
  }
144
150
  /**
145
151
  * Get the underlying Solana Connection
@@ -161,20 +167,29 @@ var RPCClient = class {
161
167
  * Get signatures for an address with retry and rate limiting
162
168
  */
163
169
  async getSignaturesForAddress(address, options) {
164
- return this.executeWithRetry(async () => {
165
- const { PublicKey } = await import("@solana/web3.js");
166
- return this.connection.getSignaturesForAddress(new PublicKey(address), options);
167
- }, `getSignaturesForAddress(${address})`);
170
+ return this.executeWithRetry(
171
+ async () => {
172
+ const { PublicKey } = await import("@solana/web3.js");
173
+ return this.connection.getSignaturesForAddress(
174
+ new PublicKey(address),
175
+ options
176
+ );
177
+ },
178
+ `getSignaturesForAddress(${address})`
179
+ );
168
180
  }
169
181
  /**
170
182
  * Get transaction details with retry and rate limiting
171
183
  */
172
184
  async getTransaction(signature, options) {
173
- return this.executeWithRetry(async () => {
174
- return this.connection.getTransaction(signature, {
175
- maxSupportedTransactionVersion: options?.maxSupportedTransactionVersion ?? 0
176
- });
177
- }, `getTransaction(${signature})`);
185
+ return this.executeWithRetry(
186
+ async () => {
187
+ return this.connection.getTransaction(signature, {
188
+ maxSupportedTransactionVersion: options?.maxSupportedTransactionVersion ?? 0
189
+ });
190
+ },
191
+ `getTransaction(${signature})`
192
+ );
178
193
  }
179
194
  /**
180
195
  * Get multiple transactions in parallel (respects rate limiting)
@@ -187,54 +202,69 @@ var RPCClient = class {
187
202
  * Get token accounts by owner with retry and rate limiting
188
203
  */
189
204
  async getTokenAccountsByOwner(ownerAddress, mintAddress) {
190
- return this.executeWithRetry(async () => {
191
- const { PublicKey } = await import("@solana/web3.js");
192
- const owner = new PublicKey(ownerAddress);
193
- const TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
194
- if (mintAddress) {
195
- const mint = new PublicKey(mintAddress);
196
- return this.connection.getTokenAccountsByOwner(owner, { mint });
197
- } else {
198
- return this.connection.getTokenAccountsByOwner(owner, {
199
- programId: TOKEN_PROGRAM_ID
200
- });
201
- }
202
- }, `getTokenAccountsByOwner(${ownerAddress})`);
205
+ return this.executeWithRetry(
206
+ async () => {
207
+ const { PublicKey } = await import("@solana/web3.js");
208
+ const owner = new PublicKey(ownerAddress);
209
+ const TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
210
+ if (mintAddress) {
211
+ const mint = new PublicKey(mintAddress);
212
+ return this.connection.getTokenAccountsByOwner(owner, { mint });
213
+ } else {
214
+ return this.connection.getTokenAccountsByOwner(owner, {
215
+ programId: TOKEN_PROGRAM_ID
216
+ });
217
+ }
218
+ },
219
+ `getTokenAccountsByOwner(${ownerAddress})`
220
+ );
203
221
  }
204
222
  /**
205
223
  * Get program accounts with retry and rate limiting
206
224
  */
207
225
  async getProgramAccounts(programId, config) {
208
- return this.executeWithRetry(async () => {
209
- const { PublicKey } = await import("@solana/web3.js");
210
- return this.connection.getProgramAccounts(new PublicKey(programId), config);
211
- }, `getProgramAccounts(${programId})`);
226
+ return this.executeWithRetry(
227
+ async () => {
228
+ const { PublicKey } = await import("@solana/web3.js");
229
+ return this.connection.getProgramAccounts(new PublicKey(programId), config);
230
+ },
231
+ `getProgramAccounts(${programId})`
232
+ );
212
233
  }
213
234
  /**
214
235
  * Get account info with retry and rate limiting
215
236
  */
216
237
  async getAccountInfo(address) {
217
- return this.executeWithRetry(async () => {
218
- const { PublicKey } = await import("@solana/web3.js");
219
- return this.connection.getAccountInfo(new PublicKey(address));
220
- }, `getAccountInfo(${address})`);
238
+ return this.executeWithRetry(
239
+ async () => {
240
+ const { PublicKey } = await import("@solana/web3.js");
241
+ return this.connection.getAccountInfo(new PublicKey(address));
242
+ },
243
+ `getAccountInfo(${address})`
244
+ );
221
245
  }
222
246
  /**
223
247
  * Get multiple account infos in parallel (respects rate limiting)
224
248
  */
225
249
  async getMultipleAccountsInfo(addresses) {
226
- return this.executeWithRetry(async () => {
227
- const { PublicKey } = await import("@solana/web3.js");
228
- const pubkeys = addresses.map((addr) => new PublicKey(addr));
229
- return this.connection.getMultipleAccountsInfo(pubkeys);
230
- }, `getMultipleAccountsInfo(${addresses.length} addresses)`);
250
+ return this.executeWithRetry(
251
+ async () => {
252
+ const { PublicKey } = await import("@solana/web3.js");
253
+ const pubkeys = addresses.map((addr) => new PublicKey(addr));
254
+ return this.connection.getMultipleAccountsInfo(pubkeys);
255
+ },
256
+ `getMultipleAccountsInfo(${addresses.length} addresses)`
257
+ );
231
258
  }
232
259
  /**
233
260
  * Check if the RPC connection is healthy
234
261
  */
235
262
  async healthCheck() {
236
263
  try {
237
- const version = await this.executeWithRetry(() => this.connection.getVersion(), "healthCheck");
264
+ const version = await this.executeWithRetry(
265
+ () => this.connection.getVersion(),
266
+ "healthCheck"
267
+ );
238
268
  return !!version;
239
269
  } catch {
240
270
  return false;
@@ -242,7 +272,7 @@ var RPCClient = class {
242
272
  }
243
273
  };
244
274
 
245
- // src/collectors/index.js
275
+ // src/collectors/index.ts
246
276
  async function collectWalletData(client, address, options = {}) {
247
277
  const maxSignatures = options.maxSignatures ?? 100;
248
278
  const includeTokenAccounts = options.includeTokenAccounts ?? true;
@@ -343,7 +373,7 @@ async function collectProgramData(client, programId, options = {}) {
343
373
  };
344
374
  }
345
375
 
346
- // src/normalizer/index.js
376
+ // src/normalizer/index.ts
347
377
  var PROGRAM_IDS = {
348
378
  SYSTEM: "11111111111111111111111111111111",
349
379
  TOKEN: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
@@ -374,14 +404,11 @@ function extractSOLTransfers(tx, signature) {
374
404
  continue;
375
405
  }
376
406
  const diff = post - pre;
377
- if (diff === 0)
378
- continue;
407
+ if (diff === 0) continue;
379
408
  const account = accountKeys[i];
380
- if (!account)
381
- continue;
409
+ if (!account) continue;
382
410
  const address = typeof account === "string" ? account : account.pubkey?.toString();
383
- if (!address)
384
- continue;
411
+ if (!address) continue;
385
412
  if (diff > 0) {
386
413
  for (let j = 0; j < accountKeys.length; j++) {
387
414
  const preSender = preBalances[j];
@@ -391,11 +418,9 @@ function extractSOLTransfers(tx, signature) {
391
418
  }
392
419
  if (postSender < preSender) {
393
420
  const sender = accountKeys[j];
394
- if (!sender)
395
- continue;
421
+ if (!sender) continue;
396
422
  const senderAddress = typeof sender === "string" ? sender : sender.pubkey?.toString();
397
- if (!senderAddress)
398
- continue;
423
+ if (!senderAddress) continue;
399
424
  transfers.push({
400
425
  from: senderAddress,
401
426
  to: address,
@@ -421,7 +446,9 @@ function extractSPLTransfers(tx, signature) {
421
446
  const postTokenBalances = tx.meta.postTokenBalances;
422
447
  const balanceChanges = /* @__PURE__ */ new Map();
423
448
  for (const post of postTokenBalances) {
424
- const pre = preTokenBalances.find((p) => p.accountIndex === post.accountIndex && p.mint === post.mint);
449
+ const pre = preTokenBalances.find(
450
+ (p) => p.accountIndex === post.accountIndex && p.mint === post.mint
451
+ );
425
452
  const preAmount = pre?.uiTokenAmount.uiAmount ?? 0;
426
453
  const postAmount = post.uiTokenAmount.uiAmount ?? 0;
427
454
  const change = postAmount - preAmount;
@@ -442,20 +469,16 @@ function extractSPLTransfers(tx, signature) {
442
469
  return;
443
470
  }
444
471
  const account = accountKeys[accountIndex];
445
- if (!account)
446
- return;
472
+ if (!account) return;
447
473
  const address = typeof account === "string" ? account : account.pubkey?.toString();
448
- if (!address)
449
- return;
474
+ if (!address) return;
450
475
  if (info.change > 0) {
451
476
  balanceChanges.forEach((senderInfo, senderIndex) => {
452
477
  if (senderInfo.mint === info.mint && senderInfo.change < 0 && senderIndex !== accountIndex && senderIndex < accountKeys.length) {
453
478
  const sender = accountKeys[senderIndex];
454
- if (!sender)
455
- return;
479
+ if (!sender) return;
456
480
  const senderAddress = typeof sender === "string" ? sender : sender.pubkey?.toString();
457
- if (!senderAddress)
458
- return;
481
+ if (!senderAddress) return;
459
482
  transfers.push({
460
483
  from: senderAddress,
461
484
  to: address,
@@ -563,8 +586,7 @@ function normalizeWalletData(rawData, labelProvider) {
563
586
  const allTransfers = [];
564
587
  const allInstructions = [];
565
588
  for (const rawTx of rawData.transactions) {
566
- if (!rawTx.transaction)
567
- continue;
589
+ if (!rawTx.transaction) continue;
568
590
  try {
569
591
  const solTransfers = extractSOLTransfers(rawTx.transaction, rawTx.signature);
570
592
  const splTransfers = extractSPLTransfers(rawTx.transaction, rawTx.signature);
@@ -644,8 +666,7 @@ function normalizeProgramData(rawData, labelProvider) {
644
666
  const allInstructions = [];
645
667
  const counterparties = /* @__PURE__ */ new Set();
646
668
  for (const rawTx of rawData.relatedTransactions) {
647
- if (!rawTx.transaction)
648
- continue;
669
+ if (!rawTx.transaction) continue;
649
670
  try {
650
671
  const solTransfers = extractSOLTransfers(rawTx.transaction, rawTx.signature);
651
672
  const splTransfers = extractSPLTransfers(rawTx.transaction, rawTx.signature);
@@ -679,7 +700,7 @@ function normalizeProgramData(rawData, labelProvider) {
679
700
  };
680
701
  }
681
702
 
682
- // src/heuristics/counterparty-reuse.js
703
+ // src/heuristics/counterparty-reuse.ts
683
704
  function detectCounterpartyReuse(context) {
684
705
  if (context.targetType !== "wallet") {
685
706
  return null;
@@ -690,8 +711,7 @@ function detectCounterpartyReuse(context) {
690
711
  const interactionCounts = /* @__PURE__ */ new Map();
691
712
  for (const transfer of context.transfers) {
692
713
  const counterparty = transfer.from === context.target ? transfer.to : transfer.from;
693
- if (counterparty === context.target)
694
- continue;
714
+ if (counterparty === context.target) continue;
695
715
  interactionCounts.set(counterparty, (interactionCounts.get(counterparty) || 0) + 1);
696
716
  }
697
717
  const reusedCounterparties = Array.from(interactionCounts.entries()).filter(([_, count]) => count >= 3).sort((a, b) => b[1] - a[1]);
@@ -724,7 +744,7 @@ function detectCounterpartyReuse(context) {
724
744
  };
725
745
  }
726
746
 
727
- // src/heuristics/amount-reuse.js
747
+ // src/heuristics/amount-reuse.ts
728
748
  function detectAmountReuse(context) {
729
749
  if (context.transfers.length < 3) {
730
750
  return null;
@@ -781,7 +801,7 @@ function detectAmountReuse(context) {
781
801
  };
782
802
  }
783
803
 
784
- // src/heuristics/timing-patterns.js
804
+ // src/heuristics/timing-patterns.ts
785
805
  function detectTimingPatterns(context) {
786
806
  if (!context.timeRange.earliest || !context.timeRange.latest) {
787
807
  return null;
@@ -833,7 +853,7 @@ function detectTimingPatterns(context) {
833
853
  };
834
854
  }
835
855
 
836
- // src/heuristics/known-entity.js
856
+ // src/heuristics/known-entity.ts
837
857
  function detectKnownEntityInteraction(context) {
838
858
  if (context.labels.size === 0) {
839
859
  return null;
@@ -887,7 +907,7 @@ function detectKnownEntityInteraction(context) {
887
907
  };
888
908
  }
889
909
 
890
- // src/heuristics/balance-traceability.js
910
+ // src/heuristics/balance-traceability.ts
891
911
  function detectBalanceTraceability(context) {
892
912
  if (context.targetType !== "wallet" || context.transfers.length < 2) {
893
913
  return null;
@@ -948,7 +968,7 @@ function detectBalanceTraceability(context) {
948
968
  };
949
969
  }
950
970
 
951
- // src/scanner/index.js
971
+ // src/scanner/index.ts
952
972
  var REPORT_VERSION = "1.0.0";
953
973
  var HEURISTICS = [
954
974
  detectCounterpartyReuse,
@@ -1039,7 +1059,7 @@ function generateReport(context) {
1039
1059
  };
1040
1060
  }
1041
1061
 
1042
- // src/labels/provider.js
1062
+ // src/labels/provider.ts
1043
1063
  var import_fs = require("fs");
1044
1064
  var import_url = require("url");
1045
1065
  var import_path = require("path");