tx-indexer 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { C as ClassifiedTransaction, F as FetchTransactionsConfig, G as GetTransactionsOptions, I as IndexerRpcApi, S as SolanaClient, l as SpamFilterConfig, e as TokenAccountBalance, T as TxIndexer, a as TxIndexerOptions, W as WalletBalance, c as createIndexer, b as createSolanaClient, h as fetchTransaction, i as fetchTransactionsBatch, f as fetchWalletBalance, g as fetchWalletSignatures, k as filterSpamTransactions, j as isSpamTransaction, p as parseAddress, d as parseSignature, t as transactionToLegs } from './client-yGDWPKKf.js';
2
- import { T as TxLeg, R as RawTransaction, a as TransactionClassification } from './classification.types-DlJe6bDZ.js';
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-DlJe6bDZ.js';
1
+ export { C as ClassifiedTransaction, F as FetchTransactionsConfig, b as GetTransactionOptions, G as GetTransactionsOptions, I as IndexerRpcApi, N as NftMetadata, S as SolanaClient, m as SpamFilterConfig, g as TokenAccountBalance, T as TxIndexer, a as TxIndexerOptions, W as WalletBalance, c as createIndexer, d as createSolanaClient, n as fetchNftMetadata, o as fetchNftMetadataBatch, i as fetchTransaction, j as fetchTransactionsBatch, f as fetchWalletBalance, h as fetchWalletSignatures, l as filterSpamTransactions, k as isSpamTransaction, p as parseAddress, e as parseSignature, t as transactionToLegs } from './client-iLW2_DnL.js';
2
+ import { T as TxLeg, R as RawTransaction, a as TransactionClassification } from './classification.types-Cn9IGtEC.js';
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';
5
5
  export { Categorization, CategorizationSchema, Counterparty, CounterpartySchema, FiatValue, MoneyAmount, ProtocolInfoSchema } from './types.js';
6
6
  import { z } from 'zod';
package/dist/index.js CHANGED
@@ -428,6 +428,7 @@ async function fetchTransaction(rpc, signature2, commitment = "confirmed") {
428
428
  signature: signature2,
429
429
  slot: response.slot,
430
430
  blockTime: response.blockTime,
431
+ fee: Number(response.meta?.fee ?? 0),
431
432
  err: response.meta?.err ?? null,
432
433
  programIds: extractProgramIds(response.transaction),
433
434
  protocol: null,
@@ -1356,8 +1357,81 @@ function filterSpamTransactions(transactions, config) {
1356
1357
  );
1357
1358
  }
1358
1359
 
1360
+ // src/nft.ts
1361
+ async function fetchNftMetadata(rpcUrl, mintAddress) {
1362
+ const response = await fetch(rpcUrl, {
1363
+ method: "POST",
1364
+ headers: { "Content-Type": "application/json" },
1365
+ body: JSON.stringify({
1366
+ jsonrpc: "2.0",
1367
+ id: "get-asset",
1368
+ method: "getAsset",
1369
+ params: { id: mintAddress }
1370
+ })
1371
+ });
1372
+ const data = await response.json();
1373
+ if (data.error || !data.result?.content?.metadata) {
1374
+ return null;
1375
+ }
1376
+ const { result } = data;
1377
+ const { content, grouping } = result;
1378
+ return {
1379
+ mint: mintAddress,
1380
+ name: content.metadata.name,
1381
+ symbol: content.metadata.symbol,
1382
+ image: content.links.image ?? content.files?.[0]?.uri ?? "",
1383
+ cdnImage: content.files?.[0]?.cdn_uri,
1384
+ description: content.metadata.description,
1385
+ collection: grouping?.find((g) => g.group_key === "collection")?.group_value,
1386
+ attributes: content.metadata.attributes
1387
+ };
1388
+ }
1389
+ async function fetchNftMetadataBatch(rpcUrl, mintAddresses) {
1390
+ const results = await Promise.all(
1391
+ mintAddresses.map((mint) => fetchNftMetadata(rpcUrl, mint))
1392
+ );
1393
+ const map = /* @__PURE__ */ new Map();
1394
+ results.forEach((metadata, index) => {
1395
+ if (metadata) {
1396
+ map.set(mintAddresses[index], metadata);
1397
+ }
1398
+ });
1399
+ return map;
1400
+ }
1401
+
1359
1402
  // src/client.ts
1403
+ var NFT_TRANSACTION_TYPES = ["nft_mint", "nft_purchase", "nft_sale"];
1404
+ async function enrichNftClassification(rpcUrl, classified) {
1405
+ const { classification } = classified;
1406
+ if (!NFT_TRANSACTION_TYPES.includes(classification.primaryType)) {
1407
+ return classified;
1408
+ }
1409
+ const nftMint = classification.metadata?.nft_mint;
1410
+ if (!nftMint) {
1411
+ return classified;
1412
+ }
1413
+ const nftData = await fetchNftMetadata(rpcUrl, nftMint);
1414
+ if (!nftData) {
1415
+ return classified;
1416
+ }
1417
+ return {
1418
+ ...classified,
1419
+ classification: {
1420
+ ...classification,
1421
+ metadata: {
1422
+ ...classification.metadata,
1423
+ nft_name: nftData.name,
1424
+ nft_image: nftData.image,
1425
+ nft_cdn_image: nftData.cdnImage,
1426
+ nft_collection: nftData.collection,
1427
+ nft_symbol: nftData.symbol,
1428
+ nft_attributes: nftData.attributes
1429
+ }
1430
+ }
1431
+ };
1432
+ }
1360
1433
  function createIndexer(options) {
1434
+ const rpcUrl = "client" in options ? "" : options.rpcUrl;
1361
1435
  const client = "client" in options ? options.client : createSolanaClient(options.rpcUrl, options.wsUrl);
1362
1436
  return {
1363
1437
  rpc: client.rpc,
@@ -1365,7 +1439,39 @@ function createIndexer(options) {
1365
1439
  return fetchWalletBalance(client.rpc, walletAddress, tokenMints);
1366
1440
  },
1367
1441
  async getTransactions(walletAddress, options2 = {}) {
1368
- const { limit = 10, before, until, filterSpam = true, spamConfig } = options2;
1442
+ const { limit = 10, before, until, filterSpam = true, spamConfig, enrichNftMetadata = true } = options2;
1443
+ async function enrichBatch(transactions) {
1444
+ if (!enrichNftMetadata || !rpcUrl) {
1445
+ return transactions;
1446
+ }
1447
+ const nftMints = transactions.filter((t) => NFT_TRANSACTION_TYPES.includes(t.classification.primaryType)).map((t) => t.classification.metadata?.nft_mint).filter(Boolean);
1448
+ if (nftMints.length === 0) {
1449
+ return transactions;
1450
+ }
1451
+ const nftMetadataMap = await fetchNftMetadataBatch(rpcUrl, nftMints);
1452
+ return transactions.map((t) => {
1453
+ const nftMint = t.classification.metadata?.nft_mint;
1454
+ if (!nftMint || !nftMetadataMap.has(nftMint)) {
1455
+ return t;
1456
+ }
1457
+ const nftData = nftMetadataMap.get(nftMint);
1458
+ return {
1459
+ ...t,
1460
+ classification: {
1461
+ ...t.classification,
1462
+ metadata: {
1463
+ ...t.classification.metadata,
1464
+ nft_name: nftData.name,
1465
+ nft_image: nftData.image,
1466
+ nft_cdn_image: nftData.cdnImage,
1467
+ nft_collection: nftData.collection,
1468
+ nft_symbol: nftData.symbol,
1469
+ nft_attributes: nftData.attributes
1470
+ }
1471
+ }
1472
+ };
1473
+ });
1474
+ }
1369
1475
  if (!filterSpam) {
1370
1476
  const signatures = await fetchWalletSignatures(client.rpc, walletAddress, {
1371
1477
  limit,
@@ -1388,7 +1494,7 @@ function createIndexer(options) {
1388
1494
  const classification = classifyTransaction(legs, tx);
1389
1495
  return { tx, classification, legs };
1390
1496
  });
1391
- return classified;
1497
+ return enrichBatch(classified);
1392
1498
  }
1393
1499
  const accumulated = [];
1394
1500
  let currentBefore = before;
@@ -1427,9 +1533,11 @@ function createIndexer(options) {
1427
1533
  break;
1428
1534
  }
1429
1535
  }
1430
- return accumulated.slice(0, limit);
1536
+ const result = accumulated.slice(0, limit);
1537
+ return enrichBatch(result);
1431
1538
  },
1432
- async getTransaction(signature2) {
1539
+ async getTransaction(signature2, options2 = {}) {
1540
+ const { enrichNftMetadata = true } = options2;
1433
1541
  const tx = await fetchTransaction(client.rpc, signature2);
1434
1542
  if (!tx) {
1435
1543
  return null;
@@ -1437,10 +1545,26 @@ function createIndexer(options) {
1437
1545
  tx.protocol = detectProtocol(tx.programIds);
1438
1546
  const legs = transactionToLegs(tx);
1439
1547
  const classification = classifyTransaction(legs, tx);
1440
- return { tx, classification, legs };
1548
+ let classified = { tx, classification, legs };
1549
+ if (enrichNftMetadata && rpcUrl) {
1550
+ classified = await enrichNftClassification(rpcUrl, classified);
1551
+ }
1552
+ return classified;
1441
1553
  },
1442
1554
  async getRawTransaction(signature2) {
1443
1555
  return fetchTransaction(client.rpc, signature2);
1556
+ },
1557
+ async getNftMetadata(mintAddress) {
1558
+ if (!rpcUrl) {
1559
+ throw new Error("getNftMetadata requires rpcUrl to be set");
1560
+ }
1561
+ return fetchNftMetadata(rpcUrl, mintAddress);
1562
+ },
1563
+ async getNftMetadataBatch(mintAddresses) {
1564
+ if (!rpcUrl) {
1565
+ throw new Error("getNftMetadataBatch requires rpcUrl to be set");
1566
+ }
1567
+ return fetchNftMetadataBatch(rpcUrl, mintAddresses);
1444
1568
  }
1445
1569
  };
1446
1570
  }
@@ -1492,6 +1616,6 @@ function groupLegsByToken(legs) {
1492
1616
  return grouped;
1493
1617
  }
1494
1618
 
1495
- export { JUPITER_V4_PROGRAM_ID, JUPITER_V6_PROGRAM_ID, KNOWN_TOKENS, SPL_MEMO_PROGRAM_ID, SYSTEM_PROGRAM_ID, TOKEN_INFO, TOKEN_PROGRAM_ID, buildAccountId, classifyTransaction, createIndexer, createSolanaClient, detectFacilitator, detectProtocol, extractMemo, fetchTransaction, fetchTransactionsBatch, fetchWalletBalance, fetchWalletSignatures, filterSpamTransactions, getTokenInfo, groupLegsByAccount, groupLegsByToken, isSolanaPayTransaction, isSpamTransaction, parseAccountId, parseAddress, parseSignature, parseSolanaPayMemo, transactionToLegs, validateLegsBalance };
1619
+ export { JUPITER_V4_PROGRAM_ID, JUPITER_V6_PROGRAM_ID, KNOWN_TOKENS, SPL_MEMO_PROGRAM_ID, SYSTEM_PROGRAM_ID, TOKEN_INFO, TOKEN_PROGRAM_ID, buildAccountId, classifyTransaction, createIndexer, createSolanaClient, detectFacilitator, detectProtocol, extractMemo, fetchNftMetadata, fetchNftMetadataBatch, fetchTransaction, fetchTransactionsBatch, fetchWalletBalance, fetchWalletSignatures, filterSpamTransactions, getTokenInfo, groupLegsByAccount, groupLegsByToken, isSolanaPayTransaction, isSpamTransaction, parseAccountId, parseAddress, parseSignature, parseSolanaPayMemo, transactionToLegs, validateLegsBalance };
1496
1620
  //# sourceMappingURL=index.js.map
1497
1621
  //# sourceMappingURL=index.js.map