Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: map 'not enough coins' error #2902

Merged
merged 39 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
569ba6c
feat: map 'not enough coins' error
Dhaiwat10 Aug 9, 2024
71bff41
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 9, 2024
e0d830e
add testing group
Dhaiwat10 Aug 9, 2024
845781e
Merge branch 'dp/not-enough-coins-error' of https://github.com/FuelLa…
Dhaiwat10 Aug 9, 2024
d1fc6db
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 12, 2024
3eb52da
handle multiple errors properly
Dhaiwat10 Aug 12, 2024
e02ff40
update tests
Dhaiwat10 Aug 12, 2024
e788395
update test
Dhaiwat10 Aug 12, 2024
ecbb25c
add `rawError` metadata
Dhaiwat10 Aug 12, 2024
aeed799
add docs
Dhaiwat10 Aug 12, 2024
3acb9b9
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 12, 2024
2f07f9a
Update handle-gql-error-message.ts
Dhaiwat10 Aug 12, 2024
b7b5723
Merge branch 'dp/not-enough-coins-error' of https://github.com/FuelLa…
Dhaiwat10 Aug 12, 2024
52fca3b
update test
Dhaiwat10 Aug 12, 2024
eb681e8
add description to docs for the error
Dhaiwat10 Aug 13, 2024
d49119f
remove 'unknown error' prefix
Dhaiwat10 Aug 13, 2024
907e62c
update error msg
Dhaiwat10 Aug 13, 2024
c700357
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 13, 2024
ac1493c
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 13, 2024
d8a7929
remove from gql subscriber
Dhaiwat10 Aug 13, 2024
3084cca
assert `FuelError`s instead of plain errors
Dhaiwat10 Aug 13, 2024
1f7138d
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 14, 2024
a8a48c7
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 21, 2024
9b29d41
missing imports
Dhaiwat10 Aug 21, 2024
f326d63
set rawError to null
Dhaiwat10 Aug 21, 2024
74bc337
missing {
Dhaiwat10 Aug 21, 2024
14e365d
update error msg
Dhaiwat10 Aug 21, 2024
72ca379
fix tests
Dhaiwat10 Aug 21, 2024
e270ccd
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 21, 2024
6816f77
Merge branch 'master' into dp/not-enough-coins-error
danielbate Aug 22, 2024
0dfccd3
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 26, 2024
e351062
fix test
Dhaiwat10 Aug 28, 2024
e2c74bd
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Aug 28, 2024
68e9cd7
Merge branch 'master' into dp/not-enough-coins-error
maschad Aug 28, 2024
5c99b49
Merge branch 'master' into dp/not-enough-coins-error
Torres-ssf Aug 29, 2024
3eac820
reword docs
Dhaiwat10 Sep 3, 2024
0436a16
reword docs
Dhaiwat10 Sep 3, 2024
79dbdfe
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Sep 3, 2024
a4ba9bc
Merge branch 'master' into dp/not-enough-coins-error
Dhaiwat10 Sep 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/rare-shrimps-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/account": patch
"@fuel-ts/errors": patch
---

feat: map 'not enough coins' error
14 changes: 8 additions & 6 deletions apps/demo-bun-fuels/src/bun.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* It ensures that built code is fully working.
*/

import { toHex, Wallet } from 'fuels';
import { launchTestNode, safeExec } from 'fuels/test-utils';
import { ErrorCode, FuelError, toHex, Wallet } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import { Sample, SampleFactory } from './sway-programs-api';

Expand Down Expand Up @@ -78,11 +78,13 @@ describe('ExampleContract', () => {

const contractInstance = new Sample(contract.id, unfundedWallet);

const { error } = await safeExec(() =>
contractInstance.functions.return_input(1337).simulate()
await expectToThrowFuelError(
() => contractInstance.functions.return_input(1337).simulate(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);

expect((<Error>error).message).toMatch('not enough coins to fit the target');
});

it('should not throw when dry running via contract factory with wallet with no resources', async () => {
Expand Down
14 changes: 8 additions & 6 deletions apps/demo-fuels/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* It ensures that built code is fully working.
*/

import { toHex, Wallet } from 'fuels';
import { launchTestNode, safeExec } from 'fuels/test-utils';
import { ErrorCode, FuelError, toHex, Wallet } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import { SampleFactory, Sample } from './sway-programs-api';

Expand Down Expand Up @@ -71,11 +71,13 @@ describe('ExampleContract', () => {

const contractInstance = new Sample(contract.id, unfundedWallet);

const { error } = await safeExec(() =>
contractInstance.functions.return_input(1337).simulate()
await expectToThrowFuelError(
() => contractInstance.functions.return_input(1337).simulate(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);

expect((<Error>error).message).toMatch('not enough coins to fit the target');
});

it('should not throw when dry running via contract factory with wallet with no resources', async () => {
Expand Down
14 changes: 9 additions & 5 deletions apps/demo-typegen/src/demo.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// #region Testing-in-ts-ts
import { toHex, Address, Wallet } from 'fuels';
import { launchTestNode, safeExec } from 'fuels/test-utils';
import { toHex, Address, Wallet, FuelError, ErrorCode } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import storageSlots from '../demo-contract/out/release/demo-contract-storage_slots.json';

Expand Down Expand Up @@ -105,9 +105,13 @@ it('should throw when simulating via contract factory with wallet with no resour
const { contract } = await waitForResult();
const contractInstance = new DemoContract(contract.id, unfundedWallet);

const { error } = await safeExec(() => contractInstance.functions.return_input(1337).simulate());

expect((<Error>error).message).toMatch('not enough coins to fit the target');
await expectToThrowFuelError(
() => contractInstance.functions.return_input(1337).simulate(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);
});

it('should not throw when dry running via contract factory with wallet with no resources', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('Send and Spend Funds from Predicates', () => {
);

// #region send-and-spend-funds-from-predicates-6
const errorMsg = 'not enough coins to fit the target';
const errorMsg = `The account(s) sending the transaction don't have enough funds to cover the transaction.`;
// #endregion send-and-spend-funds-from-predicates-6

expect((<Error>error).message).toMatch(errorMsg);
Expand Down
6 changes: 6 additions & 0 deletions apps/docs/src/guide/errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ When the Fuel Node info cache is empty; This is usually caused by not being conn

Ensure that the provider has connected to a Fuel Node successfully.

### `NOT_ENOUGH_FUNDS`

When the account sending the transaction does not have enough funds to cover the fee.

Ensure that the account creating the transaction has been funded appropriately.

### `TIMEOUT_EXCEEDED`

When the timeout has been exceeded for a given operation.
Expand Down
6 changes: 2 additions & 4 deletions apps/docs/src/guide/wallets/wallet-transferring.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ Here's an example demonstrating how to use `transferToContract`:

Always remember to call the `waitForResult()` function on the transaction response. That ensures the transaction has been mined successfully before proceeding.


## Transferring Assets To Multiple Wallets

To transfer assets to multiple wallets, use the `Account.batchTransfer` method:
Expand All @@ -53,9 +52,8 @@ To transfer assets to multiple wallets, use the `Account.batchTransfer` method:

This section demonstrates additional examples of transferring assets between wallets and to contracts.


## Checking Balances

Before transferring assets, ensure your wallet has sufficient funds. Attempting a transfer without enough funds will result in an error: `not enough coins to fit the target`.
Before you transfer assets, please make sure your wallet has enough funds. Attempting a transfer without enough funds will result in the error: `The transaction does not have enough funds to cover its execution.`

You can see how to check your balance at the [`checking-balances`](./checking-balances.md) page.
You can see how to check your balance at the [`checking-balances`](./checking-balances.md) page.
12 changes: 7 additions & 5 deletions packages/account/src/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,11 +523,13 @@ describe('Account', () => {
}

// Test excludes the UTXO where the assetIdA gets added to the senders wallet
await expect(
user.getResourcesToSpend([[1, ASSET_A, 500_000]], {
utxos: [assetAUTXO.id],
})
).rejects.toThrow(/not enough coins to fit the target/);
await expectToThrowFuelError(
() => user.getResourcesToSpend([[1, ASSET_A, 500_000]], { utxos: [assetAUTXO.id] }),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);
});

it('can transfer multiple types of coins to multiple destinations', async () => {
Expand Down
9 changes: 5 additions & 4 deletions packages/account/src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import {
} from './utils';
import type { RetryOptions } from './utils/auto-retry-fetch';
import { autoRetryFetch } from './utils/auto-retry-fetch';
import { handleGqlErrorMessage } from './utils/handle-gql-error-message';

const MAX_RETRIES = 10;

Expand Down Expand Up @@ -605,11 +606,11 @@ Supported fuel-core version: ${supportedVersion}.`
responseMiddleware: (response: GraphQLResponse<unknown> | 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')
);
for (const error of graphQlResponse.errors) {
handleGqlErrorMessage(error.message, error);
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { GraphQLError } from 'graphql';

export enum GqlErrorMessage {
NOT_ENOUGH_COINS = 'not enough coins to fit the target',
}

export const handleGqlErrorMessage = (errorMessage: string, rawError: GraphQLError) => {
switch (errorMessage) {
case GqlErrorMessage.NOT_ENOUGH_COINS:
throw new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`,
{},
rawError
);
default:
throw new FuelError(ErrorCode.INVALID_REQUEST, errorMessage);
}
};
2 changes: 1 addition & 1 deletion packages/errors/src/fuel-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ it('converts error to plain object', () => {
message,
VERSIONS: err.VERSIONS,
metadata,
rawError: {},
rawError: null,
});
});
2 changes: 1 addition & 1 deletion packages/errors/src/fuel-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class FuelError extends Error {
code: ErrorCode,
message: string,
metadata: Record<string, unknown> = {},
rawError: unknown = {}
rawError: unknown = null
Dhaiwat10 marked this conversation as resolved.
Show resolved Hide resolved
) {
super(message);
this.code = code;
Expand Down
21 changes: 13 additions & 8 deletions packages/fuel-gauge/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -909,14 +909,19 @@ describe('Contract', () => {

contract.account = Wallet.generate({ provider: contract.provider });

await expect(
contract.functions
.return_context_amount()
.callParams({
forward: [100, contract.provider.getBaseAssetId()],
})
.simulate()
).rejects.toThrowError('not enough coins to fit the target');
await expectToThrowFuelError(
() =>
contract.functions
.return_context_amount()
.callParams({
forward: [100, contract.provider.getBaseAssetId()],
})
.simulate(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);
});

it('should throw when using "simulate" without a wallet', async () => {
Expand Down
16 changes: 15 additions & 1 deletion packages/fuel-gauge/src/funding-transaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,21 @@ describe('Funding Transactions', () => {
*/
await expectToThrowFuelError(
() => sender.fund(request, txCost),
new FuelError(FuelError.CODES.INVALID_REQUEST, 'not enough coins to fit the target')
new FuelError(
FuelError.CODES.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`,
{},
{
locations: [
{
column: 3,
line: 2,
},
],
message: 'not enough coins to fit the target',
path: ['coinsToSpend'],
}
)
);

expect(getResourcesToSpend).toHaveBeenCalled();
Expand Down
22 changes: 22 additions & 0 deletions packages/fuel-gauge/src/not-enough-coins.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Contract, ErrorCode, Wallet } from 'fuels';
import { expectToThrowFuelError } from 'fuels/test-utils';

import { CallTestContractFactory } from '../test/typegen/contracts';

import { launchTestContract } from './utils';

/**
* @group node
*/
test('not enough coins error', async () => {
using contract = await launchTestContract({ factory: CallTestContractFactory });

const emptyWallet = Wallet.generate({ provider: contract.provider });

const emptyWalletContract = new Contract(contract.id, contract.interface.jsonAbi, emptyWallet);

await expectToThrowFuelError(() => emptyWalletContract.functions.return_void().call(), {
code: ErrorCode.NOT_ENOUGH_FUNDS,
message: `The account(s) sending the transaction don't have enough funds to cover the transaction.`,
});
});
27 changes: 16 additions & 11 deletions packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Predicate, Wallet } from 'fuels';
import { launchTestNode } from 'fuels/test-utils';
import { ErrorCode, FuelError, Predicate, Wallet } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import { PredicateMainArgsStruct } from '../../test/typegen';
import type { Validation } from '../types/predicate';
Expand Down Expand Up @@ -29,16 +29,21 @@ describe('Predicate', () => {

const receiver = Wallet.generate({ provider });

await expect(
predicate.transfer(
receiver.address,
await predicate.getBalance(),
provider.getBaseAssetId(),
{
gasLimit: 100_000_000,
}
await expectToThrowFuelError(
async () =>
predicate.transfer(
receiver.address,
await predicate.getBalance(),
provider.getBaseAssetId(),
{
gasLimit: 100_000_000,
}
),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
).rejects.toThrow(/not enough coins to fit the target/i);
);
});

it('throws if the passed gas limit is too low', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Contract, Wallet } from 'fuels';
import { launchTestNode } from 'fuels/test-utils';
import { Contract, ErrorCode, FuelError, Wallet } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import { CallTestContractFactory, TokenContractFactory } from '../../test/typegen/contracts';
import { PredicateMainArgsStruct, PredicateTrue } from '../../test/typegen/predicates';
Expand Down Expand Up @@ -59,8 +59,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 expectToThrowFuelError(
() => contract.functions.mint_coins(200).call(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);

// setup predicate
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { BigNumberish } from 'fuels';
import { toNumber, Script, Predicate, Wallet } from 'fuels';
import { launchTestNode } from 'fuels/test-utils';
import { toNumber, Script, Predicate, Wallet, FuelError, ErrorCode } from 'fuels';
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';

import { PredicateMainArgsStruct, ScriptMainArgs } from '../../test/typegen';
import type { Validation } from '../types/predicate';
Expand Down Expand Up @@ -33,8 +33,12 @@ describe('Predicate', () => {
const scriptInput = 1;
scriptInstance.account = receiver;

await expect(scriptInstance.functions.main(scriptInput).call()).rejects.toThrow(
/not enough coins to fit the target/
await expectToThrowFuelError(
() => scriptInstance.functions.main(scriptInput).call(),
new FuelError(
ErrorCode.NOT_ENOUGH_FUNDS,
`The account(s) sending the transaction don't have enough funds to cover the transaction.`
)
);

// setup predicate
Expand Down