tx-indexer 0.5.1 → 0.5.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/README.md +5 -5
- package/dist/{client-iLW2_DnL.d.ts → client-xmDVjOy4.d.ts} +38 -10
- package/dist/client.d.ts +2 -2
- package/dist/client.js +947 -134
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +109 -5
- package/dist/index.js +969 -137
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/package.json +1 -1
- package/dist/{classification.types-Cn9IGtEC.d.ts → classification.types-h046WjuF.d.ts} +7 -7
package/dist/client.js
CHANGED
|
@@ -12,12 +12,40 @@ function parseSignature(sig) {
|
|
|
12
12
|
|
|
13
13
|
// ../domain/src/money/token-registry.ts
|
|
14
14
|
var KNOWN_TOKENS = {
|
|
15
|
+
// Native
|
|
15
16
|
SOL: "So11111111111111111111111111111111111111112",
|
|
17
|
+
// Stablecoins
|
|
16
18
|
USDC: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
19
|
+
USDT: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
20
|
+
PYUSD: "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo",
|
|
21
|
+
USDG: "2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH",
|
|
17
22
|
USDC_BRIDGED: "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM",
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
DAI: "EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCCi3Z4dPuFhh",
|
|
24
|
+
// Major tokens
|
|
25
|
+
JUP: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN",
|
|
26
|
+
JTO: "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL",
|
|
27
|
+
PYTH: "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3",
|
|
28
|
+
BONK: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
|
|
29
|
+
WIF: "EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm",
|
|
30
|
+
RENDER: "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof",
|
|
31
|
+
HNT: "hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux",
|
|
32
|
+
RAY: "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R",
|
|
33
|
+
ORCA: "orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE",
|
|
34
|
+
MNGO: "MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac",
|
|
35
|
+
MSOL: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
|
|
36
|
+
JITOSOL: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn",
|
|
37
|
+
BSOL: "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1",
|
|
38
|
+
// Memecoins
|
|
39
|
+
POPCAT: "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr",
|
|
40
|
+
MEW: "MEW1gQWJ3nEXg2qgERiKu7FAFj79PHvQVREQUzScPP5",
|
|
41
|
+
PNUT: "2qEHjDLDLbuBgRYvsxhc5D6uDWAivNFZGan56P1tpump",
|
|
42
|
+
FARTCOIN: "9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump",
|
|
43
|
+
AI16Z: "HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC",
|
|
44
|
+
// Wrapped tokens
|
|
45
|
+
WBTC: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh",
|
|
46
|
+
WETH: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs"};
|
|
20
47
|
var TOKEN_INFO = {
|
|
48
|
+
// Native SOL
|
|
21
49
|
[KNOWN_TOKENS.SOL]: {
|
|
22
50
|
mint: KNOWN_TOKENS.SOL,
|
|
23
51
|
symbol: "SOL",
|
|
@@ -25,6 +53,7 @@ var TOKEN_INFO = {
|
|
|
25
53
|
decimals: 9,
|
|
26
54
|
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png"
|
|
27
55
|
},
|
|
56
|
+
// Stablecoins
|
|
28
57
|
[KNOWN_TOKENS.USDC]: {
|
|
29
58
|
mint: KNOWN_TOKENS.USDC,
|
|
30
59
|
symbol: "USDC",
|
|
@@ -32,22 +61,245 @@ var TOKEN_INFO = {
|
|
|
32
61
|
decimals: 6,
|
|
33
62
|
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v/logo.png"
|
|
34
63
|
},
|
|
35
|
-
[KNOWN_TOKENS.
|
|
36
|
-
mint: KNOWN_TOKENS.
|
|
37
|
-
symbol: "
|
|
38
|
-
name: "
|
|
39
|
-
decimals: 6
|
|
64
|
+
[KNOWN_TOKENS.USDT]: {
|
|
65
|
+
mint: KNOWN_TOKENS.USDT,
|
|
66
|
+
symbol: "USDT",
|
|
67
|
+
name: "Tether USD",
|
|
68
|
+
decimals: 6,
|
|
69
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB/logo.svg"
|
|
70
|
+
},
|
|
71
|
+
[KNOWN_TOKENS.PYUSD]: {
|
|
72
|
+
mint: KNOWN_TOKENS.PYUSD,
|
|
73
|
+
symbol: "PYUSD",
|
|
74
|
+
name: "PayPal USD",
|
|
75
|
+
decimals: 6,
|
|
76
|
+
logoURI: "https://img.fotofolio.xyz/?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolana-labs%2Ftoken-list%2Fmain%2Fassets%2Fmainnet%2F2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo%2Flogo.png"
|
|
40
77
|
},
|
|
41
78
|
[KNOWN_TOKENS.USDG]: {
|
|
42
79
|
mint: KNOWN_TOKENS.USDG,
|
|
43
80
|
symbol: "USDG",
|
|
44
81
|
name: "USD Glitter",
|
|
45
82
|
decimals: 6
|
|
83
|
+
},
|
|
84
|
+
[KNOWN_TOKENS.USDC_BRIDGED]: {
|
|
85
|
+
mint: KNOWN_TOKENS.USDC_BRIDGED,
|
|
86
|
+
symbol: "USDCet",
|
|
87
|
+
name: "USDC (Wormhole)",
|
|
88
|
+
decimals: 6
|
|
89
|
+
},
|
|
90
|
+
[KNOWN_TOKENS.DAI]: {
|
|
91
|
+
mint: KNOWN_TOKENS.DAI,
|
|
92
|
+
symbol: "DAI",
|
|
93
|
+
name: "DAI (Wormhole)",
|
|
94
|
+
decimals: 8
|
|
95
|
+
},
|
|
96
|
+
// Major tokens
|
|
97
|
+
[KNOWN_TOKENS.JUP]: {
|
|
98
|
+
mint: KNOWN_TOKENS.JUP,
|
|
99
|
+
symbol: "JUP",
|
|
100
|
+
name: "Jupiter",
|
|
101
|
+
decimals: 6,
|
|
102
|
+
logoURI: "https://static.jup.ag/jup/icon.png"
|
|
103
|
+
},
|
|
104
|
+
[KNOWN_TOKENS.JTO]: {
|
|
105
|
+
mint: KNOWN_TOKENS.JTO,
|
|
106
|
+
symbol: "JTO",
|
|
107
|
+
name: "Jito",
|
|
108
|
+
decimals: 9,
|
|
109
|
+
logoURI: "https://metadata.jito.network/token/jto/image"
|
|
110
|
+
},
|
|
111
|
+
[KNOWN_TOKENS.PYTH]: {
|
|
112
|
+
mint: KNOWN_TOKENS.PYTH,
|
|
113
|
+
symbol: "PYTH",
|
|
114
|
+
name: "Pyth Network",
|
|
115
|
+
decimals: 6,
|
|
116
|
+
logoURI: "https://pyth.network/token.svg"
|
|
117
|
+
},
|
|
118
|
+
[KNOWN_TOKENS.BONK]: {
|
|
119
|
+
mint: KNOWN_TOKENS.BONK,
|
|
120
|
+
symbol: "BONK",
|
|
121
|
+
name: "Bonk",
|
|
122
|
+
decimals: 5,
|
|
123
|
+
logoURI: "https://arweave.net/hQiPZOsRZXGXBJd_82PhVdlM_hACsT_q6wqwf5cSY7I"
|
|
124
|
+
},
|
|
125
|
+
[KNOWN_TOKENS.WIF]: {
|
|
126
|
+
mint: KNOWN_TOKENS.WIF,
|
|
127
|
+
symbol: "WIF",
|
|
128
|
+
name: "dogwifhat",
|
|
129
|
+
decimals: 6,
|
|
130
|
+
logoURI: "https://bafkreibk3covs5ltyqxa272uodhber6kcclnlgrbwjee4kyqhstwmjqpfa.ipfs.nftstorage.link/"
|
|
131
|
+
},
|
|
132
|
+
[KNOWN_TOKENS.RENDER]: {
|
|
133
|
+
mint: KNOWN_TOKENS.RENDER,
|
|
134
|
+
symbol: "RENDER",
|
|
135
|
+
name: "Render Token",
|
|
136
|
+
decimals: 8,
|
|
137
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof/logo.png"
|
|
138
|
+
},
|
|
139
|
+
[KNOWN_TOKENS.HNT]: {
|
|
140
|
+
mint: KNOWN_TOKENS.HNT,
|
|
141
|
+
symbol: "HNT",
|
|
142
|
+
name: "Helium",
|
|
143
|
+
decimals: 8,
|
|
144
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux/logo.png"
|
|
145
|
+
},
|
|
146
|
+
[KNOWN_TOKENS.RAY]: {
|
|
147
|
+
mint: KNOWN_TOKENS.RAY,
|
|
148
|
+
symbol: "RAY",
|
|
149
|
+
name: "Raydium",
|
|
150
|
+
decimals: 6,
|
|
151
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R/logo.png"
|
|
152
|
+
},
|
|
153
|
+
[KNOWN_TOKENS.ORCA]: {
|
|
154
|
+
mint: KNOWN_TOKENS.ORCA,
|
|
155
|
+
symbol: "ORCA",
|
|
156
|
+
name: "Orca",
|
|
157
|
+
decimals: 6,
|
|
158
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE/logo.png"
|
|
159
|
+
},
|
|
160
|
+
[KNOWN_TOKENS.MNGO]: {
|
|
161
|
+
mint: KNOWN_TOKENS.MNGO,
|
|
162
|
+
symbol: "MNGO",
|
|
163
|
+
name: "Mango",
|
|
164
|
+
decimals: 6,
|
|
165
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac/logo.png"
|
|
166
|
+
},
|
|
167
|
+
// Liquid staking tokens
|
|
168
|
+
[KNOWN_TOKENS.MSOL]: {
|
|
169
|
+
mint: KNOWN_TOKENS.MSOL,
|
|
170
|
+
symbol: "mSOL",
|
|
171
|
+
name: "Marinade Staked SOL",
|
|
172
|
+
decimals: 9,
|
|
173
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So/logo.png"
|
|
174
|
+
},
|
|
175
|
+
[KNOWN_TOKENS.JITOSOL]: {
|
|
176
|
+
mint: KNOWN_TOKENS.JITOSOL,
|
|
177
|
+
symbol: "JitoSOL",
|
|
178
|
+
name: "Jito Staked SOL",
|
|
179
|
+
decimals: 9,
|
|
180
|
+
logoURI: "https://storage.googleapis.com/token-metadata/JitoSOL-256.png"
|
|
181
|
+
},
|
|
182
|
+
[KNOWN_TOKENS.BSOL]: {
|
|
183
|
+
mint: KNOWN_TOKENS.BSOL,
|
|
184
|
+
symbol: "bSOL",
|
|
185
|
+
name: "BlazeStake Staked SOL",
|
|
186
|
+
decimals: 9,
|
|
187
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1/logo.png"
|
|
188
|
+
},
|
|
189
|
+
// Memecoins
|
|
190
|
+
[KNOWN_TOKENS.POPCAT]: {
|
|
191
|
+
mint: KNOWN_TOKENS.POPCAT,
|
|
192
|
+
symbol: "POPCAT",
|
|
193
|
+
name: "Popcat",
|
|
194
|
+
decimals: 9,
|
|
195
|
+
logoURI: "https://bafkreidvkvuzyslw5jh5z242lgzwzhbi2kxxnpkm73fkuqzasyr34jj2o4.ipfs.nftstorage.link/"
|
|
196
|
+
},
|
|
197
|
+
[KNOWN_TOKENS.MEW]: {
|
|
198
|
+
mint: KNOWN_TOKENS.MEW,
|
|
199
|
+
symbol: "MEW",
|
|
200
|
+
name: "cat in a dogs world",
|
|
201
|
+
decimals: 5,
|
|
202
|
+
logoURI: "https://bafkreidlwyr565dxtao2ipsze6bmzpszqzybz7sqi2zaet5fs7k53henju.ipfs.nftstorage.link/"
|
|
203
|
+
},
|
|
204
|
+
[KNOWN_TOKENS.PNUT]: {
|
|
205
|
+
mint: KNOWN_TOKENS.PNUT,
|
|
206
|
+
symbol: "Peanut",
|
|
207
|
+
name: "Peanut the Squirrel",
|
|
208
|
+
decimals: 6,
|
|
209
|
+
logoURI: "https://ipfs.io/ipfs/QmNS3Hdb6pMheFzRdwXr3PPCrXcBohzhLrKHqEUV1n3HnJ"
|
|
210
|
+
},
|
|
211
|
+
[KNOWN_TOKENS.FARTCOIN]: {
|
|
212
|
+
mint: KNOWN_TOKENS.FARTCOIN,
|
|
213
|
+
symbol: "FARTCOIN",
|
|
214
|
+
name: "Fartcoin",
|
|
215
|
+
decimals: 6,
|
|
216
|
+
logoURI: "https://ipfs.io/ipfs/QmQHY6t8TxucH3F9LGPBBqqRLbyWx7NxWvrnoZKcq9ErrR"
|
|
217
|
+
},
|
|
218
|
+
[KNOWN_TOKENS.AI16Z]: {
|
|
219
|
+
mint: KNOWN_TOKENS.AI16Z,
|
|
220
|
+
symbol: "ai16z",
|
|
221
|
+
name: "ai16z",
|
|
222
|
+
decimals: 9,
|
|
223
|
+
logoURI: "https://ipfs.io/ipfs/QmRbm1mprqHmJ7PvCTrSNydkquLi5r41wq8kWbHvoRm3FX"
|
|
224
|
+
},
|
|
225
|
+
// Wrapped tokens
|
|
226
|
+
[KNOWN_TOKENS.WBTC]: {
|
|
227
|
+
mint: KNOWN_TOKENS.WBTC,
|
|
228
|
+
symbol: "WBTC",
|
|
229
|
+
name: "Wrapped BTC (Wormhole)",
|
|
230
|
+
decimals: 8,
|
|
231
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh/logo.png"
|
|
232
|
+
},
|
|
233
|
+
[KNOWN_TOKENS.WETH]: {
|
|
234
|
+
mint: KNOWN_TOKENS.WETH,
|
|
235
|
+
symbol: "WETH",
|
|
236
|
+
name: "Wrapped ETH (Wormhole)",
|
|
237
|
+
decimals: 8,
|
|
238
|
+
logoURI: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/logo.png"
|
|
46
239
|
}
|
|
47
240
|
};
|
|
48
241
|
function getTokenInfo(mint) {
|
|
49
242
|
return TOKEN_INFO[mint];
|
|
50
243
|
}
|
|
244
|
+
function createUnknownToken(mint, decimals) {
|
|
245
|
+
return {
|
|
246
|
+
mint,
|
|
247
|
+
symbol: mint.slice(0, 8),
|
|
248
|
+
name: `Unknown Token (${mint.slice(0, 8)}...)`,
|
|
249
|
+
decimals
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ../solana/src/constants/program-ids.ts
|
|
254
|
+
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
255
|
+
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
256
|
+
var STAKE_PROGRAM_ID = "Stake11111111111111111111111111111111111111";
|
|
257
|
+
var STAKE_POOL_PROGRAM_ID = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy";
|
|
258
|
+
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
259
|
+
var TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
260
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
261
|
+
var SPL_MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
262
|
+
var MEMO_V1_PROGRAM_ID = "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo";
|
|
263
|
+
var JUPITER_V6_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
|
|
264
|
+
var JUPITER_V4_PROGRAM_ID = "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB";
|
|
265
|
+
var JUPITER_ORDER_ENGINE_PROGRAM_ID = "61DFfeTKM7trxYcPQCM78bJ794ddZprZpAwAnLiwTpYH";
|
|
266
|
+
var RAYDIUM_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
|
267
|
+
var RAYDIUM_CLMM_PROGRAM_ID = "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK";
|
|
268
|
+
var RAYDIUM_CPMM_PROGRAM_ID = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C";
|
|
269
|
+
var RAYDIUM_STABLE_PROGRAM_ID = "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h";
|
|
270
|
+
var ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
|
|
271
|
+
var ORCA_TOKEN_SWAP_V1_PROGRAM_ID = "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP";
|
|
272
|
+
var OPENBOOK_V2_PROGRAM_ID = "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb";
|
|
273
|
+
var PHOENIX_PROGRAM_ID = "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY";
|
|
274
|
+
var SABER_STABLE_SWAP_PROGRAM_ID = "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ";
|
|
275
|
+
var MERCURIAL_STABLE_SWAP_PROGRAM_ID = "MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky";
|
|
276
|
+
var METEORA_DLMM_PROGRAM_ID = "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo";
|
|
277
|
+
var METEORA_POOLS_PROGRAM_ID = "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB";
|
|
278
|
+
var PUMPFUN_AMM_PROGRAM_ID = "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA";
|
|
279
|
+
var PUMPFUN_BONDING_CURVE_PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
|
|
280
|
+
var LIFINITY_V2_PROGRAM_ID = "2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c";
|
|
281
|
+
var METAPLEX_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
282
|
+
var CANDY_MACHINE_V3_PROGRAM_ID = "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR";
|
|
283
|
+
var CANDY_GUARD_PROGRAM_ID = "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g";
|
|
284
|
+
var BUBBLEGUM_PROGRAM_ID = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
|
285
|
+
var MAGIC_EDEN_CANDY_MACHINE_ID = "CMZYPASGWeTz7RNGHaRJfCq2XQ5pYK6nDvVQxzkH51zb";
|
|
286
|
+
var WORMHOLE_PROGRAM_ID = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
|
|
287
|
+
var WORMHOLE_TOKEN_BRIDGE_ID = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
|
|
288
|
+
var DEGODS_BRIDGE_PROGRAM_ID = "35iLrpYNNR9ygHLcvE1xKFHbHq6paHthrF6wSovdWgGu";
|
|
289
|
+
var DEBRIDGE_PROGRAM_ID = "DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh";
|
|
290
|
+
var ALLBRIDGE_PROGRAM_ID = "BrdgN2RPzEMWF96ZbnnJaUtQDQx7VRXYaHHbYCBvceWB";
|
|
291
|
+
var PAYAI_FACILITATOR = "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4";
|
|
292
|
+
var KNOWN_FACILITATORS = [PAYAI_FACILITATOR];
|
|
293
|
+
function detectFacilitator(accountKeys) {
|
|
294
|
+
for (const facilitator of KNOWN_FACILITATORS) {
|
|
295
|
+
if (accountKeys.includes(facilitator)) {
|
|
296
|
+
if (facilitator === PAYAI_FACILITATOR) {
|
|
297
|
+
return "payai";
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
51
303
|
|
|
52
304
|
// ../solana/src/fetcher/balances.ts
|
|
53
305
|
async function fetchWalletBalance(rpc, walletAddress, tokenMints) {
|
|
@@ -66,12 +318,17 @@ async function fetchWalletBalance(rpc, walletAddress, tokenMints) {
|
|
|
66
318
|
}
|
|
67
319
|
async function fetchTokenAccounts(rpc, walletAddress) {
|
|
68
320
|
const accountsMap = /* @__PURE__ */ new Map();
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
321
|
+
const tokenPrograms = [TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID];
|
|
322
|
+
const responses = await Promise.all(
|
|
323
|
+
tokenPrograms.map(
|
|
324
|
+
(programId) => rpc.getTokenAccountsByOwner(
|
|
325
|
+
walletAddress,
|
|
326
|
+
{ programId: address(programId) },
|
|
327
|
+
{ encoding: "jsonParsed" }
|
|
328
|
+
).send().catch(() => ({ value: [] }))
|
|
329
|
+
)
|
|
330
|
+
);
|
|
331
|
+
for (const response of responses) {
|
|
75
332
|
for (const account of response.value) {
|
|
76
333
|
const parsedInfo = account.account.data.parsed.info;
|
|
77
334
|
const mint = parsedInfo.mint;
|
|
@@ -88,8 +345,6 @@ async function fetchTokenAccounts(rpc, walletAddress) {
|
|
|
88
345
|
symbol
|
|
89
346
|
});
|
|
90
347
|
}
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error("Error fetching token accounts:", error);
|
|
93
348
|
}
|
|
94
349
|
return accountsMap;
|
|
95
350
|
}
|
|
@@ -133,44 +388,6 @@ function extractProgramIds(transaction) {
|
|
|
133
388
|
return Array.from(programIds);
|
|
134
389
|
}
|
|
135
390
|
|
|
136
|
-
// ../solana/src/constants/program-ids.ts
|
|
137
|
-
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
138
|
-
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
139
|
-
var STAKE_PROGRAM_ID = "Stake11111111111111111111111111111111111111";
|
|
140
|
-
var STAKE_POOL_PROGRAM_ID = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy";
|
|
141
|
-
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
142
|
-
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
143
|
-
var SPL_MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
144
|
-
var MEMO_V1_PROGRAM_ID = "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo";
|
|
145
|
-
var JUPITER_V6_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
|
|
146
|
-
var JUPITER_V4_PROGRAM_ID = "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB";
|
|
147
|
-
var RAYDIUM_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
|
148
|
-
var ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
|
|
149
|
-
var METAPLEX_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
150
|
-
var CANDY_MACHINE_V3_PROGRAM_ID = "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR";
|
|
151
|
-
var CANDY_GUARD_PROGRAM_ID = "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g";
|
|
152
|
-
var BUBBLEGUM_PROGRAM_ID = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
|
153
|
-
var MAGIC_EDEN_CANDY_MACHINE_ID = "CMZYPASGWeTz7RNGHaRJfCq2XQ5pYK6nDvVQxzkH51zb";
|
|
154
|
-
var WORMHOLE_PROGRAM_ID = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
|
|
155
|
-
var WORMHOLE_TOKEN_BRIDGE_ID = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
|
|
156
|
-
var DEGODS_BRIDGE_PROGRAM_ID = "35iLrpYNNR9ygHLcvE1xKFHbHq6paHthrF6wSovdWgGu";
|
|
157
|
-
var DEBRIDGE_PROGRAM_ID = "DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh";
|
|
158
|
-
var ALLBRIDGE_PROGRAM_ID = "BrdgN2RPzEMWF96ZbnnJaUtQDQx7VRXYaHHbYCBvceWB";
|
|
159
|
-
var PAYAI_FACILITATOR = "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4";
|
|
160
|
-
var KNOWN_FACILITATORS = [
|
|
161
|
-
PAYAI_FACILITATOR
|
|
162
|
-
];
|
|
163
|
-
function detectFacilitator(accountKeys) {
|
|
164
|
-
for (const facilitator of KNOWN_FACILITATORS) {
|
|
165
|
-
if (accountKeys.includes(facilitator)) {
|
|
166
|
-
if (facilitator === PAYAI_FACILITATOR) {
|
|
167
|
-
return "payai";
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
391
|
// ../../node_modules/.bun/base-x@5.0.1/node_modules/base-x/src/esm/index.js
|
|
175
392
|
function base(ALPHABET2) {
|
|
176
393
|
if (ALPHABET2.length >= 255) {
|
|
@@ -380,6 +597,189 @@ function isSolanaPayTransaction(programIds, memo) {
|
|
|
380
597
|
return hasMemoProgram && memo !== null && memo !== void 0;
|
|
381
598
|
}
|
|
382
599
|
|
|
600
|
+
// ../solana/src/rpc/retry.ts
|
|
601
|
+
var DEFAULT_CONFIG = {
|
|
602
|
+
maxAttempts: 3,
|
|
603
|
+
baseDelayMs: 1e3,
|
|
604
|
+
maxDelayMs: 1e4
|
|
605
|
+
};
|
|
606
|
+
function isRetryableError(error) {
|
|
607
|
+
if (error instanceof Error) {
|
|
608
|
+
const message = error.message.toLowerCase();
|
|
609
|
+
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");
|
|
610
|
+
}
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
function calculateDelay(attempt, baseDelayMs, maxDelayMs) {
|
|
614
|
+
const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
615
|
+
const jitter = Math.random() * 0.3 * exponentialDelay;
|
|
616
|
+
return Math.min(exponentialDelay + jitter, maxDelayMs);
|
|
617
|
+
}
|
|
618
|
+
function sleep(ms) {
|
|
619
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
620
|
+
}
|
|
621
|
+
async function withRetry(fn, config = {}) {
|
|
622
|
+
const { maxAttempts, baseDelayMs, maxDelayMs } = {
|
|
623
|
+
...DEFAULT_CONFIG,
|
|
624
|
+
...config
|
|
625
|
+
};
|
|
626
|
+
let lastError;
|
|
627
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
628
|
+
try {
|
|
629
|
+
return await fn();
|
|
630
|
+
} catch (error) {
|
|
631
|
+
lastError = error;
|
|
632
|
+
const isLastAttempt = attempt === maxAttempts;
|
|
633
|
+
const shouldRetry = !isLastAttempt && isRetryableError(error);
|
|
634
|
+
if (!shouldRetry) {
|
|
635
|
+
throw error;
|
|
636
|
+
}
|
|
637
|
+
const delay = calculateDelay(attempt, baseDelayMs, maxDelayMs);
|
|
638
|
+
await sleep(delay);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
throw lastError;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// ../../node_modules/.bun/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
645
|
+
var Node = class {
|
|
646
|
+
value;
|
|
647
|
+
next;
|
|
648
|
+
constructor(value) {
|
|
649
|
+
this.value = value;
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
var Queue = class {
|
|
653
|
+
#head;
|
|
654
|
+
#tail;
|
|
655
|
+
#size;
|
|
656
|
+
constructor() {
|
|
657
|
+
this.clear();
|
|
658
|
+
}
|
|
659
|
+
enqueue(value) {
|
|
660
|
+
const node = new Node(value);
|
|
661
|
+
if (this.#head) {
|
|
662
|
+
this.#tail.next = node;
|
|
663
|
+
this.#tail = node;
|
|
664
|
+
} else {
|
|
665
|
+
this.#head = node;
|
|
666
|
+
this.#tail = node;
|
|
667
|
+
}
|
|
668
|
+
this.#size++;
|
|
669
|
+
}
|
|
670
|
+
dequeue() {
|
|
671
|
+
const current = this.#head;
|
|
672
|
+
if (!current) {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
this.#head = this.#head.next;
|
|
676
|
+
this.#size--;
|
|
677
|
+
if (!this.#head) {
|
|
678
|
+
this.#tail = void 0;
|
|
679
|
+
}
|
|
680
|
+
return current.value;
|
|
681
|
+
}
|
|
682
|
+
peek() {
|
|
683
|
+
if (!this.#head) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
return this.#head.value;
|
|
687
|
+
}
|
|
688
|
+
clear() {
|
|
689
|
+
this.#head = void 0;
|
|
690
|
+
this.#tail = void 0;
|
|
691
|
+
this.#size = 0;
|
|
692
|
+
}
|
|
693
|
+
get size() {
|
|
694
|
+
return this.#size;
|
|
695
|
+
}
|
|
696
|
+
*[Symbol.iterator]() {
|
|
697
|
+
let current = this.#head;
|
|
698
|
+
while (current) {
|
|
699
|
+
yield current.value;
|
|
700
|
+
current = current.next;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
*drain() {
|
|
704
|
+
while (this.#head) {
|
|
705
|
+
yield this.dequeue();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// ../../node_modules/.bun/p-limit@6.2.0/node_modules/p-limit/index.js
|
|
711
|
+
function pLimit(concurrency) {
|
|
712
|
+
validateConcurrency(concurrency);
|
|
713
|
+
const queue = new Queue();
|
|
714
|
+
let activeCount = 0;
|
|
715
|
+
const resumeNext = () => {
|
|
716
|
+
if (activeCount < concurrency && queue.size > 0) {
|
|
717
|
+
queue.dequeue()();
|
|
718
|
+
activeCount++;
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
const next = () => {
|
|
722
|
+
activeCount--;
|
|
723
|
+
resumeNext();
|
|
724
|
+
};
|
|
725
|
+
const run = async (function_, resolve, arguments_) => {
|
|
726
|
+
const result = (async () => function_(...arguments_))();
|
|
727
|
+
resolve(result);
|
|
728
|
+
try {
|
|
729
|
+
await result;
|
|
730
|
+
} catch {
|
|
731
|
+
}
|
|
732
|
+
next();
|
|
733
|
+
};
|
|
734
|
+
const enqueue = (function_, resolve, arguments_) => {
|
|
735
|
+
new Promise((internalResolve) => {
|
|
736
|
+
queue.enqueue(internalResolve);
|
|
737
|
+
}).then(
|
|
738
|
+
run.bind(void 0, function_, resolve, arguments_)
|
|
739
|
+
);
|
|
740
|
+
(async () => {
|
|
741
|
+
await Promise.resolve();
|
|
742
|
+
if (activeCount < concurrency) {
|
|
743
|
+
resumeNext();
|
|
744
|
+
}
|
|
745
|
+
})();
|
|
746
|
+
};
|
|
747
|
+
const generator = (function_, ...arguments_) => new Promise((resolve) => {
|
|
748
|
+
enqueue(function_, resolve, arguments_);
|
|
749
|
+
});
|
|
750
|
+
Object.defineProperties(generator, {
|
|
751
|
+
activeCount: {
|
|
752
|
+
get: () => activeCount
|
|
753
|
+
},
|
|
754
|
+
pendingCount: {
|
|
755
|
+
get: () => queue.size
|
|
756
|
+
},
|
|
757
|
+
clearQueue: {
|
|
758
|
+
value() {
|
|
759
|
+
queue.clear();
|
|
760
|
+
}
|
|
761
|
+
},
|
|
762
|
+
concurrency: {
|
|
763
|
+
get: () => concurrency,
|
|
764
|
+
set(newConcurrency) {
|
|
765
|
+
validateConcurrency(newConcurrency);
|
|
766
|
+
concurrency = newConcurrency;
|
|
767
|
+
queueMicrotask(() => {
|
|
768
|
+
while (activeCount < concurrency && queue.size > 0) {
|
|
769
|
+
resumeNext();
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
return generator;
|
|
776
|
+
}
|
|
777
|
+
function validateConcurrency(concurrency) {
|
|
778
|
+
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
|
|
779
|
+
throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
383
783
|
// ../solana/src/fetcher/transactions.ts
|
|
384
784
|
async function fetchWalletSignatures(rpc, walletAddress, config = {}) {
|
|
385
785
|
const { limit = 100, before, until } = config;
|
|
@@ -398,12 +798,16 @@ async function fetchWalletSignatures(rpc, walletAddress, config = {}) {
|
|
|
398
798
|
memo: sig.memo || null
|
|
399
799
|
}));
|
|
400
800
|
}
|
|
401
|
-
async function fetchTransaction(rpc, signature2,
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
801
|
+
async function fetchTransaction(rpc, signature2, options = {}) {
|
|
802
|
+
const { commitment = "confirmed", retry } = options;
|
|
803
|
+
const response = await withRetry(
|
|
804
|
+
() => rpc.getTransaction(signature2, {
|
|
805
|
+
commitment,
|
|
806
|
+
maxSupportedTransactionVersion: 0,
|
|
807
|
+
encoding: "json"
|
|
808
|
+
}).send(),
|
|
809
|
+
retry
|
|
810
|
+
);
|
|
407
811
|
if (!response) {
|
|
408
812
|
return null;
|
|
409
813
|
}
|
|
@@ -450,10 +854,29 @@ async function fetchTransaction(rpc, signature2, commitment = "confirmed") {
|
|
|
450
854
|
memo
|
|
451
855
|
};
|
|
452
856
|
}
|
|
453
|
-
async function fetchTransactionsBatch(rpc, signatures,
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
857
|
+
async function fetchTransactionsBatch(rpc, signatures, options = {}) {
|
|
858
|
+
const {
|
|
859
|
+
commitment = "confirmed",
|
|
860
|
+
concurrency = 10,
|
|
861
|
+
retry,
|
|
862
|
+
onFetchError
|
|
863
|
+
} = options;
|
|
864
|
+
if (signatures.length === 0) {
|
|
865
|
+
return [];
|
|
866
|
+
}
|
|
867
|
+
const limit = pLimit(concurrency);
|
|
868
|
+
const safeFetch = async (sig) => {
|
|
869
|
+
try {
|
|
870
|
+
return await fetchTransaction(rpc, sig, { commitment, retry });
|
|
871
|
+
} catch (error) {
|
|
872
|
+
onFetchError?.(
|
|
873
|
+
sig,
|
|
874
|
+
error instanceof Error ? error : new Error(String(error))
|
|
875
|
+
);
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
const promises = signatures.map((sig) => limit(() => safeFetch(sig)));
|
|
457
880
|
const results = await Promise.all(promises);
|
|
458
881
|
return results.filter((tx) => tx !== null);
|
|
459
882
|
}
|
|
@@ -598,7 +1021,7 @@ function transactionToLegs(tx) {
|
|
|
598
1021
|
amountRaw: change.change.toString().replace("-", ""),
|
|
599
1022
|
amountUi: Math.abs(change.changeUi)
|
|
600
1023
|
},
|
|
601
|
-
role: determineSolRole(change, tx
|
|
1024
|
+
role: determineSolRole(change, tx)
|
|
602
1025
|
});
|
|
603
1026
|
}
|
|
604
1027
|
const networkFee = totalSolDebits - totalSolCredits;
|
|
@@ -655,13 +1078,8 @@ function transactionToLegs(tx) {
|
|
|
655
1078
|
}
|
|
656
1079
|
return legs;
|
|
657
1080
|
}
|
|
658
|
-
function determineSolRole(change, tx,
|
|
659
|
-
const isFeePayer = feePayer ? change.address.toLowerCase() === feePayer : false;
|
|
1081
|
+
function determineSolRole(change, tx, _feePayer) {
|
|
660
1082
|
const isPositive = change.change > 0n;
|
|
661
|
-
const amountSol = Math.abs(change.changeUi);
|
|
662
|
-
if (isFeePayer && !isPositive && amountSol < 0.01) {
|
|
663
|
-
return "fee";
|
|
664
|
-
}
|
|
665
1083
|
if (isPositive) {
|
|
666
1084
|
if (tx.protocol?.id === "stake") {
|
|
667
1085
|
return "reward";
|
|
@@ -721,6 +1139,7 @@ var TransferClassifier = class {
|
|
|
721
1139
|
|
|
722
1140
|
// ../classification/src/protocols/detector.ts
|
|
723
1141
|
var KNOWN_PROGRAMS = {
|
|
1142
|
+
// Jupiter aggregator
|
|
724
1143
|
[JUPITER_V6_PROGRAM_ID]: {
|
|
725
1144
|
id: "jupiter",
|
|
726
1145
|
name: "Jupiter"
|
|
@@ -729,10 +1148,19 @@ var KNOWN_PROGRAMS = {
|
|
|
729
1148
|
id: "jupiter-v4",
|
|
730
1149
|
name: "Jupiter V4"
|
|
731
1150
|
},
|
|
1151
|
+
[JUPITER_ORDER_ENGINE_PROGRAM_ID]: {
|
|
1152
|
+
id: "jupiter-limit-order",
|
|
1153
|
+
name: "Jupiter Limit Order"
|
|
1154
|
+
},
|
|
1155
|
+
// Core token programs
|
|
732
1156
|
[TOKEN_PROGRAM_ID]: {
|
|
733
1157
|
id: "spl-token",
|
|
734
1158
|
name: "Token Program"
|
|
735
1159
|
},
|
|
1160
|
+
[TOKEN_2022_PROGRAM_ID]: {
|
|
1161
|
+
id: "token-2022",
|
|
1162
|
+
name: "Token-2022 Program"
|
|
1163
|
+
},
|
|
736
1164
|
[SYSTEM_PROGRAM_ID]: {
|
|
737
1165
|
id: "system",
|
|
738
1166
|
name: "System Program"
|
|
@@ -745,25 +1173,86 @@ var KNOWN_PROGRAMS = {
|
|
|
745
1173
|
id: "associated-token",
|
|
746
1174
|
name: "Associated Token Program"
|
|
747
1175
|
},
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1176
|
+
// Memo programs
|
|
1177
|
+
[SPL_MEMO_PROGRAM_ID]: {
|
|
1178
|
+
id: "memo",
|
|
1179
|
+
name: "Memo Program"
|
|
751
1180
|
},
|
|
752
|
-
[
|
|
753
|
-
id: "
|
|
754
|
-
name: "
|
|
1181
|
+
[MEMO_V1_PROGRAM_ID]: {
|
|
1182
|
+
id: "memo-v1",
|
|
1183
|
+
name: "Memo Program V1"
|
|
755
1184
|
},
|
|
1185
|
+
// Raydium AMMs
|
|
756
1186
|
[RAYDIUM_PROGRAM_ID]: {
|
|
757
1187
|
id: "raydium",
|
|
758
1188
|
name: "Raydium"
|
|
759
1189
|
},
|
|
760
|
-
[
|
|
761
|
-
id: "
|
|
762
|
-
name: "
|
|
1190
|
+
[RAYDIUM_CLMM_PROGRAM_ID]: {
|
|
1191
|
+
id: "raydium-clmm",
|
|
1192
|
+
name: "Raydium CLMM"
|
|
763
1193
|
},
|
|
764
|
-
[
|
|
765
|
-
id: "
|
|
766
|
-
name: "
|
|
1194
|
+
[RAYDIUM_CPMM_PROGRAM_ID]: {
|
|
1195
|
+
id: "raydium-cpmm",
|
|
1196
|
+
name: "Raydium CPMM"
|
|
1197
|
+
},
|
|
1198
|
+
[RAYDIUM_STABLE_PROGRAM_ID]: {
|
|
1199
|
+
id: "raydium-stable",
|
|
1200
|
+
name: "Raydium Stable"
|
|
1201
|
+
},
|
|
1202
|
+
// Orca
|
|
1203
|
+
[ORCA_WHIRLPOOL_PROGRAM_ID]: {
|
|
1204
|
+
id: "orca-whirlpool",
|
|
1205
|
+
name: "Orca Whirlpool"
|
|
1206
|
+
},
|
|
1207
|
+
[ORCA_TOKEN_SWAP_V1_PROGRAM_ID]: {
|
|
1208
|
+
id: "orca-v1",
|
|
1209
|
+
name: "Orca Token Swap V1"
|
|
1210
|
+
},
|
|
1211
|
+
// CLOBs (Central Limit Order Books)
|
|
1212
|
+
[OPENBOOK_V2_PROGRAM_ID]: {
|
|
1213
|
+
id: "openbook",
|
|
1214
|
+
name: "OpenBook"
|
|
1215
|
+
},
|
|
1216
|
+
[PHOENIX_PROGRAM_ID]: {
|
|
1217
|
+
id: "phoenix",
|
|
1218
|
+
name: "Phoenix"
|
|
1219
|
+
},
|
|
1220
|
+
// Stableswap protocols
|
|
1221
|
+
[SABER_STABLE_SWAP_PROGRAM_ID]: {
|
|
1222
|
+
id: "saber",
|
|
1223
|
+
name: "Saber"
|
|
1224
|
+
},
|
|
1225
|
+
[MERCURIAL_STABLE_SWAP_PROGRAM_ID]: {
|
|
1226
|
+
id: "mercurial",
|
|
1227
|
+
name: "Mercurial"
|
|
1228
|
+
},
|
|
1229
|
+
// Meteora
|
|
1230
|
+
[METEORA_DLMM_PROGRAM_ID]: {
|
|
1231
|
+
id: "meteora-dlmm",
|
|
1232
|
+
name: "Meteora DLMM"
|
|
1233
|
+
},
|
|
1234
|
+
[METEORA_POOLS_PROGRAM_ID]: {
|
|
1235
|
+
id: "meteora-pools",
|
|
1236
|
+
name: "Meteora Pools"
|
|
1237
|
+
},
|
|
1238
|
+
// Pump.fun
|
|
1239
|
+
[PUMPFUN_AMM_PROGRAM_ID]: {
|
|
1240
|
+
id: "pumpfun",
|
|
1241
|
+
name: "Pump.fun"
|
|
1242
|
+
},
|
|
1243
|
+
[PUMPFUN_BONDING_CURVE_PROGRAM_ID]: {
|
|
1244
|
+
id: "pumpfun-bonding",
|
|
1245
|
+
name: "Pump.fun Bonding Curve"
|
|
1246
|
+
},
|
|
1247
|
+
// Lifinity
|
|
1248
|
+
[LIFINITY_V2_PROGRAM_ID]: {
|
|
1249
|
+
id: "lifinity",
|
|
1250
|
+
name: "Lifinity"
|
|
1251
|
+
},
|
|
1252
|
+
// NFT programs
|
|
1253
|
+
[METAPLEX_PROGRAM_ID]: {
|
|
1254
|
+
id: "metaplex",
|
|
1255
|
+
name: "Metaplex"
|
|
767
1256
|
},
|
|
768
1257
|
[CANDY_GUARD_PROGRAM_ID]: {
|
|
769
1258
|
id: "candy-guard",
|
|
@@ -781,6 +1270,16 @@ var KNOWN_PROGRAMS = {
|
|
|
781
1270
|
id: "magic-eden-candy-machine",
|
|
782
1271
|
name: "Nft Candy Machine Program (Magic Eden)"
|
|
783
1272
|
},
|
|
1273
|
+
// Staking programs
|
|
1274
|
+
[STAKE_PROGRAM_ID]: {
|
|
1275
|
+
id: "stake",
|
|
1276
|
+
name: "Stake Program"
|
|
1277
|
+
},
|
|
1278
|
+
[STAKE_POOL_PROGRAM_ID]: {
|
|
1279
|
+
id: "stake-pool",
|
|
1280
|
+
name: "Stake Pool Program"
|
|
1281
|
+
},
|
|
1282
|
+
// Bridge programs
|
|
784
1283
|
[WORMHOLE_PROGRAM_ID]: {
|
|
785
1284
|
id: "wormhole",
|
|
786
1285
|
name: "Wormhole"
|
|
@@ -803,27 +1302,79 @@ var KNOWN_PROGRAMS = {
|
|
|
803
1302
|
}
|
|
804
1303
|
};
|
|
805
1304
|
var PRIORITY_ORDER = [
|
|
1305
|
+
// Bridge protocols (highest priority - cross-chain operations)
|
|
806
1306
|
"wormhole",
|
|
807
1307
|
"wormhole-token-bridge",
|
|
808
1308
|
"degods-bridge",
|
|
809
1309
|
"debridge",
|
|
810
1310
|
"allbridge",
|
|
1311
|
+
// DEX aggregators (route through multiple DEXes)
|
|
811
1312
|
"jupiter",
|
|
812
1313
|
"jupiter-v4",
|
|
1314
|
+
"jupiter-limit-order",
|
|
1315
|
+
// AMMs and DEXes
|
|
813
1316
|
"raydium",
|
|
1317
|
+
"raydium-clmm",
|
|
1318
|
+
"raydium-cpmm",
|
|
1319
|
+
"raydium-stable",
|
|
814
1320
|
"orca-whirlpool",
|
|
1321
|
+
"orca-v1",
|
|
1322
|
+
"meteora-dlmm",
|
|
1323
|
+
"meteora-pools",
|
|
1324
|
+
"lifinity",
|
|
1325
|
+
"pumpfun",
|
|
1326
|
+
"pumpfun-bonding",
|
|
1327
|
+
// CLOBs
|
|
1328
|
+
"openbook",
|
|
1329
|
+
"phoenix",
|
|
1330
|
+
// Stableswap
|
|
1331
|
+
"saber",
|
|
1332
|
+
"mercurial",
|
|
1333
|
+
// NFT
|
|
815
1334
|
"metaplex",
|
|
1335
|
+
"candy-guard",
|
|
1336
|
+
"candy-machine-v3",
|
|
1337
|
+
"bubblegum",
|
|
1338
|
+
"magic-eden-candy-machine",
|
|
1339
|
+
// Staking
|
|
816
1340
|
"stake",
|
|
1341
|
+
"stake-pool",
|
|
1342
|
+
// Infrastructure (lowest priority)
|
|
1343
|
+
"memo",
|
|
1344
|
+
"memo-v1",
|
|
817
1345
|
"associated-token",
|
|
818
1346
|
"spl-token",
|
|
1347
|
+
"token-2022",
|
|
819
1348
|
"compute-budget",
|
|
820
1349
|
"system"
|
|
821
1350
|
];
|
|
822
1351
|
var DEX_PROTOCOL_IDS2 = /* @__PURE__ */ new Set([
|
|
1352
|
+
// Jupiter aggregator
|
|
823
1353
|
"jupiter",
|
|
824
1354
|
"jupiter-v4",
|
|
1355
|
+
"jupiter-limit-order",
|
|
1356
|
+
// Raydium AMMs
|
|
825
1357
|
"raydium",
|
|
826
|
-
"
|
|
1358
|
+
"raydium-clmm",
|
|
1359
|
+
"raydium-cpmm",
|
|
1360
|
+
"raydium-stable",
|
|
1361
|
+
// Orca
|
|
1362
|
+
"orca-whirlpool",
|
|
1363
|
+
"orca-v1",
|
|
1364
|
+
// CLOBs
|
|
1365
|
+
"openbook",
|
|
1366
|
+
"phoenix",
|
|
1367
|
+
// Stableswap
|
|
1368
|
+
"saber",
|
|
1369
|
+
"mercurial",
|
|
1370
|
+
// Meteora
|
|
1371
|
+
"meteora-dlmm",
|
|
1372
|
+
"meteora-pools",
|
|
1373
|
+
// Pump.fun
|
|
1374
|
+
"pumpfun",
|
|
1375
|
+
"pumpfun-bonding",
|
|
1376
|
+
// Lifinity
|
|
1377
|
+
"lifinity"
|
|
827
1378
|
]);
|
|
828
1379
|
var NFT_MINT_PROTOCOL_IDS = /* @__PURE__ */ new Set([
|
|
829
1380
|
"metaplex",
|
|
@@ -872,15 +1423,28 @@ function detectProtocol(programIds) {
|
|
|
872
1423
|
}
|
|
873
1424
|
|
|
874
1425
|
// ../classification/src/classifiers/swap-classifier.ts
|
|
1426
|
+
function findSwapPair(tokensOut, tokensIn) {
|
|
1427
|
+
let bestPair = null;
|
|
1428
|
+
let bestScore = 0;
|
|
1429
|
+
for (const out of tokensOut) {
|
|
1430
|
+
for (const inLeg of tokensIn) {
|
|
1431
|
+
if (out.amount.token.symbol !== inLeg.amount.token.symbol) {
|
|
1432
|
+
const score = Math.max(out.amount.amountUi, inLeg.amount.amountUi);
|
|
1433
|
+
if (score > bestScore) {
|
|
1434
|
+
bestScore = score;
|
|
1435
|
+
bestPair = { initiatorOut: out, initiatorIn: inLeg };
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return bestPair;
|
|
1441
|
+
}
|
|
875
1442
|
var SwapClassifier = class {
|
|
876
1443
|
name = "swap";
|
|
877
1444
|
priority = 80;
|
|
878
1445
|
classify(context) {
|
|
879
1446
|
const { legs, tx, walletAddress } = context;
|
|
880
|
-
const
|
|
881
|
-
(leg) => leg.role === "fee" && leg.side === "debit"
|
|
882
|
-
);
|
|
883
|
-
const initiator = feeLeg?.accountId.replace("external:", "") ?? null;
|
|
1447
|
+
const initiator = tx.accountKeys?.[0] ?? null;
|
|
884
1448
|
if (!initiator) {
|
|
885
1449
|
return null;
|
|
886
1450
|
}
|
|
@@ -894,11 +1458,11 @@ var SwapClassifier = class {
|
|
|
894
1458
|
if (initiatorTokensOut.length === 0 || initiatorTokensIn.length === 0) {
|
|
895
1459
|
return null;
|
|
896
1460
|
}
|
|
897
|
-
const
|
|
898
|
-
|
|
899
|
-
if (initiatorOut.amount.token.symbol === initiatorIn.amount.token.symbol) {
|
|
1461
|
+
const swapPair = findSwapPair(initiatorTokensOut, initiatorTokensIn);
|
|
1462
|
+
if (!swapPair) {
|
|
900
1463
|
return null;
|
|
901
1464
|
}
|
|
1465
|
+
const { initiatorOut, initiatorIn } = swapPair;
|
|
902
1466
|
let tokenOut = initiatorOut;
|
|
903
1467
|
let tokenIn = initiatorIn;
|
|
904
1468
|
let perspectiveWallet = initiator;
|
|
@@ -1292,14 +1856,14 @@ function classifyTransaction(legs, tx, walletAddress) {
|
|
|
1292
1856
|
}
|
|
1293
1857
|
|
|
1294
1858
|
// ../domain/src/tx/spam-filter.ts
|
|
1295
|
-
var
|
|
1859
|
+
var DEFAULT_CONFIG2 = {
|
|
1296
1860
|
minSolAmount: 1e-3,
|
|
1297
1861
|
minTokenAmountUsd: 0.01,
|
|
1298
1862
|
minConfidence: 0.5,
|
|
1299
1863
|
allowFailed: false
|
|
1300
1864
|
};
|
|
1301
1865
|
function isSpamTransaction(tx, classification, config = {}) {
|
|
1302
|
-
const cfg = { ...
|
|
1866
|
+
const cfg = { ...DEFAULT_CONFIG2, ...config };
|
|
1303
1867
|
if (!cfg.allowFailed && tx.err) {
|
|
1304
1868
|
return true;
|
|
1305
1869
|
}
|
|
@@ -1334,6 +1898,118 @@ function filterSpamTransactions(transactions, config) {
|
|
|
1334
1898
|
);
|
|
1335
1899
|
}
|
|
1336
1900
|
|
|
1901
|
+
// ../domain/src/money/token-fetcher.ts
|
|
1902
|
+
var DEFAULT_JUPITER_API_URL = "https://tokens.jup.ag/tokens?tags=verified";
|
|
1903
|
+
var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1904
|
+
function createTokenFetcher(options = {}) {
|
|
1905
|
+
const {
|
|
1906
|
+
jupiterApiUrl = DEFAULT_JUPITER_API_URL,
|
|
1907
|
+
cacheTtlMs = DEFAULT_CACHE_TTL_MS,
|
|
1908
|
+
prefetch = false
|
|
1909
|
+
} = options;
|
|
1910
|
+
const jupiterCache = /* @__PURE__ */ new Map();
|
|
1911
|
+
let lastFetchTime = 0;
|
|
1912
|
+
let fetchPromise = null;
|
|
1913
|
+
async function fetchJupiterTokens() {
|
|
1914
|
+
if (fetchPromise) {
|
|
1915
|
+
return fetchPromise;
|
|
1916
|
+
}
|
|
1917
|
+
if (Date.now() - lastFetchTime < cacheTtlMs && jupiterCache.size > 0) {
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
fetchPromise = (async () => {
|
|
1921
|
+
try {
|
|
1922
|
+
const response = await fetch(jupiterApiUrl);
|
|
1923
|
+
if (!response.ok) {
|
|
1924
|
+
console.warn(
|
|
1925
|
+
`Jupiter API returned ${response.status}: ${response.statusText}`
|
|
1926
|
+
);
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
const tokens = await response.json();
|
|
1930
|
+
jupiterCache.clear();
|
|
1931
|
+
for (const token of tokens) {
|
|
1932
|
+
jupiterCache.set(token.address, {
|
|
1933
|
+
mint: token.address,
|
|
1934
|
+
symbol: token.symbol,
|
|
1935
|
+
name: token.name,
|
|
1936
|
+
decimals: token.decimals,
|
|
1937
|
+
logoURI: token.logoURI
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
lastFetchTime = Date.now();
|
|
1941
|
+
} catch (error) {
|
|
1942
|
+
console.warn("Failed to fetch Jupiter tokens:", error);
|
|
1943
|
+
} finally {
|
|
1944
|
+
fetchPromise = null;
|
|
1945
|
+
}
|
|
1946
|
+
})();
|
|
1947
|
+
return fetchPromise;
|
|
1948
|
+
}
|
|
1949
|
+
async function getToken(mint, decimals = 9) {
|
|
1950
|
+
const staticToken = TOKEN_INFO[mint];
|
|
1951
|
+
if (staticToken) {
|
|
1952
|
+
return staticToken;
|
|
1953
|
+
}
|
|
1954
|
+
const cachedToken = jupiterCache.get(mint);
|
|
1955
|
+
if (cachedToken) {
|
|
1956
|
+
return cachedToken;
|
|
1957
|
+
}
|
|
1958
|
+
await fetchJupiterTokens();
|
|
1959
|
+
const fetchedToken = jupiterCache.get(mint);
|
|
1960
|
+
if (fetchedToken) {
|
|
1961
|
+
return fetchedToken;
|
|
1962
|
+
}
|
|
1963
|
+
return createUnknownToken(mint, decimals);
|
|
1964
|
+
}
|
|
1965
|
+
async function getTokens(mints, defaultDecimals = 9) {
|
|
1966
|
+
const result = /* @__PURE__ */ new Map();
|
|
1967
|
+
const missingMints = [];
|
|
1968
|
+
for (const mint of mints) {
|
|
1969
|
+
const staticToken = TOKEN_INFO[mint];
|
|
1970
|
+
if (staticToken) {
|
|
1971
|
+
result.set(mint, staticToken);
|
|
1972
|
+
continue;
|
|
1973
|
+
}
|
|
1974
|
+
const cachedToken = jupiterCache.get(mint);
|
|
1975
|
+
if (cachedToken) {
|
|
1976
|
+
result.set(mint, cachedToken);
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
missingMints.push(mint);
|
|
1980
|
+
}
|
|
1981
|
+
if (missingMints.length > 0) {
|
|
1982
|
+
await fetchJupiterTokens();
|
|
1983
|
+
for (const mint of missingMints) {
|
|
1984
|
+
const fetchedToken = jupiterCache.get(mint);
|
|
1985
|
+
if (fetchedToken) {
|
|
1986
|
+
result.set(mint, fetchedToken);
|
|
1987
|
+
} else {
|
|
1988
|
+
result.set(mint, createUnknownToken(mint, defaultDecimals));
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
return result;
|
|
1993
|
+
}
|
|
1994
|
+
async function refresh() {
|
|
1995
|
+
lastFetchTime = 0;
|
|
1996
|
+
await fetchJupiterTokens();
|
|
1997
|
+
}
|
|
1998
|
+
function getCacheSize() {
|
|
1999
|
+
return jupiterCache.size;
|
|
2000
|
+
}
|
|
2001
|
+
if (prefetch) {
|
|
2002
|
+
fetchJupiterTokens().catch(() => {
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
return {
|
|
2006
|
+
getToken,
|
|
2007
|
+
getTokens,
|
|
2008
|
+
refresh,
|
|
2009
|
+
getCacheSize
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1337
2013
|
// src/nft.ts
|
|
1338
2014
|
async function fetchNftMetadata(rpcUrl, mintAddress) {
|
|
1339
2015
|
const response = await fetch(rpcUrl, {
|
|
@@ -1378,6 +2054,102 @@ async function fetchNftMetadataBatch(rpcUrl, mintAddresses) {
|
|
|
1378
2054
|
|
|
1379
2055
|
// src/client.ts
|
|
1380
2056
|
var NFT_TRANSACTION_TYPES = ["nft_mint", "nft_purchase", "nft_sale"];
|
|
2057
|
+
async function enrichTokenMetadata(tokenFetcher, classified) {
|
|
2058
|
+
const mints = /* @__PURE__ */ new Set();
|
|
2059
|
+
const decimalsMap = /* @__PURE__ */ new Map();
|
|
2060
|
+
for (const leg of classified.legs) {
|
|
2061
|
+
const mint = leg.amount.token.mint;
|
|
2062
|
+
mints.add(mint);
|
|
2063
|
+
decimalsMap.set(mint, leg.amount.token.decimals);
|
|
2064
|
+
}
|
|
2065
|
+
if (classified.classification.primaryAmount?.token.mint) {
|
|
2066
|
+
const mint = classified.classification.primaryAmount.token.mint;
|
|
2067
|
+
mints.add(mint);
|
|
2068
|
+
decimalsMap.set(
|
|
2069
|
+
mint,
|
|
2070
|
+
classified.classification.primaryAmount.token.decimals
|
|
2071
|
+
);
|
|
2072
|
+
}
|
|
2073
|
+
if (classified.classification.secondaryAmount?.token.mint) {
|
|
2074
|
+
const mint = classified.classification.secondaryAmount.token.mint;
|
|
2075
|
+
mints.add(mint);
|
|
2076
|
+
decimalsMap.set(
|
|
2077
|
+
mint,
|
|
2078
|
+
classified.classification.secondaryAmount.token.decimals
|
|
2079
|
+
);
|
|
2080
|
+
}
|
|
2081
|
+
if (mints.size === 0) {
|
|
2082
|
+
return classified;
|
|
2083
|
+
}
|
|
2084
|
+
const tokenInfoMap = await tokenFetcher.getTokens(
|
|
2085
|
+
Array.from(mints),
|
|
2086
|
+
9
|
|
2087
|
+
// default decimals
|
|
2088
|
+
);
|
|
2089
|
+
function enrichAmount(amount) {
|
|
2090
|
+
if (!amount) return amount;
|
|
2091
|
+
const enrichedToken = tokenInfoMap.get(amount.token.mint);
|
|
2092
|
+
if (!enrichedToken || enrichedToken.symbol === amount.token.symbol) {
|
|
2093
|
+
return amount;
|
|
2094
|
+
}
|
|
2095
|
+
return {
|
|
2096
|
+
...amount,
|
|
2097
|
+
token: {
|
|
2098
|
+
...enrichedToken,
|
|
2099
|
+
// Keep the decimals from the original (from RPC) as they're authoritative
|
|
2100
|
+
decimals: amount.token.decimals
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
function enrichLeg(leg) {
|
|
2105
|
+
const enrichedToken = tokenInfoMap.get(leg.amount.token.mint);
|
|
2106
|
+
if (!enrichedToken || enrichedToken.symbol === leg.amount.token.symbol) {
|
|
2107
|
+
return leg;
|
|
2108
|
+
}
|
|
2109
|
+
return {
|
|
2110
|
+
...leg,
|
|
2111
|
+
amount: {
|
|
2112
|
+
...leg.amount,
|
|
2113
|
+
token: {
|
|
2114
|
+
...enrichedToken,
|
|
2115
|
+
decimals: leg.amount.token.decimals
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
const enrichedLegs = classified.legs.map(enrichLeg);
|
|
2121
|
+
const enrichedClassification = {
|
|
2122
|
+
...classified.classification,
|
|
2123
|
+
primaryAmount: enrichAmount(classified.classification.primaryAmount) ?? null,
|
|
2124
|
+
secondaryAmount: enrichAmount(classified.classification.secondaryAmount)
|
|
2125
|
+
};
|
|
2126
|
+
return {
|
|
2127
|
+
tx: classified.tx,
|
|
2128
|
+
legs: enrichedLegs,
|
|
2129
|
+
classification: enrichedClassification
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
async function enrichTokenMetadataBatch(tokenFetcher, transactions) {
|
|
2133
|
+
const mints = /* @__PURE__ */ new Set();
|
|
2134
|
+
for (const classified of transactions) {
|
|
2135
|
+
for (const leg of classified.legs) {
|
|
2136
|
+
mints.add(leg.amount.token.mint);
|
|
2137
|
+
}
|
|
2138
|
+
if (classified.classification.primaryAmount?.token.mint) {
|
|
2139
|
+
mints.add(classified.classification.primaryAmount.token.mint);
|
|
2140
|
+
}
|
|
2141
|
+
if (classified.classification.secondaryAmount?.token.mint) {
|
|
2142
|
+
mints.add(classified.classification.secondaryAmount.token.mint);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
if (mints.size === 0) {
|
|
2146
|
+
return transactions;
|
|
2147
|
+
}
|
|
2148
|
+
await tokenFetcher.getTokens(Array.from(mints));
|
|
2149
|
+
return Promise.all(
|
|
2150
|
+
transactions.map((tx) => enrichTokenMetadata(tokenFetcher, tx))
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
1381
2153
|
async function enrichNftClassification(rpcUrl, classified) {
|
|
1382
2154
|
const { classification } = classified;
|
|
1383
2155
|
if (!NFT_TRANSACTION_TYPES.includes(classification.primaryType)) {
|
|
@@ -1410,51 +2182,74 @@ async function enrichNftClassification(rpcUrl, classified) {
|
|
|
1410
2182
|
function createIndexer(options) {
|
|
1411
2183
|
const rpcUrl = "client" in options ? "" : options.rpcUrl;
|
|
1412
2184
|
const client = "client" in options ? options.client : createSolanaClient(options.rpcUrl, options.wsUrl);
|
|
2185
|
+
const tokenFetcher = createTokenFetcher();
|
|
1413
2186
|
return {
|
|
1414
2187
|
rpc: client.rpc,
|
|
1415
2188
|
async getBalance(walletAddress, tokenMints) {
|
|
1416
2189
|
return fetchWalletBalance(client.rpc, walletAddress, tokenMints);
|
|
1417
2190
|
},
|
|
1418
2191
|
async getTransactions(walletAddress, options2 = {}) {
|
|
1419
|
-
const {
|
|
2192
|
+
const {
|
|
2193
|
+
limit = 10,
|
|
2194
|
+
before,
|
|
2195
|
+
until,
|
|
2196
|
+
filterSpam = true,
|
|
2197
|
+
spamConfig,
|
|
2198
|
+
enrichNftMetadata = true,
|
|
2199
|
+
enrichTokenMetadata: enrichTokens = true
|
|
2200
|
+
} = options2;
|
|
1420
2201
|
async function enrichBatch(transactions) {
|
|
1421
|
-
|
|
1422
|
-
|
|
2202
|
+
let result2 = transactions;
|
|
2203
|
+
if (enrichTokens) {
|
|
2204
|
+
result2 = await enrichTokenMetadataBatch(tokenFetcher, result2);
|
|
1423
2205
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
metadata: {
|
|
1440
|
-
...t.classification.metadata,
|
|
1441
|
-
nft_name: nftData.name,
|
|
1442
|
-
nft_image: nftData.image,
|
|
1443
|
-
nft_cdn_image: nftData.cdnImage,
|
|
1444
|
-
nft_collection: nftData.collection,
|
|
1445
|
-
nft_symbol: nftData.symbol,
|
|
1446
|
-
nft_attributes: nftData.attributes
|
|
2206
|
+
if (enrichNftMetadata && rpcUrl) {
|
|
2207
|
+
const nftMints = result2.filter(
|
|
2208
|
+
(t) => NFT_TRANSACTION_TYPES.includes(
|
|
2209
|
+
t.classification.primaryType
|
|
2210
|
+
)
|
|
2211
|
+
).map((t) => t.classification.metadata?.nft_mint).filter(Boolean);
|
|
2212
|
+
if (nftMints.length > 0) {
|
|
2213
|
+
const nftMetadataMap = await fetchNftMetadataBatch(
|
|
2214
|
+
rpcUrl,
|
|
2215
|
+
nftMints
|
|
2216
|
+
);
|
|
2217
|
+
result2 = result2.map((t) => {
|
|
2218
|
+
const nftMint = t.classification.metadata?.nft_mint;
|
|
2219
|
+
if (!nftMint || !nftMetadataMap.has(nftMint)) {
|
|
2220
|
+
return t;
|
|
1447
2221
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
2222
|
+
const nftData = nftMetadataMap.get(nftMint);
|
|
2223
|
+
return {
|
|
2224
|
+
...t,
|
|
2225
|
+
classification: {
|
|
2226
|
+
...t.classification,
|
|
2227
|
+
metadata: {
|
|
2228
|
+
...t.classification.metadata,
|
|
2229
|
+
nft_name: nftData.name,
|
|
2230
|
+
nft_image: nftData.image,
|
|
2231
|
+
nft_cdn_image: nftData.cdnImage,
|
|
2232
|
+
nft_collection: nftData.collection,
|
|
2233
|
+
nft_symbol: nftData.symbol,
|
|
2234
|
+
nft_attributes: nftData.attributes
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
};
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return result2;
|
|
1451
2242
|
}
|
|
1452
2243
|
if (!filterSpam) {
|
|
1453
|
-
const signatures = await fetchWalletSignatures(
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
2244
|
+
const signatures = await fetchWalletSignatures(
|
|
2245
|
+
client.rpc,
|
|
2246
|
+
walletAddress,
|
|
2247
|
+
{
|
|
2248
|
+
limit,
|
|
2249
|
+
before,
|
|
2250
|
+
until
|
|
2251
|
+
}
|
|
2252
|
+
);
|
|
1458
2253
|
if (signatures.length === 0) {
|
|
1459
2254
|
return [];
|
|
1460
2255
|
}
|
|
@@ -1469,7 +2264,11 @@ function createIndexer(options) {
|
|
|
1469
2264
|
const classified = transactions.map((tx) => {
|
|
1470
2265
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1471
2266
|
const legs = transactionToLegs(tx);
|
|
1472
|
-
const classification = classifyTransaction(
|
|
2267
|
+
const classification = classifyTransaction(
|
|
2268
|
+
legs,
|
|
2269
|
+
tx,
|
|
2270
|
+
walletAddressStr2
|
|
2271
|
+
);
|
|
1473
2272
|
return { tx, classification, legs };
|
|
1474
2273
|
});
|
|
1475
2274
|
return enrichBatch(classified);
|
|
@@ -1482,11 +2281,15 @@ function createIndexer(options) {
|
|
|
1482
2281
|
while (accumulated.length < limit && iteration < MAX_ITERATIONS) {
|
|
1483
2282
|
iteration++;
|
|
1484
2283
|
const batchSize = iteration === 1 ? limit : limit * 2;
|
|
1485
|
-
const signatures = await fetchWalletSignatures(
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
2284
|
+
const signatures = await fetchWalletSignatures(
|
|
2285
|
+
client.rpc,
|
|
2286
|
+
walletAddress,
|
|
2287
|
+
{
|
|
2288
|
+
limit: batchSize,
|
|
2289
|
+
before: currentBefore,
|
|
2290
|
+
until
|
|
2291
|
+
}
|
|
2292
|
+
);
|
|
1490
2293
|
if (signatures.length === 0) {
|
|
1491
2294
|
break;
|
|
1492
2295
|
}
|
|
@@ -1500,7 +2303,11 @@ function createIndexer(options) {
|
|
|
1500
2303
|
const classified = transactions.map((tx) => {
|
|
1501
2304
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1502
2305
|
const legs = transactionToLegs(tx);
|
|
1503
|
-
const classification = classifyTransaction(
|
|
2306
|
+
const classification = classifyTransaction(
|
|
2307
|
+
legs,
|
|
2308
|
+
tx,
|
|
2309
|
+
walletAddressStr
|
|
2310
|
+
);
|
|
1504
2311
|
return { tx, classification, legs };
|
|
1505
2312
|
});
|
|
1506
2313
|
const nonSpam = filterSpamTransactions(classified, spamConfig);
|
|
@@ -1516,7 +2323,10 @@ function createIndexer(options) {
|
|
|
1516
2323
|
return enrichBatch(result);
|
|
1517
2324
|
},
|
|
1518
2325
|
async getTransaction(signature2, options2 = {}) {
|
|
1519
|
-
const {
|
|
2326
|
+
const {
|
|
2327
|
+
enrichNftMetadata = true,
|
|
2328
|
+
enrichTokenMetadata: enrichTokens = true
|
|
2329
|
+
} = options2;
|
|
1520
2330
|
const tx = await fetchTransaction(client.rpc, signature2);
|
|
1521
2331
|
if (!tx) {
|
|
1522
2332
|
return null;
|
|
@@ -1525,6 +2335,9 @@ function createIndexer(options) {
|
|
|
1525
2335
|
const legs = transactionToLegs(tx);
|
|
1526
2336
|
const classification = classifyTransaction(legs, tx);
|
|
1527
2337
|
let classified = { tx, classification, legs };
|
|
2338
|
+
if (enrichTokens) {
|
|
2339
|
+
classified = await enrichTokenMetadata(tokenFetcher, classified);
|
|
2340
|
+
}
|
|
1528
2341
|
if (enrichNftMetadata && rpcUrl) {
|
|
1529
2342
|
classified = await enrichNftClassification(rpcUrl, classified);
|
|
1530
2343
|
}
|