diff --git a/.changeset/odd-bears-drive.md b/.changeset/odd-bears-drive.md new file mode 100644 index 00000000000..52940926de7 --- /dev/null +++ b/.changeset/odd-bears-drive.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": minor +--- + +chore!: limit TX pagination number for `getTransactionsSummaries` diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 6eabf92c7e1..6350737c0a6 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -62,6 +62,7 @@ import { import type { RetryOptions } from './utils/auto-retry-fetch'; import { autoRetryFetch } from './utils/auto-retry-fetch'; import { handleGqlErrorMessage } from './utils/handle-gql-error-message'; +import { validatePaginationArgs } from './utils/validate-pagination-args'; const MAX_RETRIES = 10; @@ -1407,7 +1408,7 @@ Supported fuel-core version: ${supportedVersion}.` const { coins: { edges, pageInfo }, } = await this.operations.getCoins({ - ...this.validatePaginationArgs({ + ...validatePaginationArgs({ paginationLimit: RESOURCES_PAGE_SIZE_LIMIT, inputArgs: paginationArgs, }), @@ -1575,7 +1576,7 @@ Supported fuel-core version: ${supportedVersion}.` const { blocks: { edges, pageInfo }, } = await this.operations.getBlocks({ - ...this.validatePaginationArgs({ + ...validatePaginationArgs({ paginationLimit: BLOCKS_PAGE_SIZE_LIMIT, inputArgs: params, }), @@ -1686,7 +1687,7 @@ Supported fuel-core version: ${supportedVersion}.` const { transactions: { edges, pageInfo }, } = await this.operations.getTransactions({ - ...this.validatePaginationArgs({ + ...validatePaginationArgs({ inputArgs: paginationArgs, paginationLimit: TRANSACTIONS_PAGE_SIZE_LIMIT, }), @@ -1806,7 +1807,7 @@ Supported fuel-core version: ${supportedVersion}.` const { messages: { edges, pageInfo }, } = await this.operations.getMessages({ - ...this.validatePaginationArgs({ + ...validatePaginationArgs({ inputArgs: paginationArgs, paginationLimit: RESOURCES_PAGE_SIZE_LIMIT, }), @@ -2103,52 +2104,6 @@ Supported fuel-core version: ${supportedVersion}.` return relayedTransactionStatus; } - /** - * @hidden - */ - private validatePaginationArgs(params: { - inputArgs?: CursorPaginationArgs; - paginationLimit: number; - }): CursorPaginationArgs { - const { paginationLimit, inputArgs = {} } = params; - const { first, last, after, before } = inputArgs; - - if (after && before) { - throw new FuelError( - ErrorCode.INVALID_INPUT_PARAMETERS, - 'Pagination arguments "after" and "before" cannot be used together' - ); - } - - if ((first || 0) > paginationLimit || (last || 0) > paginationLimit) { - throw new FuelError( - ErrorCode.INVALID_INPUT_PARAMETERS, - `Pagination limit for this query cannot exceed ${paginationLimit} items` - ); - } - - if (first && before) { - throw new FuelError( - ErrorCode.INVALID_INPUT_PARAMETERS, - 'The use of pagination argument "first" with "before" is not supported' - ); - } - - if (last && after) { - throw new FuelError( - ErrorCode.INVALID_INPUT_PARAMETERS, - 'The use of pagination argument "last" with "after" is not supported' - ); - } - - // If neither first nor last is provided, set a default first value - if (!first && !last) { - inputArgs.first = paginationLimit; - } - - return inputArgs; - } - /** * @hidden */ diff --git a/packages/account/src/providers/transaction-summary/get-transaction-summary.ts b/packages/account/src/providers/transaction-summary/get-transaction-summary.ts index b7af213dada..788a42686cb 100644 --- a/packages/account/src/providers/transaction-summary/get-transaction-summary.ts +++ b/packages/account/src/providers/transaction-summary/get-transaction-summary.ts @@ -8,9 +8,10 @@ import type { GqlReceiptFragment, } from '../__generated__/operations'; import type Provider from '../provider'; -import type { PageInfo } from '../provider'; +import { TRANSACTIONS_PAGE_SIZE_LIMIT, type PageInfo } from '../provider'; import type { TransactionRequest } from '../transaction-request'; import type { TransactionResult } from '../transaction-response'; +import { validatePaginationArgs } from '../utils/validate-pagination-args'; import { assembleTransactionSummary } from './assemble-transaction-summary'; import { processGqlReceipt } from './receipt'; @@ -142,7 +143,17 @@ export async function getTransactionsSummaries( ): Promise { const { filters, provider, abiMap } = params; - const { transactionsByOwner } = await provider.operations.getTransactionsByOwner(filters); + const { owner, ...inputArgs } = filters; + + const validPaginationParams = validatePaginationArgs({ + inputArgs, + paginationLimit: TRANSACTIONS_PAGE_SIZE_LIMIT, + }); + + const { transactionsByOwner } = await provider.operations.getTransactionsByOwner({ + ...validPaginationParams, + owner, + }); const { edges, pageInfo } = transactionsByOwner; diff --git a/packages/account/src/providers/utils/validate-pagination-args.ts b/packages/account/src/providers/utils/validate-pagination-args.ts new file mode 100644 index 00000000000..ccd9def0347 --- /dev/null +++ b/packages/account/src/providers/utils/validate-pagination-args.ts @@ -0,0 +1,49 @@ +import { FuelError, ErrorCode } from '@fuel-ts/errors'; + +import type { CursorPaginationArgs } from '../provider'; + +/** + * @hidden + */ +export const validatePaginationArgs = (params: { + inputArgs?: CursorPaginationArgs; + paginationLimit: number; +}): CursorPaginationArgs => { + const { paginationLimit, inputArgs = {} } = params; + const { first, last, after, before } = inputArgs; + + if (after && before) { + throw new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + 'Pagination arguments "after" and "before" cannot be used together' + ); + } + + if ((first || 0) > paginationLimit || (last || 0) > paginationLimit) { + throw new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + `Pagination limit for this query cannot exceed ${paginationLimit} items` + ); + } + + if (first && before) { + throw new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + 'The use of pagination argument "first" with "before" is not supported' + ); + } + + if (last && after) { + throw new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + 'The use of pagination argument "last" with "after" is not supported' + ); + } + + // If neither first nor last is provided, set a default first value + if (!first && !last) { + inputArgs.first = paginationLimit; + } + + return inputArgs; +}; diff --git a/packages/fuel-gauge/src/transaction-summary.test.ts b/packages/fuel-gauge/src/transaction-summary.test.ts index c8476575a2d..ca8d53e9acd 100644 --- a/packages/fuel-gauge/src/transaction-summary.test.ts +++ b/packages/fuel-gauge/src/transaction-summary.test.ts @@ -20,8 +20,17 @@ import { ChainName, bn, OutputType, + TRANSACTIONS_PAGE_SIZE_LIMIT, + FuelError, + ErrorCode, } from 'fuels'; -import { ASSET_A, ASSET_B, launchTestNode, TestMessage } from 'fuels/test-utils'; +import { + ASSET_A, + ASSET_B, + expectToThrowFuelError, + launchTestNode, + TestMessage, +} from 'fuels/test-utils'; import { MultiTokenContractFactory, TokenContractFactory } from '../test/typegen'; import type { ContractIdInput, TransferParamsInput } from '../test/typegen/contracts/TokenContract'; @@ -164,6 +173,56 @@ describe('TransactionSummary', () => { }); }); + it('should ensure getTransactionsSummaries limits TX pagination number', async () => { + using launched = await launchTestNode(); + + const { + provider, + wallets: [sender], + } = launched; + + await expectToThrowFuelError( + () => + getTransactionsSummaries({ + provider, + filters: { + first: TRANSACTIONS_PAGE_SIZE_LIMIT + 1, + owner: sender.address.toB256(), + }, + }), + new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + 'Pagination limit for this query cannot exceed 60 items' + ) + ); + + await expectToThrowFuelError( + () => + getTransactionsSummaries({ + provider, + filters: { + last: TRANSACTIONS_PAGE_SIZE_LIMIT + 1, + owner: sender.address.toB256(), + }, + }), + new FuelError( + ErrorCode.INVALID_INPUT_PARAMETERS, + 'Pagination limit for this query cannot exceed 60 items' + ) + ); + + // When using limit it should work + await expect( + getTransactionsSummaries({ + provider, + filters: { + last: TRANSACTIONS_PAGE_SIZE_LIMIT, + owner: sender.address.toB256(), + }, + }) + ).resolves.toBeDefined(); + }); + it('should ensure getTransactionSummaryFromRequest executes just fine [TX REQUEST]', async () => { using launched = await launchTestNode();