From 47044a7f4fcc0ac93a61466aa9c6790ccc5d7ccb Mon Sep 17 00:00:00 2001 From: Anderson Arboleya Date: Mon, 14 Oct 2024 20:56:21 -0300 Subject: [PATCH 01/17] Upgrading `fuel-core` to `0.40.0` --- internal/fuel-core/VERSION | 2 +- packages/versions/src/lib/getBuiltinVersions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/fuel-core/VERSION b/internal/fuel-core/VERSION index 4ef2eb086f5..9b0025a7850 100644 --- a/internal/fuel-core/VERSION +++ b/internal/fuel-core/VERSION @@ -1 +1 @@ -0.39.0 +0.40.0 diff --git a/packages/versions/src/lib/getBuiltinVersions.ts b/packages/versions/src/lib/getBuiltinVersions.ts index 926fb6aa3f7..43aa49183dd 100644 --- a/packages/versions/src/lib/getBuiltinVersions.ts +++ b/packages/versions/src/lib/getBuiltinVersions.ts @@ -3,7 +3,7 @@ import type { Versions } from './types'; export function getBuiltinVersions(): Versions { return { FORC: '0.65.2', - FUEL_CORE: '0.39.0', + FUEL_CORE: '0.40.0', FUELS: '0.96.1', }; } From d6439bb39a82e806e6758c1ed4fccb02666320b9 Mon Sep 17 00:00:00 2001 From: Anderson Arboleya Date: Mon, 14 Oct 2024 20:56:58 -0300 Subject: [PATCH 02/17] Adding changeset --- .changeset/lucky-avocados-add.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/lucky-avocados-add.md diff --git a/.changeset/lucky-avocados-add.md b/.changeset/lucky-avocados-add.md new file mode 100644 index 00000000000..8da22c18cf5 --- /dev/null +++ b/.changeset/lucky-avocados-add.md @@ -0,0 +1,6 @@ +--- +"@internal/fuel-core": patch +"@fuel-ts/versions": patch +--- + +chore: upgrading `fuel-core` to `0.40.0` From 008a087f66c4a6c1af0dd6490744bc1532db8b61 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Tue, 15 Oct 2024 09:49:57 +0700 Subject: [PATCH 03/17] chore: rebuild From b4f65392fcfb3e10ebdb7f67aa2f5339a5970ce4 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Tue, 15 Oct 2024 13:51:03 +0700 Subject: [PATCH 04/17] test: fix provider input validation test --- packages/account/src/providers/provider.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index eea8adcd4e1..0cf32557666 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -867,11 +867,14 @@ describe('Provider', () => { request.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); request.addResources(resources); + const moreResources = await sender.getResourcesToSpend(quantities); + request.addResources(moreResources); + await expectToThrowFuelError( () => sender.sendTransaction(request), new FuelError( ErrorCode.MAX_INPUTS_EXCEEDED, - `The transaction exceeds the maximum allowed number of inputs. Tx inputs: ${quantities.length}, max inputs: ${maxInputs}` + `The transaction exceeds the maximum allowed number of inputs. Tx inputs: 4, max inputs: ${maxInputs}` ) ); }); From 0b05e6d31512614e9439cd73167b7563702667dd Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Tue, 15 Oct 2024 14:08:46 +0700 Subject: [PATCH 05/17] test: example of getCoinsToSpend throw --- packages/account/src/account.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 7e49d958516..043650f1ca4 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -924,6 +924,29 @@ describe('Account', () => { }); }); + it('invalid request with getCoinsToSpend', async () => { + using launched = await setupTestProviderAndWallets({ + walletsConfig: { + amountPerCoin: 100, + coinsPerAsset: 400, + }, + }); + const { + wallets: [wallet], + provider, + } = launched; + + expect(provider.getChain().consensusParameters.txParameters.maxInputs.toNumber()).toBe(255); + + await expectToThrowFuelError( + () => wallet.getResourcesToSpend([[30_000, provider.getBaseAssetId()]]), + { + code: ErrorCode.INVALID_REQUEST, + message: 'max number of coins is reached while trying to fit the target', + } + ); + }); + test('can properly use getBalances', async () => { const fundAmount = 10_000; From 8e98fdf290675c7e95a9b82337a5b29a3e6b2310 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Tue, 15 Oct 2024 14:59:12 +0700 Subject: [PATCH 06/17] test: update account test for max inputs --- packages/account/src/account.test.ts | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 043650f1ca4..cf3b93f43b4 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -899,7 +899,7 @@ describe('Account', () => { vi.restoreAllMocks(); }); - it('should validate max number of inputs when funding the TX', async () => { + it('throws when funding with more than 255 coins for an input', async () => { using launched = await setupTestProviderAndWallets({ walletsConfig: { amountPerCoin: 100, @@ -920,33 +920,11 @@ describe('Account', () => { request.maxFee = txCost.maxFee; await expectToThrowFuelError(() => wallet.fund(request, txCost), { - code: ErrorCode.MAX_INPUTS_EXCEEDED, + code: ErrorCode.INVALID_REQUEST, + message: 'max number of coins is reached while trying to fit the target', }); }); - it('invalid request with getCoinsToSpend', async () => { - using launched = await setupTestProviderAndWallets({ - walletsConfig: { - amountPerCoin: 100, - coinsPerAsset: 400, - }, - }); - const { - wallets: [wallet], - provider, - } = launched; - - expect(provider.getChain().consensusParameters.txParameters.maxInputs.toNumber()).toBe(255); - - await expectToThrowFuelError( - () => wallet.getResourcesToSpend([[30_000, provider.getBaseAssetId()]]), - { - code: ErrorCode.INVALID_REQUEST, - message: 'max number of coins is reached while trying to fit the target', - } - ); - }); - test('can properly use getBalances', async () => { const fundAmount = 10_000; From 6bbcae0b53a05874c53e0f57e5b1c103f01d0406 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Tue, 15 Oct 2024 15:24:35 +0700 Subject: [PATCH 07/17] test: add doc --- packages/account/src/providers/provider.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 0cf32557666..f0042b90ad0 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -867,6 +867,9 @@ describe('Provider', () => { request.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); request.addResources(resources); + // We need to add more resources manually here as a single `getResourcesToSpend` call + // will always truncate to `maxInputs`. So we need to add more resources manually + // to test our validation logic. const moreResources = await sender.getResourcesToSpend(quantities); request.addResources(moreResources); From 71868313da69cbff9388229cf60662a84fd03485 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 11:04:35 +0700 Subject: [PATCH 08/17] feat: map max coins reached error --- packages/account/src/account.test.ts | 5 +- .../utils/handle-gql-error-message.ts | 8 +++ packages/errors/src/error-codes.ts | 2 +- .../src/mapped-error-messages.test.ts | 50 +++++++++++++++++++ .../fuel-gauge/src/not-enough-coins.test.ts | 22 -------- 5 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 packages/fuel-gauge/src/mapped-error-messages.test.ts delete mode 100644 packages/fuel-gauge/src/not-enough-coins.test.ts diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index cf3b93f43b4..0a64bbc3417 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -920,8 +920,9 @@ describe('Account', () => { request.maxFee = txCost.maxFee; await expectToThrowFuelError(() => wallet.fund(request, txCost), { - code: ErrorCode.INVALID_REQUEST, - message: 'max number of coins is reached while trying to fit the target', + code: ErrorCode.MAX_COINS_REACHED, + message: + 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', }); }); diff --git a/packages/account/src/providers/utils/handle-gql-error-message.ts b/packages/account/src/providers/utils/handle-gql-error-message.ts index 9f19a2f53b9..8aeefa5af9e 100644 --- a/packages/account/src/providers/utils/handle-gql-error-message.ts +++ b/packages/account/src/providers/utils/handle-gql-error-message.ts @@ -3,6 +3,7 @@ import type { GraphQLError } from 'graphql'; export enum GqlErrorMessage { NOT_ENOUGH_COINS = 'not enough coins to fit the target', + MAX_COINS_REACHED = 'max number of coins is reached while trying to fit the target', } export const handleGqlErrorMessage = (errorMessage: string, rawError: GraphQLError) => { @@ -14,6 +15,13 @@ export const handleGqlErrorMessage = (errorMessage: string, rawError: GraphQLErr {}, rawError ); + case GqlErrorMessage.MAX_COINS_REACHED: + throw new FuelError( + ErrorCode.MAX_COINS_REACHED, + 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', + {}, + rawError + ); default: throw new FuelError(ErrorCode.INVALID_REQUEST, errorMessage); } diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index 151235770bd..76f6e8aae80 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -85,7 +85,7 @@ export enum ErrorCode { MAX_INPUTS_EXCEEDED = 'max-inputs-exceeded', FUNDS_TOO_LOW = 'funds-too-low', MAX_OUTPUTS_EXCEEDED = 'max-outputs-exceeded', - + MAX_COINS_REACHED = 'max-coins-reached', // receipt INVALID_RECEIPT_TYPE = 'invalid-receipt-type', diff --git a/packages/fuel-gauge/src/mapped-error-messages.test.ts b/packages/fuel-gauge/src/mapped-error-messages.test.ts new file mode 100644 index 00000000000..7f23eaccab8 --- /dev/null +++ b/packages/fuel-gauge/src/mapped-error-messages.test.ts @@ -0,0 +1,50 @@ +import { Contract, ErrorCode, ScriptTransactionRequest, Wallet } from 'fuels'; +import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils'; + +import { CallTestContractFactory } from '../test/typegen/contracts'; + +import { launchTestContract } from './utils'; + +/** + * @group node + * @group browser + */ +describe('mapped error messages', () => { + 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.`, + }); + }); + + test('max coins reached error', async () => { + using launched = await launchTestNode({ + walletsConfig: { + amountPerCoin: 1, + coinsPerAsset: 256, + }, + }); + const { + wallets: [wallet], + } = launched; + + const request = new ScriptTransactionRequest(); + request.addCoinOutput(wallet.address, 256, wallet.provider.getBaseAssetId()); + const txCost = await wallet.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await expectToThrowFuelError(() => wallet.fund(request, txCost), { + code: ErrorCode.MAX_COINS_REACHED, + message: + 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', + }); + }); +}); diff --git a/packages/fuel-gauge/src/not-enough-coins.test.ts b/packages/fuel-gauge/src/not-enough-coins.test.ts deleted file mode 100644 index 273d7263426..00000000000 --- a/packages/fuel-gauge/src/not-enough-coins.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -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.`, - }); -}); From 6bb694baa65dfa95b70e3889e6c72638535e3134 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 13:43:14 +0700 Subject: [PATCH 09/17] chore: update changeset --- .changeset/lucky-avocados-add.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.changeset/lucky-avocados-add.md b/.changeset/lucky-avocados-add.md index 8da22c18cf5..25355bc1eeb 100644 --- a/.changeset/lucky-avocados-add.md +++ b/.changeset/lucky-avocados-add.md @@ -1,6 +1,8 @@ --- "@internal/fuel-core": patch "@fuel-ts/versions": patch +"@fuel-ts/account": patch +"@fuel-ts/errors": patch --- chore: upgrading `fuel-core` to `0.40.0` From b469bef02e50a2f2a57cb7428096b1839b195cb3 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 14:20:13 +0700 Subject: [PATCH 10/17] docs: add a cookbook for combining UTXOs --- .../guide/cookbook/combining-utxos.test.ts | 65 +++++++++++++++++++ apps/docs/.vitepress/config.ts | 4 ++ .../src/guide/cookbook/combining-utxos.md | 11 ++++ apps/docs/src/guide/errors/index.md | 6 ++ packages/account/src/account.test.ts | 2 +- .../utils/handle-gql-error-message.ts | 2 +- .../src/mapped-error-messages.test.ts | 2 +- 7 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts create mode 100644 apps/docs/src/guide/cookbook/combining-utxos.md diff --git a/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts b/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts new file mode 100644 index 00000000000..7901ea4685f --- /dev/null +++ b/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts @@ -0,0 +1,65 @@ +import { Provider, Wallet } from 'fuels'; +import { launchTestNode } from 'fuels/test-utils'; + +/** + * @group node + * @group browser + */ +describe('Combining UTXOs', () => { + it('Combines UTXOs', async () => { + using launched = await launchTestNode(); + + const { + provider: testProvider, + wallets: [testWallet], + } = launched; + const providerUrl = testProvider.url; + const WALLET_PVT_KEY = testWallet.privateKey; + + // #region combining-utxos + const provider = await Provider.create(providerUrl); + const fundingWallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); + const wallet = Wallet.generate({ provider }); + + // First, lets fund a wallet with 10_000 of the base asset. But as we are doing this across 10 transactions, + // we will end up with 10 UTXOs. + for (let i = 0; i < 10; i++) { + const initTx = await fundingWallet.transfer(wallet.address, 1000, provider.getBaseAssetId()); + await initTx.waitForResult(); + } + + // We can fetch the coins to see how many UTXOs we have, and confirm it is 10. + const { coins: initialCoins } = await wallet.getCoins(provider.getBaseAssetId()); + console.log('Initial Coins Length', initialCoins.length); + // 10 + + // But we can also confirm the total balance of the base asset for this account is 10_000. + const initialBalance = await wallet.getBalance(provider.getBaseAssetId()); + console.log('Initial Balance', initialBalance.toNumber()); + // 10_000 + + // Now we can combine the UTXOs into a single UTXO by performing a single transfer for the + // majority of the balance. Of course, we will still need some funds for the transaction fees. + const combineTx = await wallet.transfer(wallet.address, 9500, provider.getBaseAssetId()); + await combineTx.wait(); + + // Now we can perform the same validations and see we have less UTXOs. We have 2 in this instance + // as we have performed the transfer in the base asset. So we have a UTXO for our transfer, and another + // for what is left after paying the fees. + const { coins: combinedCoins } = await wallet.getCoins(provider.getBaseAssetId()); + console.log('Combined Coins Length', combinedCoins.length); + // 2 + + // And we can also confirm the final balance of the base asset for this account is 9_998. So + // the cost of combining is also minimal. + const combinedBalance = await wallet.getBalance(provider.getBaseAssetId()); + console.log('Combined Balance', combinedBalance.toNumber()); + // 9_998 + // #endregion combining-utxos + + expect(initialCoins.length).toBe(10); + expect(initialBalance.toNumber()).toBe(10_000); + expect(combinedCoins.length).toBe(2); + expect(combinedBalance.toNumber()).toBe(9_998); + }); +}); diff --git a/apps/docs/.vitepress/config.ts b/apps/docs/.vitepress/config.ts index f62eb604519..4efd373d2b1 100644 --- a/apps/docs/.vitepress/config.ts +++ b/apps/docs/.vitepress/config.ts @@ -422,6 +422,10 @@ export default defineConfig({ text: 'Resubmitting Failed Transactions', link: '/guide/cookbook/resubmitting-failed-transactions', }, + { + text: 'Combining UTXOs', + link: '/guide/cookbook/combining-utxos', + }, ], }, { diff --git a/apps/docs/src/guide/cookbook/combining-utxos.md b/apps/docs/src/guide/cookbook/combining-utxos.md new file mode 100644 index 00000000000..37839f28c87 --- /dev/null +++ b/apps/docs/src/guide/cookbook/combining-utxos.md @@ -0,0 +1,11 @@ +# Combining UTXOs + +When performing a funding operation or calling `getResourcesToSpend`, you may encounter the `MAX_COINS_REACHED` error if the number of coins fetched per asset exceeds the maximum limit allowed by the chain. + +You may also want to do this if you want to reduce the number of inputs in your transaction, which can be useful if you are trying to reduce the size of your transaction or you are receiving the `MAX_INPUTS_EXCEEDED` error. + +One way to avoid these errors is to combine your UTXOs. This can be done by performing a transfer that combines multiple UTXOs into a single UTXO, where the transaction has multiple inputs for the asset, but a smaller number of outputs. + +> **Note:** You will not be able to have a single UTXO for the base asset after combining, as one output will be for the transfer, and you will have another for the fees. + +<<< @/../../docs-snippets/src/guide/cookbook/combining-utxos.test.ts#combining-utxos{ts:line-numbers} diff --git a/apps/docs/src/guide/errors/index.md b/apps/docs/src/guide/errors/index.md index ad57e214d8c..3304d1818b2 100644 --- a/apps/docs/src/guide/errors/index.md +++ b/apps/docs/src/guide/errors/index.md @@ -325,3 +325,9 @@ When the number of transaction inputs exceeds the maximum limit allowed by the b ### `MAX_OUTPUTS_EXCEEDED` When the number of transaction outputs exceeds the maximum limit allowed by the blockchain. + +### `MAX_COINS_REACHED` + +When performing a funding operation, or calling `getResourcesToSpend`, this error can be thrown if the number of coins fetched per asset exceeds the maximum limit allowed by the blockchain. + +This can be avoided by paginating the results of the `getCoins` method to fund your transaction, or by reducing the number of UTXOs for your account. This can be done by performing a transfer that amalgamates your UTXOs, as demonstrated in this cookbook. diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 0a64bbc3417..e6d31144455 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -922,7 +922,7 @@ describe('Account', () => { await expectToThrowFuelError(() => wallet.fund(request, txCost), { code: ErrorCode.MAX_COINS_REACHED, message: - 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', + 'The account retrieving coins has exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.', }); }); diff --git a/packages/account/src/providers/utils/handle-gql-error-message.ts b/packages/account/src/providers/utils/handle-gql-error-message.ts index 8aeefa5af9e..3a2d3d82fb2 100644 --- a/packages/account/src/providers/utils/handle-gql-error-message.ts +++ b/packages/account/src/providers/utils/handle-gql-error-message.ts @@ -18,7 +18,7 @@ export const handleGqlErrorMessage = (errorMessage: string, rawError: GraphQLErr case GqlErrorMessage.MAX_COINS_REACHED: throw new FuelError( ErrorCode.MAX_COINS_REACHED, - 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', + 'The account retrieving coins has exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.', {}, rawError ); diff --git a/packages/fuel-gauge/src/mapped-error-messages.test.ts b/packages/fuel-gauge/src/mapped-error-messages.test.ts index 7f23eaccab8..d2a1404a8e7 100644 --- a/packages/fuel-gauge/src/mapped-error-messages.test.ts +++ b/packages/fuel-gauge/src/mapped-error-messages.test.ts @@ -44,7 +44,7 @@ describe('mapped error messages', () => { await expectToThrowFuelError(() => wallet.fund(request, txCost), { code: ErrorCode.MAX_COINS_REACHED, message: - 'The account retrieving coins has reached the maximum response size. Please use the `getCoins` method to paginate the response.', + 'The account retrieving coins has exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.', }); }); }); From 989662e9828e1671e5c97fbd3e2a368612203e9c Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 14:28:04 +0700 Subject: [PATCH 11/17] chore: add lint rule for test file --- apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts b/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts index 7901ea4685f..053cf508bfa 100644 --- a/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { Provider, Wallet } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; From dcdf656ad5641847911263ec5c944811e50dda7e Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 18:01:26 +0700 Subject: [PATCH 12/17] docs: covert to docs snippets2 --- .../guide/cookbook/combining-utxos.test.ts | 66 ------------------- .../src/cookbook/combining-utxos.ts | 57 ++++++++++++++++ .../src/guide/cookbook/combining-utxos.md | 2 +- 3 files changed, 58 insertions(+), 67 deletions(-) delete mode 100644 apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts create mode 100644 apps/docs-snippets2/src/cookbook/combining-utxos.ts diff --git a/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts b/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts deleted file mode 100644 index 053cf508bfa..00000000000 --- a/apps/docs-snippets/src/guide/cookbook/combining-utxos.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* eslint-disable no-console */ -import { Provider, Wallet } from 'fuels'; -import { launchTestNode } from 'fuels/test-utils'; - -/** - * @group node - * @group browser - */ -describe('Combining UTXOs', () => { - it('Combines UTXOs', async () => { - using launched = await launchTestNode(); - - const { - provider: testProvider, - wallets: [testWallet], - } = launched; - const providerUrl = testProvider.url; - const WALLET_PVT_KEY = testWallet.privateKey; - - // #region combining-utxos - const provider = await Provider.create(providerUrl); - const fundingWallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); - const wallet = Wallet.generate({ provider }); - - // First, lets fund a wallet with 10_000 of the base asset. But as we are doing this across 10 transactions, - // we will end up with 10 UTXOs. - for (let i = 0; i < 10; i++) { - const initTx = await fundingWallet.transfer(wallet.address, 1000, provider.getBaseAssetId()); - await initTx.waitForResult(); - } - - // We can fetch the coins to see how many UTXOs we have, and confirm it is 10. - const { coins: initialCoins } = await wallet.getCoins(provider.getBaseAssetId()); - console.log('Initial Coins Length', initialCoins.length); - // 10 - - // But we can also confirm the total balance of the base asset for this account is 10_000. - const initialBalance = await wallet.getBalance(provider.getBaseAssetId()); - console.log('Initial Balance', initialBalance.toNumber()); - // 10_000 - - // Now we can combine the UTXOs into a single UTXO by performing a single transfer for the - // majority of the balance. Of course, we will still need some funds for the transaction fees. - const combineTx = await wallet.transfer(wallet.address, 9500, provider.getBaseAssetId()); - await combineTx.wait(); - - // Now we can perform the same validations and see we have less UTXOs. We have 2 in this instance - // as we have performed the transfer in the base asset. So we have a UTXO for our transfer, and another - // for what is left after paying the fees. - const { coins: combinedCoins } = await wallet.getCoins(provider.getBaseAssetId()); - console.log('Combined Coins Length', combinedCoins.length); - // 2 - - // And we can also confirm the final balance of the base asset for this account is 9_998. So - // the cost of combining is also minimal. - const combinedBalance = await wallet.getBalance(provider.getBaseAssetId()); - console.log('Combined Balance', combinedBalance.toNumber()); - // 9_998 - // #endregion combining-utxos - - expect(initialCoins.length).toBe(10); - expect(initialBalance.toNumber()).toBe(10_000); - expect(combinedCoins.length).toBe(2); - expect(combinedBalance.toNumber()).toBe(9_998); - }); -}); diff --git a/apps/docs-snippets2/src/cookbook/combining-utxos.ts b/apps/docs-snippets2/src/cookbook/combining-utxos.ts new file mode 100644 index 00000000000..560d2a2c0ec --- /dev/null +++ b/apps/docs-snippets2/src/cookbook/combining-utxos.ts @@ -0,0 +1,57 @@ +// #region combining-utxos +import { Provider, Wallet } from 'fuels'; + +import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../env'; + +const provider = await Provider.create(LOCAL_NETWORK_URL); +const fundingWallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); + +const wallet = Wallet.generate({ provider }); + +// First, lets fund a wallet with 10_000 of the base asset. But as we are doing this across 10 transactions, +// we will end up with 10 UTXOs. +for (let i = 0; i < 10; i++) { + const initTx = await fundingWallet.transfer( + wallet.address, + 1000, + provider.getBaseAssetId() + ); + await initTx.waitForResult(); +} + +// We can fetch the coins to see how many UTXOs we have, and confirm it is 10. +const { coins: initialCoins } = await wallet.getCoins( + provider.getBaseAssetId() +); +console.log('Initial Coins Length', initialCoins.length); +// 10 + +// But we can also confirm the total balance of the base asset for this account is 10_000. +const initialBalance = await wallet.getBalance(provider.getBaseAssetId()); +console.log('Initial Balance', initialBalance.toNumber()); +// 10_000 + +// Now we can combine the UTXOs into a single UTXO by performing a single transfer for the +// majority of the balance. Of course, we will still need some funds for the transaction fees. +const combineTx = await wallet.transfer( + wallet.address, + 9500, + provider.getBaseAssetId() +); +await combineTx.wait(); + +// Now we can perform the same validations and see we have less UTXOs. We have 2 in this instance +// as we have performed the transfer in the base asset. So we have a UTXO for our transfer, and another +// for what is left after paying the fees. +const { coins: combinedCoins } = await wallet.getCoins( + provider.getBaseAssetId() +); +console.log('Combined Coins Length', combinedCoins.length); +// 2 + +// And we can also confirm the final balance of the base asset for this account is 9_998. So +// the cost of combining is also minimal. +const combinedBalance = await wallet.getBalance(provider.getBaseAssetId()); +console.log('Combined Balance', combinedBalance.toNumber()); +// 9_998 +// #endregion combining-utxos diff --git a/apps/docs/src/guide/cookbook/combining-utxos.md b/apps/docs/src/guide/cookbook/combining-utxos.md index 37839f28c87..f6c91435c62 100644 --- a/apps/docs/src/guide/cookbook/combining-utxos.md +++ b/apps/docs/src/guide/cookbook/combining-utxos.md @@ -8,4 +8,4 @@ One way to avoid these errors is to combine your UTXOs. This can be done by perf > **Note:** You will not be able to have a single UTXO for the base asset after combining, as one output will be for the transfer, and you will have another for the fees. -<<< @/../../docs-snippets/src/guide/cookbook/combining-utxos.test.ts#combining-utxos{ts:line-numbers} +<<< @/../../docs-snippets2/src/guide/cookbook/combining-utxos.test.ts#combining-utxos{ts:line-numbers} From 7f0641deb0ee2ec4652b4e6b354c52794382ed0e Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Wed, 16 Oct 2024 18:09:21 +0700 Subject: [PATCH 13/17] chore: fix snippet path --- apps/docs/src/guide/cookbook/combining-utxos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/src/guide/cookbook/combining-utxos.md b/apps/docs/src/guide/cookbook/combining-utxos.md index f6c91435c62..3d076ba6858 100644 --- a/apps/docs/src/guide/cookbook/combining-utxos.md +++ b/apps/docs/src/guide/cookbook/combining-utxos.md @@ -8,4 +8,4 @@ One way to avoid these errors is to combine your UTXOs. This can be done by perf > **Note:** You will not be able to have a single UTXO for the base asset after combining, as one output will be for the transfer, and you will have another for the fees. -<<< @/../../docs-snippets2/src/guide/cookbook/combining-utxos.test.ts#combining-utxos{ts:line-numbers} +<<< @/../../docs-snippets2/src/cookbook/combining-utxos.ts#combining-utxos{ts:line-numbers} \ No newline at end of file From 9e17c08ff9c92ce781baa7049641cdf46e2bd4b7 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Thu, 17 Oct 2024 11:01:55 +0700 Subject: [PATCH 14/17] chore: improve doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nedim Salkić --- apps/docs-snippets2/src/cookbook/combining-utxos.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/docs-snippets2/src/cookbook/combining-utxos.ts b/apps/docs-snippets2/src/cookbook/combining-utxos.ts index 560d2a2c0ec..90cee50add6 100644 --- a/apps/docs-snippets2/src/cookbook/combining-utxos.ts +++ b/apps/docs-snippets2/src/cookbook/combining-utxos.ts @@ -40,9 +40,9 @@ const combineTx = await wallet.transfer( ); await combineTx.wait(); -// Now we can perform the same validations and see we have less UTXOs. We have 2 in this instance -// as we have performed the transfer in the base asset. So we have a UTXO for our transfer, and another -// for what is left after paying the fees. +// Now we can perform the same validations and see we have less UTXOs. +// We have 2 in this instance, as we have performed the transfer in the base asset: +// a UTXO for our transfer, and another for what is left after paying the fees. const { coins: combinedCoins } = await wallet.getCoins( provider.getBaseAssetId() ); From 92c01776ba84cf6e106603ad17be064ddd4673bd Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Thu, 17 Oct 2024 11:02:37 +0700 Subject: [PATCH 15/17] chore: improve doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nedim Salkić --- apps/docs-snippets2/src/cookbook/combining-utxos.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs-snippets2/src/cookbook/combining-utxos.ts b/apps/docs-snippets2/src/cookbook/combining-utxos.ts index 90cee50add6..929071d699d 100644 --- a/apps/docs-snippets2/src/cookbook/combining-utxos.ts +++ b/apps/docs-snippets2/src/cookbook/combining-utxos.ts @@ -49,8 +49,8 @@ const { coins: combinedCoins } = await wallet.getCoins( console.log('Combined Coins Length', combinedCoins.length); // 2 -// And we can also confirm the final balance of the base asset for this account is 9_998. So -// the cost of combining is also minimal. +// And we can also confirm the final balance of the base asset for this account is 9_998, +// so the cost of combining is also minimal. const combinedBalance = await wallet.getBalance(provider.getBaseAssetId()); console.log('Combined Balance', combinedBalance.toNumber()); // 9_998 From 8938481872a3a5279e63ad7262e731b55ce08380 Mon Sep 17 00:00:00 2001 From: Daniel Bate Date: Thu, 17 Oct 2024 11:13:54 +0700 Subject: [PATCH 16/17] chore: lint --- apps/docs-snippets2/src/cookbook/combining-utxos.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs-snippets2/src/cookbook/combining-utxos.ts b/apps/docs-snippets2/src/cookbook/combining-utxos.ts index 929071d699d..773a563a0b2 100644 --- a/apps/docs-snippets2/src/cookbook/combining-utxos.ts +++ b/apps/docs-snippets2/src/cookbook/combining-utxos.ts @@ -40,7 +40,7 @@ const combineTx = await wallet.transfer( ); await combineTx.wait(); -// Now we can perform the same validations and see we have less UTXOs. +// Now we can perform the same validations and see we have less UTXOs. // We have 2 in this instance, as we have performed the transfer in the base asset: // a UTXO for our transfer, and another for what is left after paying the fees. const { coins: combinedCoins } = await wallet.getCoins( From 5d02e1f164f3ba34d3fd30c8585770df8e75944d Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Mon, 21 Oct 2024 13:21:06 +0100 Subject: [PATCH 17/17] docs: added link to relevant cookbook --- apps/docs/src/guide/errors/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/src/guide/errors/index.md b/apps/docs/src/guide/errors/index.md index 3304d1818b2..324e1c8b12f 100644 --- a/apps/docs/src/guide/errors/index.md +++ b/apps/docs/src/guide/errors/index.md @@ -330,4 +330,4 @@ When the number of transaction outputs exceeds the maximum limit allowed by the When performing a funding operation, or calling `getResourcesToSpend`, this error can be thrown if the number of coins fetched per asset exceeds the maximum limit allowed by the blockchain. -This can be avoided by paginating the results of the `getCoins` method to fund your transaction, or by reducing the number of UTXOs for your account. This can be done by performing a transfer that amalgamates your UTXOs, as demonstrated in this cookbook. +This can be avoided by paginating the results of the `getCoins` method to fund your transaction, or by reducing the number of UTXOs for your account. This can be done by performing a transfer that amalgamates your UTXOs, as demonstrated in [this cookbook](../cookbook/combining-utxos.md).