diff --git a/packages/cardano-services-client/src/blockfrost/util.ts b/packages/cardano-services-client/src/blockfrost/util.ts index c46f6531ad4..6535e690335 100644 --- a/packages/cardano-services-client/src/blockfrost/util.ts +++ b/packages/cardano-services-client/src/blockfrost/util.ts @@ -32,17 +32,20 @@ export const fetchSequentially = async ( haveEnoughItems?: (allItems: Item[], lastResponseBatch: Response[]) => boolean; paginationOptions?: PaginationOptions; }, - page = 1, accumulated: Item[] = [] ): Promise => { const count = props.paginationOptions?.count || 100; + const page = props.paginationOptions?.page || 1; try { const response = await props.request(buildQueryString({ count, order: props.paginationOptions?.order, page })); const maybeTranslatedResponse = props.responseTranslator ? props.responseTranslator(response) : response; const newAccumulatedItems = [...accumulated, ...maybeTranslatedResponse] as Item[]; const haveEnoughItems = props.haveEnoughItems?.(newAccumulatedItems, response); if (response.length === count && !haveEnoughItems) { - return fetchSequentially(props, page + 1, newAccumulatedItems); + return fetchSequentially( + { ...props, paginationOptions: { ...props.paginationOptions, page: page + 1 } }, + newAccumulatedItems + ); } return newAccumulatedItems; } catch (error) { diff --git a/packages/wallet/src/services/TransactionsTracker.ts b/packages/wallet/src/services/TransactionsTracker.ts index 45b940665af..01f0540217b 100644 --- a/packages/wallet/src/services/TransactionsTracker.ts +++ b/packages/wallet/src/services/TransactionsTracker.ts @@ -40,6 +40,8 @@ import { newAndStoredMulticast } from './util/newAndStoredMulticast'; import chunk from 'lodash/chunk.js'; import sortBy from 'lodash/sortBy.js'; +const ONE_MONTH_BLOCK_TIME = 21_600 * 6; + export interface TransactionsTrackerProps { chainHistoryProvider: ChainHistoryProvider; addresses$: Observable; @@ -140,7 +142,7 @@ const allTransactionsByAddresses = async ( startAt += PAGE_SIZE; response = [...response, ...pageResults]; - } while (pageResults.length === PAGE_SIZE); + } while (pageResults.length >= PAGE_SIZE); } else { const txes = await chainHistoryProvider.transactionsByAddresses({ addresses: addressGroup, @@ -201,6 +203,43 @@ export const revertLastBlock = ( return deduplicateSortedArray(result, txEquals); }; +/** + * Fetches the last `historicalTransactionsFetchLimit` transactions for a set of addresses. + * If there is a single address, it returns the most recent ones up to `historicalTransactionsFetchLimit`. If there + * are more than one address, it returns all transaction from all addresses, one month back from the most recent transaction. + * + * @param {ChainHistoryProvider} chainHistoryProvider - The chain history provider used to fetch transaction history. + * @param {Cardano.PaymentAddress[]} addresses - A list of Cardano payment addresses to fetch transactions for. + * @param {number} historicalTransactionsFetchLimit - The maximum number of transactions to fetch in the initial pass. + * @returns {Promise} A promise that resolves to a list of hydrated transactions from the given addresses. + */ +const fetchInitialTransactions = async ( + chainHistoryProvider: ChainHistoryProvider, + addresses: Cardano.PaymentAddress[], + historicalTransactionsFetchLimit: number +): Promise => { + const firstPassTxs = await allTransactionsByAddresses(chainHistoryProvider, { + addresses, + filterBy: { limit: historicalTransactionsFetchLimit, type: 'tip' } + }); + + if (firstPassTxs.length === 0) { + return []; + } + + if (addresses.length === 1) { + return firstPassTxs; + } + + const highBlockNo = Cardano.BlockNo(Math.max(...firstPassTxs.map((tx) => tx.blockHeader.blockNo))); + const onMonthBack = Cardano.BlockNo(Math.max(highBlockNo - ONE_MONTH_BLOCK_TIME, 0)); + + return await allTransactionsByAddresses(chainHistoryProvider, { + addresses, + filterBy: { blockRange: { lowerBound: onMonthBack }, type: 'blockRange' } + }); +}; + const findIntersectionAndUpdateTxStore = ({ chainHistoryProvider, historicalTransactionsFetchLimit, @@ -245,12 +284,12 @@ const findIntersectionAndUpdateTxStore = ({ ); const lowerBound = lastStoredTransaction?.blockHeader.blockNo; - const newTransactions = await allTransactionsByAddresses(chainHistoryProvider, { - addresses, - filterBy: lowerBound - ? { blockRange: { lowerBound }, type: 'blockRange' } - : { limit: historicalTransactionsFetchLimit, type: 'tip' } - }); + const newTransactions = await (lowerBound === undefined + ? fetchInitialTransactions(chainHistoryProvider, addresses, historicalTransactionsFetchLimit) + : allTransactionsByAddresses(chainHistoryProvider, { + addresses, + filterBy: { blockRange: { lowerBound }, type: 'blockRange' } + })); logger.debug( `chainHistoryProvider returned ${newTransactions.length} transactions`,