tx-indexer 0.5.2 → 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-DdzTiKZ4.d.ts → client-xmDVjOy4.d.ts} +13 -1
- package/dist/client.d.ts +2 -2
- package/dist/client.js +499 -49
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +109 -5
- package/dist/index.js +521 -52
- 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,194 @@ 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
|
+
}
|
|
51
252
|
|
|
52
253
|
// ../solana/src/constants/program-ids.ts
|
|
53
254
|
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
@@ -1697,6 +1898,118 @@ function filterSpamTransactions(transactions, config) {
|
|
|
1697
1898
|
);
|
|
1698
1899
|
}
|
|
1699
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
|
+
|
|
1700
2013
|
// src/nft.ts
|
|
1701
2014
|
async function fetchNftMetadata(rpcUrl, mintAddress) {
|
|
1702
2015
|
const response = await fetch(rpcUrl, {
|
|
@@ -1741,6 +2054,102 @@ async function fetchNftMetadataBatch(rpcUrl, mintAddresses) {
|
|
|
1741
2054
|
|
|
1742
2055
|
// src/client.ts
|
|
1743
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
|
+
}
|
|
1744
2153
|
async function enrichNftClassification(rpcUrl, classified) {
|
|
1745
2154
|
const { classification } = classified;
|
|
1746
2155
|
if (!NFT_TRANSACTION_TYPES.includes(classification.primaryType)) {
|
|
@@ -1773,51 +2182,74 @@ async function enrichNftClassification(rpcUrl, classified) {
|
|
|
1773
2182
|
function createIndexer(options) {
|
|
1774
2183
|
const rpcUrl = "client" in options ? "" : options.rpcUrl;
|
|
1775
2184
|
const client = "client" in options ? options.client : createSolanaClient(options.rpcUrl, options.wsUrl);
|
|
2185
|
+
const tokenFetcher = createTokenFetcher();
|
|
1776
2186
|
return {
|
|
1777
2187
|
rpc: client.rpc,
|
|
1778
2188
|
async getBalance(walletAddress, tokenMints) {
|
|
1779
2189
|
return fetchWalletBalance(client.rpc, walletAddress, tokenMints);
|
|
1780
2190
|
},
|
|
1781
2191
|
async getTransactions(walletAddress, options2 = {}) {
|
|
1782
|
-
const {
|
|
2192
|
+
const {
|
|
2193
|
+
limit = 10,
|
|
2194
|
+
before,
|
|
2195
|
+
until,
|
|
2196
|
+
filterSpam = true,
|
|
2197
|
+
spamConfig,
|
|
2198
|
+
enrichNftMetadata = true,
|
|
2199
|
+
enrichTokenMetadata: enrichTokens = true
|
|
2200
|
+
} = options2;
|
|
1783
2201
|
async function enrichBatch(transactions) {
|
|
1784
|
-
|
|
1785
|
-
|
|
2202
|
+
let result2 = transactions;
|
|
2203
|
+
if (enrichTokens) {
|
|
2204
|
+
result2 = await enrichTokenMetadataBatch(tokenFetcher, result2);
|
|
1786
2205
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
metadata: {
|
|
1803
|
-
...t.classification.metadata,
|
|
1804
|
-
nft_name: nftData.name,
|
|
1805
|
-
nft_image: nftData.image,
|
|
1806
|
-
nft_cdn_image: nftData.cdnImage,
|
|
1807
|
-
nft_collection: nftData.collection,
|
|
1808
|
-
nft_symbol: nftData.symbol,
|
|
1809
|
-
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;
|
|
1810
2221
|
}
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
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;
|
|
1814
2242
|
}
|
|
1815
2243
|
if (!filterSpam) {
|
|
1816
|
-
const signatures = await fetchWalletSignatures(
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
2244
|
+
const signatures = await fetchWalletSignatures(
|
|
2245
|
+
client.rpc,
|
|
2246
|
+
walletAddress,
|
|
2247
|
+
{
|
|
2248
|
+
limit,
|
|
2249
|
+
before,
|
|
2250
|
+
until
|
|
2251
|
+
}
|
|
2252
|
+
);
|
|
1821
2253
|
if (signatures.length === 0) {
|
|
1822
2254
|
return [];
|
|
1823
2255
|
}
|
|
@@ -1832,7 +2264,11 @@ function createIndexer(options) {
|
|
|
1832
2264
|
const classified = transactions.map((tx) => {
|
|
1833
2265
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1834
2266
|
const legs = transactionToLegs(tx);
|
|
1835
|
-
const classification = classifyTransaction(
|
|
2267
|
+
const classification = classifyTransaction(
|
|
2268
|
+
legs,
|
|
2269
|
+
tx,
|
|
2270
|
+
walletAddressStr2
|
|
2271
|
+
);
|
|
1836
2272
|
return { tx, classification, legs };
|
|
1837
2273
|
});
|
|
1838
2274
|
return enrichBatch(classified);
|
|
@@ -1845,11 +2281,15 @@ function createIndexer(options) {
|
|
|
1845
2281
|
while (accumulated.length < limit && iteration < MAX_ITERATIONS) {
|
|
1846
2282
|
iteration++;
|
|
1847
2283
|
const batchSize = iteration === 1 ? limit : limit * 2;
|
|
1848
|
-
const signatures = await fetchWalletSignatures(
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
2284
|
+
const signatures = await fetchWalletSignatures(
|
|
2285
|
+
client.rpc,
|
|
2286
|
+
walletAddress,
|
|
2287
|
+
{
|
|
2288
|
+
limit: batchSize,
|
|
2289
|
+
before: currentBefore,
|
|
2290
|
+
until
|
|
2291
|
+
}
|
|
2292
|
+
);
|
|
1853
2293
|
if (signatures.length === 0) {
|
|
1854
2294
|
break;
|
|
1855
2295
|
}
|
|
@@ -1863,7 +2303,11 @@ function createIndexer(options) {
|
|
|
1863
2303
|
const classified = transactions.map((tx) => {
|
|
1864
2304
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1865
2305
|
const legs = transactionToLegs(tx);
|
|
1866
|
-
const classification = classifyTransaction(
|
|
2306
|
+
const classification = classifyTransaction(
|
|
2307
|
+
legs,
|
|
2308
|
+
tx,
|
|
2309
|
+
walletAddressStr
|
|
2310
|
+
);
|
|
1867
2311
|
return { tx, classification, legs };
|
|
1868
2312
|
});
|
|
1869
2313
|
const nonSpam = filterSpamTransactions(classified, spamConfig);
|
|
@@ -1879,7 +2323,10 @@ function createIndexer(options) {
|
|
|
1879
2323
|
return enrichBatch(result);
|
|
1880
2324
|
},
|
|
1881
2325
|
async getTransaction(signature2, options2 = {}) {
|
|
1882
|
-
const {
|
|
2326
|
+
const {
|
|
2327
|
+
enrichNftMetadata = true,
|
|
2328
|
+
enrichTokenMetadata: enrichTokens = true
|
|
2329
|
+
} = options2;
|
|
1883
2330
|
const tx = await fetchTransaction(client.rpc, signature2);
|
|
1884
2331
|
if (!tx) {
|
|
1885
2332
|
return null;
|
|
@@ -1888,6 +2335,9 @@ function createIndexer(options) {
|
|
|
1888
2335
|
const legs = transactionToLegs(tx);
|
|
1889
2336
|
const classification = classifyTransaction(legs, tx);
|
|
1890
2337
|
let classified = { tx, classification, legs };
|
|
2338
|
+
if (enrichTokens) {
|
|
2339
|
+
classified = await enrichTokenMetadata(tokenFetcher, classified);
|
|
2340
|
+
}
|
|
1891
2341
|
if (enrichNftMetadata && rpcUrl) {
|
|
1892
2342
|
classified = await enrichNftClassification(rpcUrl, classified);
|
|
1893
2343
|
}
|