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

chore: upgrading fuel-core to 0.40.0 #3332

Merged
merged 19 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions .changeset/lucky-avocados-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +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`
arboleya marked this conversation as resolved.
Show resolved Hide resolved
57 changes: 57 additions & 0 deletions apps/docs-snippets2/src/cookbook/combining-utxos.ts
Original file line number Diff line number Diff line change
@@ -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:
// 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
4 changes: 4 additions & 0 deletions apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
],
},
{
Expand Down
11 changes: 11 additions & 0 deletions apps/docs/src/guide/cookbook/combining-utxos.md
Original file line number Diff line number Diff line change
@@ -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-snippets2/src/cookbook/combining-utxos.ts#combining-utxos{ts:line-numbers}
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 @@ -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](../cookbook/combining-utxos.md).
2 changes: 1 addition & 1 deletion internal/fuel-core/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.39.0
0.40.0
6 changes: 4 additions & 2 deletions packages/account/src/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
petertonysmith94 marked this conversation as resolved.
Show resolved Hide resolved
using launched = await setupTestProviderAndWallets({
walletsConfig: {
amountPerCoin: 100,
Expand All @@ -920,7 +920,9 @@ describe('Account', () => {
request.maxFee = txCost.maxFee;

await expectToThrowFuelError(() => wallet.fund(request, txCost), {
code: ErrorCode.MAX_INPUTS_EXCEEDED,
code: ErrorCode.MAX_COINS_REACHED,
message:
'The account retrieving coins has exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.',
});
});

Expand Down
8 changes: 7 additions & 1 deletion packages/account/src/providers/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -867,11 +867,17 @@ 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);
petertonysmith94 marked this conversation as resolved.
Show resolved Hide resolved
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}`
)
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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 exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.',
{},
rawError
);
default:
throw new FuelError(ErrorCode.INVALID_REQUEST, errorMessage);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/errors/src/error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',

Expand Down
50 changes: 50 additions & 0 deletions packages/fuel-gauge/src/mapped-error-messages.test.ts
Original file line number Diff line number Diff line change
@@ -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 exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.',
});
});
});
22 changes: 0 additions & 22 deletions packages/fuel-gauge/src/not-enough-coins.test.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/versions/src/lib/getBuiltinVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Versions } from './types';
export function getBuiltinVersions(): Versions {
return {
FORC: '0.66.2',
FUEL_CORE: '0.39.0',
FUEL_CORE: '0.40.0',
FUELS: '0.96.1',
};
}