tx-indexer 0.5.1 → 0.5.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/{client-iLW2_DnL.d.ts → client-DdzTiKZ4.d.ts} +25 -9
- package/dist/client.d.ts +1 -1
- package/dist/client.js +448 -85
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +448 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as ClassifiedTransaction, F as FetchTransactionsConfig, b as GetTransactionOptions, G as GetTransactionsOptions, I as IndexerRpcApi, N as NftMetadata, S as SolanaClient,
|
|
1
|
+
export { C as ClassifiedTransaction, k as FetchBatchOptions, l as FetchTransactionOptions, F as FetchTransactionsConfig, b as GetTransactionOptions, G as GetTransactionsOptions, I as IndexerRpcApi, N as NftMetadata, R as RetryConfig, S as SolanaClient, o as SpamFilterConfig, g as TokenAccountBalance, T as TxIndexer, a as TxIndexerOptions, W as WalletBalance, c as createIndexer, d as createSolanaClient, q as fetchNftMetadata, r as fetchNftMetadataBatch, i as fetchTransaction, j as fetchTransactionsBatch, f as fetchWalletBalance, h as fetchWalletSignatures, n as filterSpamTransactions, m as isSpamTransaction, p as parseAddress, e as parseSignature, t as transactionToLegs } from './client-DdzTiKZ4.js';
|
|
2
2
|
import { T as TxLeg, R as RawTransaction, a as TransactionClassification } from './classification.types-Cn9IGtEC.js';
|
|
3
3
|
export { f as RawTransactionSchema, k as TokenBalance, e as TokenBalanceSchema, n as TransactionClassificationSchema, j as TxCategory, d as TxCategorySchema, h as TxDirection, b as TxDirectionSchema, m as TxLegRole, g as TxLegSchema, l as TxLegSide, i as TxPrimaryType, c as TxPrimaryTypeSchema } from './classification.types-Cn9IGtEC.js';
|
|
4
4
|
import { ProtocolInfo, TokenInfo } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,57 @@ function getTokenInfo(mint) {
|
|
|
61
61
|
KNOWN_TOKENS.USDC
|
|
62
62
|
];
|
|
63
63
|
|
|
64
|
+
// ../solana/src/constants/program-ids.ts
|
|
65
|
+
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
66
|
+
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
67
|
+
var STAKE_PROGRAM_ID = "Stake11111111111111111111111111111111111111";
|
|
68
|
+
var STAKE_POOL_PROGRAM_ID = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy";
|
|
69
|
+
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
70
|
+
var TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
71
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
72
|
+
var SPL_MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
73
|
+
var MEMO_V1_PROGRAM_ID = "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo";
|
|
74
|
+
var JUPITER_V6_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
|
|
75
|
+
var JUPITER_V4_PROGRAM_ID = "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB";
|
|
76
|
+
var JUPITER_ORDER_ENGINE_PROGRAM_ID = "61DFfeTKM7trxYcPQCM78bJ794ddZprZpAwAnLiwTpYH";
|
|
77
|
+
var RAYDIUM_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
|
78
|
+
var RAYDIUM_CLMM_PROGRAM_ID = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK";
|
|
79
|
+
var RAYDIUM_CPMM_PROGRAM_ID = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
|
|
80
|
+
var RAYDIUM_STABLE_PROGRAM_ID = "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h";
|
|
81
|
+
var ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
|
|
82
|
+
var ORCA_TOKEN_SWAP_V1_PROGRAM_ID = "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP";
|
|
83
|
+
var OPENBOOK_V2_PROGRAM_ID = "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb";
|
|
84
|
+
var PHOENIX_PROGRAM_ID = "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY";
|
|
85
|
+
var SABER_STABLE_SWAP_PROGRAM_ID = "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ";
|
|
86
|
+
var MERCURIAL_STABLE_SWAP_PROGRAM_ID = "MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky";
|
|
87
|
+
var METEORA_DLMM_PROGRAM_ID = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
|
|
88
|
+
var METEORA_POOLS_PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
|
|
89
|
+
var PUMPFUN_AMM_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
|
|
90
|
+
var PUMPFUN_BONDING_CURVE_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
|
|
91
|
+
var LIFINITY_V2_PROGRAM_ID = "2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c";
|
|
92
|
+
var METAPLEX_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
93
|
+
var CANDY_MACHINE_V3_PROGRAM_ID = "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR";
|
|
94
|
+
var CANDY_GUARD_PROGRAM_ID = "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g";
|
|
95
|
+
var BUBBLEGUM_PROGRAM_ID = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
|
96
|
+
var MAGIC_EDEN_CANDY_MACHINE_ID = "CMZYPASGWeTz7RNGHaRJfCq2XQ5pYK6nDvVQxzkH51zb";
|
|
97
|
+
var WORMHOLE_PROGRAM_ID = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
|
|
98
|
+
var WORMHOLE_TOKEN_BRIDGE_ID = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
|
|
99
|
+
var DEGODS_BRIDGE_PROGRAM_ID = "35iLrpYNNR9ygHLcvE1xKFHbHq6paHthrF6wSovdWgGu";
|
|
100
|
+
var DEBRIDGE_PROGRAM_ID = "DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh";
|
|
101
|
+
var ALLBRIDGE_PROGRAM_ID = "BrdgN2RPzEMWF96ZbnnJaUtQDQx7VRXYaHHbYCBvceWB";
|
|
102
|
+
var PAYAI_FACILITATOR = "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4";
|
|
103
|
+
var KNOWN_FACILITATORS = [PAYAI_FACILITATOR];
|
|
104
|
+
function detectFacilitator(accountKeys) {
|
|
105
|
+
for (const facilitator of KNOWN_FACILITATORS) {
|
|
106
|
+
if (accountKeys.includes(facilitator)) {
|
|
107
|
+
if (facilitator === PAYAI_FACILITATOR) {
|
|
108
|
+
return "payai";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
64
115
|
// ../solana/src/fetcher/balances.ts
|
|
65
116
|
async function fetchWalletBalance(rpc, walletAddress, tokenMints) {
|
|
66
117
|
const balanceResponse = await rpc.getBalance(walletAddress).send();
|
|
@@ -78,12 +129,17 @@ async function fetchWalletBalance(rpc, walletAddress, tokenMints) {
|
|
|
78
129
|
}
|
|
79
130
|
async function fetchTokenAccounts(rpc, walletAddress) {
|
|
80
131
|
const accountsMap = /* @__PURE__ */ new Map();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
132
|
+
const tokenPrograms = [TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID];
|
|
133
|
+
const responses = await Promise.all(
|
|
134
|
+
tokenPrograms.map(
|
|
135
|
+
(programId) => rpc.getTokenAccountsByOwner(
|
|
136
|
+
walletAddress,
|
|
137
|
+
{ programId: address(programId) },
|
|
138
|
+
{ encoding: "jsonParsed" }
|
|
139
|
+
).send().catch(() => ({ value: [] }))
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
for (const response of responses) {
|
|
87
143
|
for (const account of response.value) {
|
|
88
144
|
const parsedInfo = account.account.data.parsed.info;
|
|
89
145
|
const mint = parsedInfo.mint;
|
|
@@ -100,8 +156,6 @@ async function fetchTokenAccounts(rpc, walletAddress) {
|
|
|
100
156
|
symbol
|
|
101
157
|
});
|
|
102
158
|
}
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error("Error fetching token accounts:", error);
|
|
105
159
|
}
|
|
106
160
|
return accountsMap;
|
|
107
161
|
}
|
|
@@ -145,44 +199,6 @@ function extractProgramIds(transaction) {
|
|
|
145
199
|
return Array.from(programIds);
|
|
146
200
|
}
|
|
147
201
|
|
|
148
|
-
// ../solana/src/constants/program-ids.ts
|
|
149
|
-
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
150
|
-
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
151
|
-
var STAKE_PROGRAM_ID = "Stake11111111111111111111111111111111111111";
|
|
152
|
-
var STAKE_POOL_PROGRAM_ID = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy";
|
|
153
|
-
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
154
|
-
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
155
|
-
var SPL_MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
156
|
-
var MEMO_V1_PROGRAM_ID = "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo";
|
|
157
|
-
var JUPITER_V6_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
|
|
158
|
-
var JUPITER_V4_PROGRAM_ID = "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB";
|
|
159
|
-
var RAYDIUM_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
|
160
|
-
var ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
|
|
161
|
-
var METAPLEX_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
162
|
-
var CANDY_MACHINE_V3_PROGRAM_ID = "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR";
|
|
163
|
-
var CANDY_GUARD_PROGRAM_ID = "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g";
|
|
164
|
-
var BUBBLEGUM_PROGRAM_ID = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
|
165
|
-
var MAGIC_EDEN_CANDY_MACHINE_ID = "CMZYPASGWeTz7RNGHaRJfCq2XQ5pYK6nDvVQxzkH51zb";
|
|
166
|
-
var WORMHOLE_PROGRAM_ID = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
|
|
167
|
-
var WORMHOLE_TOKEN_BRIDGE_ID = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
|
|
168
|
-
var DEGODS_BRIDGE_PROGRAM_ID = "35iLrpYNNR9ygHLcvE1xKFHbHq6paHthrF6wSovdWgGu";
|
|
169
|
-
var DEBRIDGE_PROGRAM_ID = "DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh";
|
|
170
|
-
var ALLBRIDGE_PROGRAM_ID = "BrdgN2RPzEMWF96ZbnnJaUtQDQx7VRXYaHHbYCBvceWB";
|
|
171
|
-
var PAYAI_FACILITATOR = "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4";
|
|
172
|
-
var KNOWN_FACILITATORS = [
|
|
173
|
-
PAYAI_FACILITATOR
|
|
174
|
-
];
|
|
175
|
-
function detectFacilitator(accountKeys) {
|
|
176
|
-
for (const facilitator of KNOWN_FACILITATORS) {
|
|
177
|
-
if (accountKeys.includes(facilitator)) {
|
|
178
|
-
if (facilitator === PAYAI_FACILITATOR) {
|
|
179
|
-
return "payai";
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
202
|
// ../../node_modules/.bun/base-x@5.0.1/node_modules/base-x/src/esm/index.js
|
|
187
203
|
function base(ALPHABET2) {
|
|
188
204
|
if (ALPHABET2.length >= 255) {
|
|
@@ -392,6 +408,189 @@ function isSolanaPayTransaction(programIds, memo) {
|
|
|
392
408
|
return hasMemoProgram && memo !== null && memo !== void 0;
|
|
393
409
|
}
|
|
394
410
|
|
|
411
|
+
// ../solana/src/rpc/retry.ts
|
|
412
|
+
var DEFAULT_CONFIG = {
|
|
413
|
+
maxAttempts: 3,
|
|
414
|
+
baseDelayMs: 1e3,
|
|
415
|
+
maxDelayMs: 1e4
|
|
416
|
+
};
|
|
417
|
+
function isRetryableError(error) {
|
|
418
|
+
if (error instanceof Error) {
|
|
419
|
+
const message = error.message.toLowerCase();
|
|
420
|
+
return message.includes("timeout") || message.includes("econnreset") || message.includes("econnrefused") || message.includes("socket hang up") || message.includes("network") || message.includes("429") || message.includes("rate limit") || message.includes("too many requests") || message.includes("503") || message.includes("502") || message.includes("504");
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
function calculateDelay(attempt, baseDelayMs, maxDelayMs) {
|
|
425
|
+
const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
426
|
+
const jitter = Math.random() * 0.3 * exponentialDelay;
|
|
427
|
+
return Math.min(exponentialDelay + jitter, maxDelayMs);
|
|
428
|
+
}
|
|
429
|
+
function sleep(ms) {
|
|
430
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
431
|
+
}
|
|
432
|
+
async function withRetry(fn, config = {}) {
|
|
433
|
+
const { maxAttempts, baseDelayMs, maxDelayMs } = {
|
|
434
|
+
...DEFAULT_CONFIG,
|
|
435
|
+
...config
|
|
436
|
+
};
|
|
437
|
+
let lastError;
|
|
438
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
439
|
+
try {
|
|
440
|
+
return await fn();
|
|
441
|
+
} catch (error) {
|
|
442
|
+
lastError = error;
|
|
443
|
+
const isLastAttempt = attempt === maxAttempts;
|
|
444
|
+
const shouldRetry = !isLastAttempt && isRetryableError(error);
|
|
445
|
+
if (!shouldRetry) {
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
const delay = calculateDelay(attempt, baseDelayMs, maxDelayMs);
|
|
449
|
+
await sleep(delay);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
throw lastError;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ../../node_modules/.bun/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
456
|
+
var Node = class {
|
|
457
|
+
value;
|
|
458
|
+
next;
|
|
459
|
+
constructor(value) {
|
|
460
|
+
this.value = value;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
var Queue = class {
|
|
464
|
+
#head;
|
|
465
|
+
#tail;
|
|
466
|
+
#size;
|
|
467
|
+
constructor() {
|
|
468
|
+
this.clear();
|
|
469
|
+
}
|
|
470
|
+
enqueue(value) {
|
|
471
|
+
const node = new Node(value);
|
|
472
|
+
if (this.#head) {
|
|
473
|
+
this.#tail.next = node;
|
|
474
|
+
this.#tail = node;
|
|
475
|
+
} else {
|
|
476
|
+
this.#head = node;
|
|
477
|
+
this.#tail = node;
|
|
478
|
+
}
|
|
479
|
+
this.#size++;
|
|
480
|
+
}
|
|
481
|
+
dequeue() {
|
|
482
|
+
const current = this.#head;
|
|
483
|
+
if (!current) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
this.#head = this.#head.next;
|
|
487
|
+
this.#size--;
|
|
488
|
+
if (!this.#head) {
|
|
489
|
+
this.#tail = void 0;
|
|
490
|
+
}
|
|
491
|
+
return current.value;
|
|
492
|
+
}
|
|
493
|
+
peek() {
|
|
494
|
+
if (!this.#head) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
return this.#head.value;
|
|
498
|
+
}
|
|
499
|
+
clear() {
|
|
500
|
+
this.#head = void 0;
|
|
501
|
+
this.#tail = void 0;
|
|
502
|
+
this.#size = 0;
|
|
503
|
+
}
|
|
504
|
+
get size() {
|
|
505
|
+
return this.#size;
|
|
506
|
+
}
|
|
507
|
+
*[Symbol.iterator]() {
|
|
508
|
+
let current = this.#head;
|
|
509
|
+
while (current) {
|
|
510
|
+
yield current.value;
|
|
511
|
+
current = current.next;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
*drain() {
|
|
515
|
+
while (this.#head) {
|
|
516
|
+
yield this.dequeue();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
// ../../node_modules/.bun/p-limit@6.2.0/node_modules/p-limit/index.js
|
|
522
|
+
function pLimit(concurrency) {
|
|
523
|
+
validateConcurrency(concurrency);
|
|
524
|
+
const queue = new Queue();
|
|
525
|
+
let activeCount = 0;
|
|
526
|
+
const resumeNext = () => {
|
|
527
|
+
if (activeCount < concurrency && queue.size > 0) {
|
|
528
|
+
queue.dequeue()();
|
|
529
|
+
activeCount++;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
const next = () => {
|
|
533
|
+
activeCount--;
|
|
534
|
+
resumeNext();
|
|
535
|
+
};
|
|
536
|
+
const run = async (function_, resolve, arguments_) => {
|
|
537
|
+
const result = (async () => function_(...arguments_))();
|
|
538
|
+
resolve(result);
|
|
539
|
+
try {
|
|
540
|
+
await result;
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
next();
|
|
544
|
+
};
|
|
545
|
+
const enqueue = (function_, resolve, arguments_) => {
|
|
546
|
+
new Promise((internalResolve) => {
|
|
547
|
+
queue.enqueue(internalResolve);
|
|
548
|
+
}).then(
|
|
549
|
+
run.bind(void 0, function_, resolve, arguments_)
|
|
550
|
+
);
|
|
551
|
+
(async () => {
|
|
552
|
+
await Promise.resolve();
|
|
553
|
+
if (activeCount < concurrency) {
|
|
554
|
+
resumeNext();
|
|
555
|
+
}
|
|
556
|
+
})();
|
|
557
|
+
};
|
|
558
|
+
const generator = (function_, ...arguments_) => new Promise((resolve) => {
|
|
559
|
+
enqueue(function_, resolve, arguments_);
|
|
560
|
+
});
|
|
561
|
+
Object.defineProperties(generator, {
|
|
562
|
+
activeCount: {
|
|
563
|
+
get: () => activeCount
|
|
564
|
+
},
|
|
565
|
+
pendingCount: {
|
|
566
|
+
get: () => queue.size
|
|
567
|
+
},
|
|
568
|
+
clearQueue: {
|
|
569
|
+
value() {
|
|
570
|
+
queue.clear();
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
concurrency: {
|
|
574
|
+
get: () => concurrency,
|
|
575
|
+
set(newConcurrency) {
|
|
576
|
+
validateConcurrency(newConcurrency);
|
|
577
|
+
concurrency = newConcurrency;
|
|
578
|
+
queueMicrotask(() => {
|
|
579
|
+
while (activeCount < concurrency && queue.size > 0) {
|
|
580
|
+
resumeNext();
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
return generator;
|
|
587
|
+
}
|
|
588
|
+
function validateConcurrency(concurrency) {
|
|
589
|
+
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
|
|
590
|
+
throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
395
594
|
// ../solana/src/fetcher/transactions.ts
|
|
396
595
|
async function fetchWalletSignatures(rpc, walletAddress, config = {}) {
|
|
397
596
|
const { limit = 100, before, until } = config;
|
|
@@ -410,12 +609,16 @@ async function fetchWalletSignatures(rpc, walletAddress, config = {}) {
|
|
|
410
609
|
memo: sig.memo || null
|
|
411
610
|
}));
|
|
412
611
|
}
|
|
413
|
-
async function fetchTransaction(rpc, signature2,
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
612
|
+
async function fetchTransaction(rpc, signature2, options = {}) {
|
|
613
|
+
const { commitment = "confirmed", retry } = options;
|
|
614
|
+
const response = await withRetry(
|
|
615
|
+
() => rpc.getTransaction(signature2, {
|
|
616
|
+
commitment,
|
|
617
|
+
maxSupportedTransactionVersion: 0,
|
|
618
|
+
encoding: "json"
|
|
619
|
+
}).send(),
|
|
620
|
+
retry
|
|
621
|
+
);
|
|
419
622
|
if (!response) {
|
|
420
623
|
return null;
|
|
421
624
|
}
|
|
@@ -462,10 +665,29 @@ async function fetchTransaction(rpc, signature2, commitment = "confirmed") {
|
|
|
462
665
|
memo
|
|
463
666
|
};
|
|
464
667
|
}
|
|
465
|
-
async function fetchTransactionsBatch(rpc, signatures,
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
668
|
+
async function fetchTransactionsBatch(rpc, signatures, options = {}) {
|
|
669
|
+
const {
|
|
670
|
+
commitment = "confirmed",
|
|
671
|
+
concurrency = 10,
|
|
672
|
+
retry,
|
|
673
|
+
onFetchError
|
|
674
|
+
} = options;
|
|
675
|
+
if (signatures.length === 0) {
|
|
676
|
+
return [];
|
|
677
|
+
}
|
|
678
|
+
const limit = pLimit(concurrency);
|
|
679
|
+
const safeFetch = async (sig) => {
|
|
680
|
+
try {
|
|
681
|
+
return await fetchTransaction(rpc, sig, { commitment, retry });
|
|
682
|
+
} catch (error) {
|
|
683
|
+
onFetchError?.(
|
|
684
|
+
sig,
|
|
685
|
+
error instanceof Error ? error : new Error(String(error))
|
|
686
|
+
);
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
const promises = signatures.map((sig) => limit(() => safeFetch(sig)));
|
|
469
691
|
const results = await Promise.all(promises);
|
|
470
692
|
return results.filter((tx) => tx !== null);
|
|
471
693
|
}
|
|
@@ -640,7 +862,7 @@ function transactionToLegs(tx) {
|
|
|
640
862
|
amountRaw: change.change.toString().replace("-", ""),
|
|
641
863
|
amountUi: Math.abs(change.changeUi)
|
|
642
864
|
},
|
|
643
|
-
role: determineSolRole(change, tx
|
|
865
|
+
role: determineSolRole(change, tx)
|
|
644
866
|
});
|
|
645
867
|
}
|
|
646
868
|
const networkFee = totalSolDebits - totalSolCredits;
|
|
@@ -697,13 +919,8 @@ function transactionToLegs(tx) {
|
|
|
697
919
|
}
|
|
698
920
|
return legs;
|
|
699
921
|
}
|
|
700
|
-
function determineSolRole(change, tx,
|
|
701
|
-
const isFeePayer = feePayer ? change.address.toLowerCase() === feePayer : false;
|
|
922
|
+
function determineSolRole(change, tx, _feePayer) {
|
|
702
923
|
const isPositive = change.change > 0n;
|
|
703
|
-
const amountSol = Math.abs(change.changeUi);
|
|
704
|
-
if (isFeePayer && !isPositive && amountSol < 0.01) {
|
|
705
|
-
return "fee";
|
|
706
|
-
}
|
|
707
924
|
if (isPositive) {
|
|
708
925
|
if (tx.protocol?.id === "stake") {
|
|
709
926
|
return "reward";
|
|
@@ -763,6 +980,7 @@ var TransferClassifier = class {
|
|
|
763
980
|
|
|
764
981
|
// ../classification/src/protocols/detector.ts
|
|
765
982
|
var KNOWN_PROGRAMS = {
|
|
983
|
+
// Jupiter aggregator
|
|
766
984
|
[JUPITER_V6_PROGRAM_ID]: {
|
|
767
985
|
id: "jupiter",
|
|
768
986
|
name: "Jupiter"
|
|
@@ -771,10 +989,19 @@ var KNOWN_PROGRAMS = {
|
|
|
771
989
|
id: "jupiter-v4",
|
|
772
990
|
name: "Jupiter V4"
|
|
773
991
|
},
|
|
992
|
+
[JUPITER_ORDER_ENGINE_PROGRAM_ID]: {
|
|
993
|
+
id: "jupiter-limit-order",
|
|
994
|
+
name: "Jupiter Limit Order"
|
|
995
|
+
},
|
|
996
|
+
// Core token programs
|
|
774
997
|
[TOKEN_PROGRAM_ID]: {
|
|
775
998
|
id: "spl-token",
|
|
776
999
|
name: "Token Program"
|
|
777
1000
|
},
|
|
1001
|
+
[TOKEN_2022_PROGRAM_ID]: {
|
|
1002
|
+
id: "token-2022",
|
|
1003
|
+
name: "Token-2022 Program"
|
|
1004
|
+
},
|
|
778
1005
|
[SYSTEM_PROGRAM_ID]: {
|
|
779
1006
|
id: "system",
|
|
780
1007
|
name: "System Program"
|
|
@@ -787,25 +1014,86 @@ var KNOWN_PROGRAMS = {
|
|
|
787
1014
|
id: "associated-token",
|
|
788
1015
|
name: "Associated Token Program"
|
|
789
1016
|
},
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1017
|
+
// Memo programs
|
|
1018
|
+
[SPL_MEMO_PROGRAM_ID]: {
|
|
1019
|
+
id: "memo",
|
|
1020
|
+
name: "Memo Program"
|
|
793
1021
|
},
|
|
794
|
-
[
|
|
795
|
-
id: "
|
|
796
|
-
name: "
|
|
1022
|
+
[MEMO_V1_PROGRAM_ID]: {
|
|
1023
|
+
id: "memo-v1",
|
|
1024
|
+
name: "Memo Program V1"
|
|
797
1025
|
},
|
|
1026
|
+
// Raydium AMMs
|
|
798
1027
|
[RAYDIUM_PROGRAM_ID]: {
|
|
799
1028
|
id: "raydium",
|
|
800
1029
|
name: "Raydium"
|
|
801
1030
|
},
|
|
802
|
-
[
|
|
803
|
-
id: "
|
|
804
|
-
name: "
|
|
1031
|
+
[RAYDIUM_CLMM_PROGRAM_ID]: {
|
|
1032
|
+
id: "raydium-clmm",
|
|
1033
|
+
name: "Raydium CLMM"
|
|
805
1034
|
},
|
|
806
|
-
[
|
|
807
|
-
id: "
|
|
808
|
-
name: "
|
|
1035
|
+
[RAYDIUM_CPMM_PROGRAM_ID]: {
|
|
1036
|
+
id: "raydium-cpmm",
|
|
1037
|
+
name: "Raydium CPMM"
|
|
1038
|
+
},
|
|
1039
|
+
[RAYDIUM_STABLE_PROGRAM_ID]: {
|
|
1040
|
+
id: "raydium-stable",
|
|
1041
|
+
name: "Raydium Stable"
|
|
1042
|
+
},
|
|
1043
|
+
// Orca
|
|
1044
|
+
[ORCA_WHIRLPOOL_PROGRAM_ID]: {
|
|
1045
|
+
id: "orca-whirlpool",
|
|
1046
|
+
name: "Orca Whirlpool"
|
|
1047
|
+
},
|
|
1048
|
+
[ORCA_TOKEN_SWAP_V1_PROGRAM_ID]: {
|
|
1049
|
+
id: "orca-v1",
|
|
1050
|
+
name: "Orca Token Swap V1"
|
|
1051
|
+
},
|
|
1052
|
+
// CLOBs (Central Limit Order Books)
|
|
1053
|
+
[OPENBOOK_V2_PROGRAM_ID]: {
|
|
1054
|
+
id: "openbook",
|
|
1055
|
+
name: "OpenBook"
|
|
1056
|
+
},
|
|
1057
|
+
[PHOENIX_PROGRAM_ID]: {
|
|
1058
|
+
id: "phoenix",
|
|
1059
|
+
name: "Phoenix"
|
|
1060
|
+
},
|
|
1061
|
+
// Stableswap protocols
|
|
1062
|
+
[SABER_STABLE_SWAP_PROGRAM_ID]: {
|
|
1063
|
+
id: "saber",
|
|
1064
|
+
name: "Saber"
|
|
1065
|
+
},
|
|
1066
|
+
[MERCURIAL_STABLE_SWAP_PROGRAM_ID]: {
|
|
1067
|
+
id: "mercurial",
|
|
1068
|
+
name: "Mercurial"
|
|
1069
|
+
},
|
|
1070
|
+
// Meteora
|
|
1071
|
+
[METEORA_DLMM_PROGRAM_ID]: {
|
|
1072
|
+
id: "meteora-dlmm",
|
|
1073
|
+
name: "Meteora DLMM"
|
|
1074
|
+
},
|
|
1075
|
+
[METEORA_POOLS_PROGRAM_ID]: {
|
|
1076
|
+
id: "meteora-pools",
|
|
1077
|
+
name: "Meteora Pools"
|
|
1078
|
+
},
|
|
1079
|
+
// Pump.fun
|
|
1080
|
+
[PUMPFUN_AMM_PROGRAM_ID]: {
|
|
1081
|
+
id: "pumpfun",
|
|
1082
|
+
name: "Pump.fun"
|
|
1083
|
+
},
|
|
1084
|
+
[PUMPFUN_BONDING_CURVE_PROGRAM_ID]: {
|
|
1085
|
+
id: "pumpfun-bonding",
|
|
1086
|
+
name: "Pump.fun Bonding Curve"
|
|
1087
|
+
},
|
|
1088
|
+
// Lifinity
|
|
1089
|
+
[LIFINITY_V2_PROGRAM_ID]: {
|
|
1090
|
+
id: "lifinity",
|
|
1091
|
+
name: "Lifinity"
|
|
1092
|
+
},
|
|
1093
|
+
// NFT programs
|
|
1094
|
+
[METAPLEX_PROGRAM_ID]: {
|
|
1095
|
+
id: "metaplex",
|
|
1096
|
+
name: "Metaplex"
|
|
809
1097
|
},
|
|
810
1098
|
[CANDY_GUARD_PROGRAM_ID]: {
|
|
811
1099
|
id: "candy-guard",
|
|
@@ -823,6 +1111,16 @@ var KNOWN_PROGRAMS = {
|
|
|
823
1111
|
id: "magic-eden-candy-machine",
|
|
824
1112
|
name: "Nft Candy Machine Program (Magic Eden)"
|
|
825
1113
|
},
|
|
1114
|
+
// Staking programs
|
|
1115
|
+
[STAKE_PROGRAM_ID]: {
|
|
1116
|
+
id: "stake",
|
|
1117
|
+
name: "Stake Program"
|
|
1118
|
+
},
|
|
1119
|
+
[STAKE_POOL_PROGRAM_ID]: {
|
|
1120
|
+
id: "stake-pool",
|
|
1121
|
+
name: "Stake Pool Program"
|
|
1122
|
+
},
|
|
1123
|
+
// Bridge programs
|
|
826
1124
|
[WORMHOLE_PROGRAM_ID]: {
|
|
827
1125
|
id: "wormhole",
|
|
828
1126
|
name: "Wormhole"
|
|
@@ -845,27 +1143,79 @@ var KNOWN_PROGRAMS = {
|
|
|
845
1143
|
}
|
|
846
1144
|
};
|
|
847
1145
|
var PRIORITY_ORDER = [
|
|
1146
|
+
// Bridge protocols (highest priority - cross-chain operations)
|
|
848
1147
|
"wormhole",
|
|
849
1148
|
"wormhole-token-bridge",
|
|
850
1149
|
"degods-bridge",
|
|
851
1150
|
"debridge",
|
|
852
1151
|
"allbridge",
|
|
1152
|
+
// DEX aggregators (route through multiple DEXes)
|
|
853
1153
|
"jupiter",
|
|
854
1154
|
"jupiter-v4",
|
|
1155
|
+
"jupiter-limit-order",
|
|
1156
|
+
// AMMs and DEXes
|
|
855
1157
|
"raydium",
|
|
1158
|
+
"raydium-clmm",
|
|
1159
|
+
"raydium-cpmm",
|
|
1160
|
+
"raydium-stable",
|
|
856
1161
|
"orca-whirlpool",
|
|
1162
|
+
"orca-v1",
|
|
1163
|
+
"meteora-dlmm",
|
|
1164
|
+
"meteora-pools",
|
|
1165
|
+
"lifinity",
|
|
1166
|
+
"pumpfun",
|
|
1167
|
+
"pumpfun-bonding",
|
|
1168
|
+
// CLOBs
|
|
1169
|
+
"openbook",
|
|
1170
|
+
"phoenix",
|
|
1171
|
+
// Stableswap
|
|
1172
|
+
"saber",
|
|
1173
|
+
"mercurial",
|
|
1174
|
+
// NFT
|
|
857
1175
|
"metaplex",
|
|
1176
|
+
"candy-guard",
|
|
1177
|
+
"candy-machine-v3",
|
|
1178
|
+
"bubblegum",
|
|
1179
|
+
"magic-eden-candy-machine",
|
|
1180
|
+
// Staking
|
|
858
1181
|
"stake",
|
|
1182
|
+
"stake-pool",
|
|
1183
|
+
// Infrastructure (lowest priority)
|
|
1184
|
+
"memo",
|
|
1185
|
+
"memo-v1",
|
|
859
1186
|
"associated-token",
|
|
860
1187
|
"spl-token",
|
|
1188
|
+
"token-2022",
|
|
861
1189
|
"compute-budget",
|
|
862
1190
|
"system"
|
|
863
1191
|
];
|
|
864
1192
|
var DEX_PROTOCOL_IDS2 = /* @__PURE__ */ new Set([
|
|
1193
|
+
// Jupiter aggregator
|
|
865
1194
|
"jupiter",
|
|
866
1195
|
"jupiter-v4",
|
|
1196
|
+
"jupiter-limit-order",
|
|
1197
|
+
// Raydium AMMs
|
|
867
1198
|
"raydium",
|
|
868
|
-
"
|
|
1199
|
+
"raydium-clmm",
|
|
1200
|
+
"raydium-cpmm",
|
|
1201
|
+
"raydium-stable",
|
|
1202
|
+
// Orca
|
|
1203
|
+
"orca-whirlpool",
|
|
1204
|
+
"orca-v1",
|
|
1205
|
+
// CLOBs
|
|
1206
|
+
"openbook",
|
|
1207
|
+
"phoenix",
|
|
1208
|
+
// Stableswap
|
|
1209
|
+
"saber",
|
|
1210
|
+
"mercurial",
|
|
1211
|
+
// Meteora
|
|
1212
|
+
"meteora-dlmm",
|
|
1213
|
+
"meteora-pools",
|
|
1214
|
+
// Pump.fun
|
|
1215
|
+
"pumpfun",
|
|
1216
|
+
"pumpfun-bonding",
|
|
1217
|
+
// Lifinity
|
|
1218
|
+
"lifinity"
|
|
869
1219
|
]);
|
|
870
1220
|
var NFT_MINT_PROTOCOL_IDS = /* @__PURE__ */ new Set([
|
|
871
1221
|
"metaplex",
|
|
@@ -914,15 +1264,28 @@ function detectProtocol(programIds) {
|
|
|
914
1264
|
}
|
|
915
1265
|
|
|
916
1266
|
// ../classification/src/classifiers/swap-classifier.ts
|
|
1267
|
+
function findSwapPair(tokensOut, tokensIn) {
|
|
1268
|
+
let bestPair = null;
|
|
1269
|
+
let bestScore = 0;
|
|
1270
|
+
for (const out of tokensOut) {
|
|
1271
|
+
for (const inLeg of tokensIn) {
|
|
1272
|
+
if (out.amount.token.symbol !== inLeg.amount.token.symbol) {
|
|
1273
|
+
const score = Math.max(out.amount.amountUi, inLeg.amount.amountUi);
|
|
1274
|
+
if (score > bestScore) {
|
|
1275
|
+
bestScore = score;
|
|
1276
|
+
bestPair = { initiatorOut: out, initiatorIn: inLeg };
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return bestPair;
|
|
1282
|
+
}
|
|
917
1283
|
var SwapClassifier = class {
|
|
918
1284
|
name = "swap";
|
|
919
1285
|
priority = 80;
|
|
920
1286
|
classify(context) {
|
|
921
1287
|
const { legs, tx, walletAddress } = context;
|
|
922
|
-
const
|
|
923
|
-
(leg) => leg.role === "fee" && leg.side === "debit"
|
|
924
|
-
);
|
|
925
|
-
const initiator = feeLeg?.accountId.replace("external:", "") ?? null;
|
|
1288
|
+
const initiator = tx.accountKeys?.[0] ?? null;
|
|
926
1289
|
if (!initiator) {
|
|
927
1290
|
return null;
|
|
928
1291
|
}
|
|
@@ -936,11 +1299,11 @@ var SwapClassifier = class {
|
|
|
936
1299
|
if (initiatorTokensOut.length === 0 || initiatorTokensIn.length === 0) {
|
|
937
1300
|
return null;
|
|
938
1301
|
}
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
if (initiatorOut.amount.token.symbol === initiatorIn.amount.token.symbol) {
|
|
1302
|
+
const swapPair = findSwapPair(initiatorTokensOut, initiatorTokensIn);
|
|
1303
|
+
if (!swapPair) {
|
|
942
1304
|
return null;
|
|
943
1305
|
}
|
|
1306
|
+
const { initiatorOut, initiatorIn } = swapPair;
|
|
944
1307
|
let tokenOut = initiatorOut;
|
|
945
1308
|
let tokenIn = initiatorIn;
|
|
946
1309
|
let perspectiveWallet = initiator;
|
|
@@ -1334,14 +1697,14 @@ function classifyTransaction(legs, tx, walletAddress) {
|
|
|
1334
1697
|
}
|
|
1335
1698
|
|
|
1336
1699
|
// ../domain/src/tx/spam-filter.ts
|
|
1337
|
-
var
|
|
1700
|
+
var DEFAULT_CONFIG2 = {
|
|
1338
1701
|
minSolAmount: 1e-3,
|
|
1339
1702
|
minTokenAmountUsd: 0.01,
|
|
1340
1703
|
minConfidence: 0.5,
|
|
1341
1704
|
allowFailed: false
|
|
1342
1705
|
};
|
|
1343
1706
|
function isSpamTransaction(tx, classification, config = {}) {
|
|
1344
|
-
const cfg = { ...
|
|
1707
|
+
const cfg = { ...DEFAULT_CONFIG2, ...config };
|
|
1345
1708
|
if (!cfg.allowFailed && tx.err) {
|
|
1346
1709
|
return true;
|
|
1347
1710
|
}
|