diff --git a/.changeset/honest-fishes-mix.md b/.changeset/honest-fishes-mix.md new file mode 100644 index 00000000000..f381e3e9939 --- /dev/null +++ b/.changeset/honest-fishes-mix.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/account": patch +"@fuel-ts/errors": patch +--- + +chore: handle exceeding maximum inputs when funding a transaction \ No newline at end of file diff --git a/apps/docs/src/guide/errors/index.md b/apps/docs/src/guide/errors/index.md index af55d41ce4f..fe61222a90a 100644 --- a/apps/docs/src/guide/errors/index.md +++ b/apps/docs/src/guide/errors/index.md @@ -298,3 +298,7 @@ The purpose of the lock function is to provide a way to ensure that the implemen In cases where the error hasn't been mapped yet, this code will be used. If you believe you found a bug, please report the [issue](https://github.com/FuelLabs/fuels-ts/issues/new/choose) to the team. + +### `MAX_INPUTS_EXCEEDED` + +When the number of transaction inputs exceeds the maximum limit allowed by the blockchain. \ No newline at end of file diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 167a58308e9..83830bdc0a6 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -8,7 +8,7 @@ import { BN, bn } from '@fuel-ts/math'; import type { Receipt } from '@fuel-ts/transactions'; import { InputType, ReceiptType, TransactionType } from '@fuel-ts/transactions'; import { DateTime, arrayify, sleep } from '@fuel-ts/utils'; -import { ASSET_A } from '@fuel-ts/utils/test-utils'; +import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; import { versions } from '@fuel-ts/versions'; import * as fuelTsVersionsMod from '@fuel-ts/versions'; @@ -26,6 +26,7 @@ import { import { Wallet } from '../wallet'; import type { Coin } from './coin'; +import { coinQuantityfy } from './coin-quantity'; import type { ChainInfo, CursorPaginationArgs, NodeInfo } from './provider'; import Provider, { BLOCKS_PAGE_SIZE_LIMIT, @@ -33,7 +34,7 @@ import Provider, { RESOURCES_PAGE_SIZE_LIMIT, } from './provider'; import type { CoinTransactionRequestInput } from './transaction-request'; -import { ScriptTransactionRequest, CreateTransactionRequest } from './transaction-request'; +import { CreateTransactionRequest, ScriptTransactionRequest } from './transaction-request'; import { TransactionResponse } from './transaction-response'; import type { SubmittedStatus } from './transaction-summary/types'; import * as gasMod from './utils/gas'; @@ -541,6 +542,59 @@ describe('Provider', () => { }); }); + it('should throws if max of inputs was exceeded', async () => { + const maxInputs = 2; + using launched = await setupTestProviderAndWallets({ + nodeOptions: { + snapshotConfig: { + chainConfig: { + consensus_parameters: { + V1: { + tx_params: { + V1: { + max_inputs: maxInputs, + }, + }, + }, + }, + }, + }, + }, + walletsConfig: { + amountPerCoin: 500_000, + }, + }); + + const { + wallets: [sender, receiver], + provider, + } = launched; + + const request = new ScriptTransactionRequest(); + + const quantities = [coinQuantityfy([1000, ASSET_A]), coinQuantityfy([500, ASSET_B])]; + const resources = await sender.getResourcesToSpend(quantities); + + request.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); + + const txCost = await sender.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + request.addResources(resources); + + await sender.fund(request, txCost); + + await expectToThrowFuelError( + () => sender.sendTransaction(request), + new FuelError( + ErrorCode.MAX_INPUTS_EXCEEDED, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ) + ); + }); + it('can getBlocks', async () => { using launched = await setupTestProviderAndWallets(); const blocksLenght = 5; diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 1d514c4ec6b..e6f155be09d 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -695,6 +695,15 @@ Supported fuel-core version: ${supportedVersion}.` }); } + private validateTransaction(tx: TransactionRequest, consensusParameters: ConsensusParameters) { + if (bn(tx.inputs.length).gt(consensusParameters.txParameters.maxInputs)) { + throw new FuelError( + ErrorCode.MAX_INPUTS_EXCEEDED, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ); + } + } + /** * Submits a transaction to the chain to be executed. * @@ -716,6 +725,10 @@ Supported fuel-core version: ${supportedVersion}.` } // #endregion Provider-sendTransaction + const { consensusParameters } = this.getChain(); + + this.validateTransaction(transactionRequest, consensusParameters); + const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); let abis: JsonAbisFromAllCalls | undefined; diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index 5b790cb9a91..a8a7d51305c 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -77,6 +77,7 @@ export enum ErrorCode { DUPLICATED_POLICY = 'duplicated-policy', TRANSACTION_SQUEEZED_OUT = 'transaction-squeezed-out', CONTRACT_SIZE_EXCEEDS_LIMIT = 'contract-size-exceeds-limit', + MAX_INPUTS_EXCEEDED = 'max-inputs-exceeded', // receipt INVALID_RECEIPT_TYPE = 'invalid-receipt-type',