diff --git a/packages/core-backend/src/api/accounts/client.test.ts b/packages/core-backend/src/api/accounts/client.test.ts index 00d13eac6b7..100e5166361 100644 --- a/packages/core-backend/src/api/accounts/client.test.ts +++ b/packages/core-backend/src/api/accounts/client.test.ts @@ -397,6 +397,82 @@ describe('AccountsApiClient', () => { }); expect(mockFetch).not.toHaveBeenCalled(); }); + + describe('getV4MultiAccountTransactionsInfiniteQueryOptions', () => { + it('returns a queryKey', () => { + const result = + client.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions({ + accountAddresses: ['eip155:0:0xabc'], + networks: ['eip155:1', 'eip155:137'], + sortDirection: 'DESC', + limit: 25, + }); + + expect(result.queryKey).toStrictEqual([ + 'accounts', + 'transactions', + 'v4MultiAccount', + { + accountAddresses: ['eip155:0:0xabc'], + networks: ['eip155:1', 'eip155:137'], + startTimestamp: undefined, + endTimestamp: undefined, + limit: 25, + sortDirection: 'DESC', + includeLogs: undefined, + includeTxMetadata: undefined, + maxLogsPerTx: undefined, + lang: undefined, + }, + ]); + }); + + it('sorts accountAddresses in the queryKey for stability', () => { + const result = + client.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions({ + accountAddresses: ['eip155:0:0xzzz', 'eip155:0:0xaaa'], + }); + + const keyObj = result.queryKey[3]; + expect(keyObj).toMatchObject({ + accountAddresses: ['eip155:0:0xaaa', 'eip155:0:0xzzz'], + }); + }); + + it('sorts networks in the queryKey for stability', () => { + const result = + client.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions({ + accountAddresses: ['eip155:0:0xabc'], + networks: ['eip155:137', 'eip155:1'], + }); + + const keyObj = result.queryKey[3]; + expect(keyObj).toMatchObject({ + networks: ['eip155:1', 'eip155:137'], + }); + }); + + it('uses STALE_TIMES.TRANSACTIONS and GC_TIMES.DEFAULT by default', () => { + const result = + client.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions({ + accountAddresses: ['eip155:0:0xabc'], + }); + + expect(result.staleTime).toBe(30 * 1000); + expect(result.gcTime).toBe(5 * 60 * 1000); + }); + + it('allows overriding staleTime and gcTime via options', () => { + const result = + client.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions( + { accountAddresses: ['eip155:0:0xabc'] }, + { staleTime: 60_000, gcTime: 120_000 }, + ); + + expect(result.staleTime).toBe(60_000); + expect(result.gcTime).toBe(120_000); + }); + }); }); describe('Relationships', () => { diff --git a/packages/core-backend/src/api/accounts/client.ts b/packages/core-backend/src/api/accounts/client.ts index 166b02acf00..d67064c779b 100644 --- a/packages/core-backend/src/api/accounts/client.ts +++ b/packages/core-backend/src/api/accounts/client.ts @@ -12,6 +12,7 @@ */ import type { + FetchInfiniteQueryOptions, FetchQueryOptions, QueryFunctionContext, } from '@tanstack/query-core'; @@ -757,6 +758,99 @@ export class AccountsApiClient extends BaseApiClient { }; } + /** + * Returns TanStack Query options for v4 multi-account transactions, + * designed for use with `useInfiniteQuery`. + * + * @param params - API endpoint parameters (excluding pagination cursors). + * @param params.accountAddresses - Array of CAIP-10 account addresses. + * @param params.networks - CAIP-2 network IDs to filter by. + * @param params.startTimestamp - Start timestamp (epoch). + * @param params.endTimestamp - End timestamp (epoch). + * @param params.limit - Max transactions per page (default 50). + * @param params.sortDirection - Sort direction (ASC/DESC). + * @param params.includeLogs - Whether to include logs. + * @param params.includeTxMetadata - Whether to include transaction metadata. + * @param params.maxLogsPerTx - Max logs per transaction. + * @param params.lang - Language for transaction category (default "en"). + * @param options - Fetch options including cache settings. + * @returns Options object compatible with `useInfiniteQuery`. + */ + getV4MultiAccountTransactionsInfiniteQueryOptions( + params: { + accountAddresses: string[]; + networks?: string[]; + startTimestamp?: number; + endTimestamp?: number; + limit?: number; + sortDirection?: 'ASC' | 'DESC'; + includeLogs?: boolean; + includeTxMetadata?: boolean; + maxLogsPerTx?: number; + lang?: string; + }, + options?: FetchOptions, + ): FetchInfiniteQueryOptions< + V4MultiAccountTransactionsResponse, + Error, + V4MultiAccountTransactionsResponse, + readonly unknown[], + string | undefined + > { + return { + queryKey: [ + 'accounts', + 'transactions', + 'v4MultiAccount', + { + accountAddresses: [...params.accountAddresses].sort(), + networks: params.networks && [...params.networks].sort(), + startTimestamp: params.startTimestamp, + endTimestamp: params.endTimestamp, + limit: params.limit, + sortDirection: params.sortDirection, + includeLogs: params.includeLogs, + includeTxMetadata: params.includeTxMetadata, + maxLogsPerTx: params.maxLogsPerTx, + lang: params.lang, + }, + ] as const, + queryFn: ({ + pageParam, + signal, + }: { + pageParam?: string; + signal?: AbortSignal; + }) => + this.fetch( + API_URLS.ACCOUNTS, + '/v4/multiaccount/transactions', + { + signal, + params: { + accountAddresses: params.accountAddresses, + networks: params.networks, + startTimestamp: params.startTimestamp, + endTimestamp: params.endTimestamp, + cursor: pageParam, + limit: params.limit, + sortDirection: params.sortDirection, + includeLogs: params.includeLogs, + includeTxMetadata: params.includeTxMetadata, + maxLogsPerTx: params.maxLogsPerTx, + lang: params.lang, + }, + }, + ), + getNextPageParam: ({ pageInfo }: V4MultiAccountTransactionsResponse) => + pageInfo.hasNextPage ? pageInfo.endCursor : undefined, + initialPageParam: options?.initialPageParam, + ...getQueryOptionsOverrides(options), + staleTime: options?.staleTime ?? STALE_TIMES.TRANSACTIONS, + gcTime: options?.gcTime ?? GC_TIMES.DEFAULT, + }; + } + /** * Get multi-account transactions (v4 endpoint). *