@jpool/bond-sdk 0.8.0-next.4 → 0.9.0-next.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.mjs CHANGED
@@ -1291,167 +1291,82 @@ var JBondClient = class _JBondClient {
1291
1291
  const availableBalance = Math.max(0, lamports - rentExempt);
1292
1292
  return availableBalance / LAMPORTS_PER_SOL;
1293
1293
  }
1294
- /**
1295
- * Get transaction history grouped by epochs
1296
- * @param vote - The vote account to get history for
1297
- * @param epochsCount - Number of recent epochs to return (default: 10)
1298
- * @returns Array of epoch history items sorted by epoch (descending)
1299
- */
1300
- async getHistoryGroupedByEpochs(vote, epochsCount = 10) {
1301
- const epochInfo = await this.connection.getEpochInfo();
1302
- const fullHistory = await this.getFullHistory(new PublicKey(vote));
1303
- const epochMap = /* @__PURE__ */ new Map();
1304
- for (const item of fullHistory) {
1305
- if (item.epoch < epochInfo.epoch - epochsCount + 1) {
1306
- continue;
1307
- }
1308
- if (!epochMap.has(item.epoch)) {
1309
- epochMap.set(item.epoch, {
1310
- epoch: item.epoch,
1311
- deposits: 0,
1312
- withdrawals: 0,
1313
- balanceChange: 0,
1314
- signatures: []
1315
- });
1316
- }
1317
- const epochData = epochMap.get(item.epoch);
1318
- if (item.type === "deposit") {
1319
- epochData.deposits += item.amount;
1320
- } else if (item.type === "withdrawal") {
1321
- epochData.withdrawals += item.amount;
1322
- }
1323
- if (!epochData.signatures.includes(item.signature)) {
1324
- epochData.signatures.push(item.signature);
1325
- }
1326
- }
1327
- for (const epochData of epochMap.values()) {
1328
- epochData.balanceChange = epochData.deposits - epochData.withdrawals;
1329
- }
1330
- return [...epochMap.values()].toSorted((a, b) => b.epoch - a.epoch);
1331
- }
1332
1294
  /**
1333
1295
  * Get transaction history for a specific validator bond account
1334
1296
  */
1335
1297
  async getHistory(vote, options) {
1336
- const [ValidatorBondAccount] = this.pda.validatorBond(new PublicKey(vote));
1337
- const signatures = (await this.connection.getSignaturesForAddress(
1338
- ValidatorBondAccount,
1339
- {
1340
- limit: options?.limit || 1e3,
1341
- before: options?.before,
1342
- until: options?.until
1343
- }
1344
- )).filter((sig) => !sig.err);
1345
- const signatureStrings = signatures.map((sig) => sig.signature);
1346
- const BATCH_SIZE = 100;
1347
- const allTransactions = [];
1348
- for (let i = 0; i < signatureStrings.length; i += BATCH_SIZE) {
1349
- const batch = signatureStrings.slice(i, i + BATCH_SIZE);
1350
- const transactions = await this.connection.getParsedTransactions(
1351
- batch,
1352
- {
1353
- maxSupportedTransactionVersion: 0
1298
+ const cluster = options?.cluster || "mainnet-beta";
1299
+ const [validatorBondAccount] = this.pda.validatorBond(vote);
1300
+ const signatures = await this.fetchSignaturesForValidator(validatorBondAccount, {
1301
+ limit: options?.limit,
1302
+ before: options?.before,
1303
+ until: options?.until
1304
+ });
1305
+ if (signatures.length === 0) {
1306
+ return [];
1307
+ }
1308
+ const signatureStrings = signatures.map((s) => s.signature);
1309
+ const parsedTxs = await this.fetchParsedTransactions(signatureStrings);
1310
+ const txBySig = /* @__PURE__ */ new Map();
1311
+ for (let i = 0; i < signatureStrings.length; i++) {
1312
+ const requestedSig = signatureStrings[i];
1313
+ const tx = parsedTxs[i] ?? null;
1314
+ if (tx && tx.transaction && Array.isArray(tx.transaction.signatures) && tx.transaction.signatures[0]) {
1315
+ const txSig = tx.transaction.signatures[0];
1316
+ if (txSig !== requestedSig) {
1317
+ const found = parsedTxs.find((t) => t && t.transaction && t.transaction.signatures && t.transaction.signatures[0] === requestedSig) ?? null;
1318
+ txBySig.set(requestedSig, found);
1319
+ continue;
1354
1320
  }
1355
- );
1356
- allTransactions.push(...transactions);
1321
+ }
1322
+ txBySig.set(requestedSig, tx);
1357
1323
  }
1358
- const cluster = options?.cluster || "mainnet-beta";
1359
1324
  const history = [];
1360
- for (const [idx, tx] of allTransactions.entries()) {
1361
- const sigInfo = signatures[idx];
1325
+ for (const sigInfo of signatures) {
1326
+ const sig = sigInfo.signature;
1327
+ const tx = txBySig.get(sig) ?? null;
1362
1328
  if (!tx || !tx.meta || tx.meta.err !== null) {
1363
1329
  continue;
1364
1330
  }
1365
1331
  try {
1366
- const slot = tx.slot || 0;
1332
+ const slot = tx.slot ?? 0;
1367
1333
  const instructions = tx.transaction.message.instructions;
1368
1334
  for (const instruction of instructions) {
1369
- if ("programId" in instruction && instruction.programId.equals(this.options.programId ?? this.program.programId)) {
1370
- const ixData = instruction;
1371
- if ("parsed" in ixData && ixData.parsed) {
1372
- continue;
1373
- }
1374
- const data = ixData.data;
1375
- if (!data) {
1376
- continue;
1377
- }
1378
- let type = null;
1379
- let amount = 0;
1380
- try {
1381
- const dataBuffer = bs58.decode(data);
1382
- if (dataBuffer.length >= 16) {
1383
- const discriminator = dataBuffer.slice(0, 8);
1384
- const bondInitDiscriminator = this.getInstructionDiscriminator("register");
1385
- const bondTopUpDiscriminator = this.getInstructionDiscriminator("topUp");
1386
- const withdrawCompensationDiscriminator = this.getInstructionDiscriminator("claim");
1387
- const bondWithdrawDiscriminator = this.getInstructionDiscriminator("withdraw");
1388
- const amountBytes = dataBuffer.slice(8, 16);
1389
- const amountBN = new BN(amountBytes, "le");
1390
- amount = amountBN.toNumber() / LAMPORTS_PER_SOL;
1391
- if (Buffer.from(discriminator).equals(Buffer.from(bondInitDiscriminator))) {
1392
- type = "deposit" /* Deposit */;
1393
- } else if (Buffer.from(discriminator).equals(Buffer.from(bondTopUpDiscriminator))) {
1394
- type = "deposit" /* Deposit */;
1395
- } else if (Buffer.from(discriminator).equals(Buffer.from(withdrawCompensationDiscriminator))) {
1396
- type = "compensation" /* Compensation */;
1397
- } else if (Buffer.from(discriminator).equals(Buffer.from(bondWithdrawDiscriminator))) {
1398
- type = "withdrawal" /* Withdrawal */;
1399
- }
1400
- }
1401
- } catch {
1402
- console.warn("Failed to decode instruction data");
1403
- }
1404
- if (type && amount > 0) {
1405
- let beforeBalance;
1406
- let afterBalance;
1407
- const accountIndex = tx.transaction.message.accountKeys.findIndex(
1408
- (key) => key.pubkey.equals(ValidatorBondAccount)
1409
- );
1410
- if (accountIndex !== -1 && tx.meta.preBalances && tx.meta.postBalances) {
1411
- beforeBalance = Number(tx.meta.preBalances[accountIndex] || 0) / LAMPORTS_PER_SOL;
1412
- afterBalance = Number(tx.meta.postBalances[accountIndex] || 0) / LAMPORTS_PER_SOL;
1413
- }
1414
- history.push({
1415
- signature: sigInfo.signature,
1416
- slot,
1417
- epoch: slotToEpoch(slot, cluster),
1418
- type,
1419
- amount,
1420
- beforeBalance,
1421
- afterBalance
1422
- });
1423
- }
1335
+ if (!("programId" in instruction)) {
1336
+ continue;
1337
+ }
1338
+ if (!instruction.programId.equals(this.options.programId ?? this.program.programId)) {
1339
+ continue;
1424
1340
  }
1341
+ if (instruction.parsed) {
1342
+ continue;
1343
+ }
1344
+ const { type, amount } = this.decodeInstructionData(instruction.data);
1345
+ if (!type || amount <= 0) {
1346
+ continue;
1347
+ }
1348
+ let beforeBalance;
1349
+ let afterBalance;
1350
+ const accountIndex = tx.transaction.message.accountKeys.findIndex((k) => k.pubkey.equals(validatorBondAccount));
1351
+ if (accountIndex !== -1 && tx.meta.preBalances && tx.meta.postBalances) {
1352
+ beforeBalance = Number(tx.meta.preBalances[accountIndex] || 0) / LAMPORTS_PER_SOL;
1353
+ afterBalance = Number(tx.meta.postBalances[accountIndex] || 0) / LAMPORTS_PER_SOL;
1354
+ }
1355
+ history.push({
1356
+ signature: sigInfo.signature,
1357
+ slot,
1358
+ epoch: slotToEpoch(slot, cluster),
1359
+ type,
1360
+ amount,
1361
+ beforeBalance,
1362
+ afterBalance
1363
+ });
1425
1364
  }
1426
1365
  } catch (error) {
1427
1366
  console.error(`Error processing transaction ${sigInfo.signature}:`, error);
1428
1367
  }
1429
1368
  }
1430
- return history.toSorted((a, b) => b.slot - a.slot);
1431
- }
1432
- /**
1433
- * Get full transaction history by paginating through results
1434
- * @param voteAccount
1435
- * @param pageSize
1436
- */
1437
- async getFullHistory(voteAccount, pageSize = 100) {
1438
- const allHistory = [];
1439
- let before;
1440
- while (true) {
1441
- const batch = await this.getHistory(voteAccount, {
1442
- limit: pageSize,
1443
- before
1444
- });
1445
- if (batch.length === 0) {
1446
- break;
1447
- }
1448
- allHistory.push(...batch);
1449
- before = batch.at(-1)?.signature;
1450
- if (batch.length < pageSize) {
1451
- break;
1452
- }
1453
- }
1454
- return allHistory;
1369
+ return history.sort((a, b) => b.slot - a.slot);
1455
1370
  }
1456
1371
  /**
1457
1372
  * Get instruction discriminator from IDL
@@ -1468,6 +1383,65 @@ var JBondClient = class _JBondClient {
1468
1383
  }
1469
1384
  return new Uint8Array(instruction.discriminator);
1470
1385
  }
1386
+ async fetchSignaturesForValidator(validatorBondAccount, options) {
1387
+ const sigs = await this.connection.getSignaturesForAddress(
1388
+ validatorBondAccount,
1389
+ {
1390
+ limit: options?.limit || 1e3,
1391
+ before: options?.before,
1392
+ until: options?.until
1393
+ }
1394
+ );
1395
+ return sigs.filter((s) => !s.err);
1396
+ }
1397
+ // Fetch parsed transactions in batches to avoid rate limits
1398
+ async fetchParsedTransactions(signatureStrings, batchSize = 100) {
1399
+ const allTxs = [];
1400
+ for (let i = 0; i < signatureStrings.length; i += batchSize) {
1401
+ const batch = signatureStrings.slice(i, i + batchSize);
1402
+ const txs = await this.connection.getParsedTransactions(batch, {
1403
+ maxSupportedTransactionVersion: 0
1404
+ });
1405
+ allTxs.push(...txs);
1406
+ }
1407
+ return allTxs;
1408
+ }
1409
+ // Decode instruction data to determine transaction type and amount
1410
+ decodeInstructionData(data) {
1411
+ if (!data) {
1412
+ return { type: null, amount: 0 };
1413
+ }
1414
+ try {
1415
+ const dataBuffer = bs58.decode(data);
1416
+ if (dataBuffer.length < 16) {
1417
+ return { type: null, amount: 0 };
1418
+ }
1419
+ const discriminator = dataBuffer.slice(0, 8);
1420
+ const amountBytes = dataBuffer.slice(8, 16);
1421
+ const amountBN = new BN(amountBytes, "le");
1422
+ const amount = amountBN.toNumber() / LAMPORTS_PER_SOL;
1423
+ const bondInitDiscriminator = this.getInstructionDiscriminator("register");
1424
+ const bondTopUpDiscriminator = this.getInstructionDiscriminator("topUp");
1425
+ const withdrawCompensationDiscriminator = this.getInstructionDiscriminator("claim");
1426
+ const bondWithdrawDiscriminator = this.getInstructionDiscriminator("withdraw");
1427
+ if (Buffer.from(discriminator).equals(Buffer.from(bondInitDiscriminator))) {
1428
+ return { type: "deposit" /* Deposit */, amount };
1429
+ }
1430
+ if (Buffer.from(discriminator).equals(Buffer.from(bondTopUpDiscriminator))) {
1431
+ return { type: "deposit" /* Deposit */, amount };
1432
+ }
1433
+ if (Buffer.from(discriminator).equals(Buffer.from(withdrawCompensationDiscriminator))) {
1434
+ return { type: "compensation" /* Compensation */, amount };
1435
+ }
1436
+ if (Buffer.from(discriminator).equals(Buffer.from(bondWithdrawDiscriminator))) {
1437
+ return { type: "withdrawal" /* Withdrawal */, amount };
1438
+ }
1439
+ return { type: null, amount: 0 };
1440
+ } catch (err) {
1441
+ console.warn("Failed to decode instruction data", err);
1442
+ return { type: null, amount: 0 };
1443
+ }
1444
+ }
1471
1445
  };
1472
1446
 
1473
1447
  export { BondClientEnv, BondTransactionType, ENV_PROGRAM_ID, JBondClient, NodeWallet };