diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 48aac5059e6..895eb76ab66 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -12,7 +12,7 @@ import { import { arrayify, hexlify, DateTime } from '@fuel-ts/utils'; import { checkFuelCoreVersionCompatibility } from '@fuel-ts/versions'; import { equalBytes } from '@noble/curves/abstract/utils'; -import type { DocumentNode } from 'graphql'; +import type { DocumentNode, GraphQLError } from 'graphql'; import { GraphQLClient } from 'graphql-request'; import type { GraphQLResponse } from 'graphql-request/src/types'; import { clone } from 'ramda'; @@ -404,7 +404,30 @@ export default class Provider { fullRequest = await options.requestMiddleware(fullRequest); } - return options.fetch ? options.fetch(url, fullRequest, options) : fetch(url, fullRequest); + const response = await (options.fetch + ? options.fetch(url, fullRequest, options) + : fetch(url, fullRequest)); + + const body = await response.clone().json(); + + if (Array.isArray(body.errors)) { + console.log('got the resposne'); + + const error: GraphQLError = body.errors[0]; + let fuelError: FuelError = new FuelError(ErrorCode.UNKNOWN, '', undefined, error); + if (error) { + switch (error.message) { + case 'not enough coins to fit the target': + fuelError = new FuelError(ErrorCode.NOT_ENOUGH_COINS, ''); + break; + default: + break; + } + } + throw fuelError; + } + + return response; }, retryOptions); } @@ -552,12 +575,17 @@ Supported fuel-core version: ${supportedVersion}.` responseMiddleware: (response: GraphQLResponse | Error) => { if ('response' in response) { const graphQlResponse = response.response as GraphQLResponse; - if (Array.isArray(graphQlResponse?.errors)) { - throw new FuelError( - FuelError.CODES.INVALID_REQUEST, - graphQlResponse.errors.map((err: Error) => err.message).join('\n\n') - ); - } + const error = graphQlResponse.errors?.[0]; + + // if (Array.isArray(graphQlResponse?.errors)) { + // console.log(graphQlResponse.errors); + // throw new FuelError( + // FuelError.CODES.INVALID_REQUEST, + // graphQlResponse.errors.map((err: Error) => err.message).join('\n\n'), + // undefined, + // graphQlResponse.errors[0] + // ); + // } } }, }); diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index ff92629a3ab..55fd3df35d5 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -101,6 +101,9 @@ export enum ErrorCode { // graphql STREAM_PARSING_ERROR = 'stream-parsing-error', + // VM Errors + NOT_ENOUGH_COINS = 'not-enough-coins', + // Unknown UNKNOWN = 'unknown', } diff --git a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts index 32965c971dd..d431e975a42 100644 --- a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts @@ -1,4 +1,5 @@ -import { Contract, Wallet } from 'fuels'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; +import { Contract, ErrorCode, FuelError, Wallet } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; import { @@ -64,8 +65,13 @@ describe('Predicate', () => { // calling the contract with the receiver account (no resources) contract.account = receiver; - await expect(contract.functions.mint_coins(200).call()).rejects.toThrow( - /not enough coins to fit the target/ + + await contract.functions.mint_coins(200).call(); + await expectToThrowFuelError( + () => contract.functions.mint_coins(200).call(), + new FuelError(ErrorCode.NOT_ENOUGH_COINS, '', undefined, { + message: 'not enough coins to fit the target', + }) ); // setup predicate diff --git a/packages/fuel-gauge/src/vm-error-mappings.test.ts b/packages/fuel-gauge/src/vm-error-mappings.test.ts new file mode 100644 index 00000000000..c32af6ced89 --- /dev/null +++ b/packages/fuel-gauge/src/vm-error-mappings.test.ts @@ -0,0 +1,25 @@ +import { expectToThrowFuelError, safeExec } from '@fuel-ts/errors/test-utils'; +import { ErrorCode, FuelError, WalletUnlocked } from 'fuels'; +import { launchTestNode } from 'fuels/test-utils'; + +describe('vm error mappings', () => { + test.each([false])( + 'not enough coins to fit the target (subscription: %s)', + async (awaitExecution) => { + using launched = await launchTestNode(); + + const { provider } = launched; + + const sender = WalletUnlocked.generate({ provider }); + const receiver = WalletUnlocked.generate(); + const tx = await sender.createTransfer(receiver.address, 10); + + await provider.sendTransaction(tx, { awaitExecution }); + + // await expectToThrowFuelError( + // () => provider.sendTransaction(tx, { awaitExecution }), + // new FuelError(ErrorCode.NOT_ENOUGH_COINS, '') + // ); + } + ); +});