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!: refactored the getTransactionCost method #2643

Merged
merged 40 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fb3d44a
chore: refactored the `getTransactionCost` method
petertonysmith94 Jun 28, 2024
55998e3
chore: fix typo
petertonysmith94 Jun 28, 2024
5b42211
chore: added missing functionality from `BaseInvocationScope`
petertonysmith94 Jul 1, 2024
ccd661f
Merge branch 'master' of https://github.com/FuelLabs/fuels-ts into ps…
petertonysmith94 Jul 1, 2024
40c8309
chore: fix predicate docs
petertonysmith94 Jul 1, 2024
580bbd8
chore: moved `getResourcesForTransaction` from the `provider` to the …
petertonysmith94 Jul 1, 2024
efd6f7e
chore: using `generateFakeResources` in `Account.getTransactionCost`
petertonysmith94 Jul 8, 2024
4f208e4
chore: removed `Account.getResourcesForTransaction` method
petertonysmith94 Jul 8, 2024
44d0dc5
Revert "chore: using `generateFakeResources` in `Account.getTransacti…
petertonysmith94 Jul 8, 2024
7bc0add
chore: removed redundant `getTransactionCost` from `BaseInvocationScope`
petertonysmith94 Jul 8, 2024
26f20d4
chore: removed redundant provider
petertonysmith94 Jul 8, 2024
b9e5258
Merge branch 'master' of https://github.com/FuelLabs/fuels-ts into ps…
petertonysmith94 Jul 8, 2024
fb68eca
chore: changeset
petertonysmith94 Jul 8, 2024
3c3a110
chore: remove redundant export
petertonysmith94 Jul 10, 2024
7e787b4
chore: removed redundant account attribute on `AbstractScript`
petertonysmith94 Jul 10, 2024
8a82b8e
chore: removed funded step from `Provider.getTransactionCost`
petertonysmith94 Jul 10, 2024
2674cdd
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 10, 2024
0f7fa67
Merge branch 'master' of https://github.com/FuelLabs/fuels-ts into ps…
petertonysmith94 Jul 11, 2024
33d9b1b
chore: fix tests
petertonysmith94 Jul 11, 2024
dcfdeb1
chore: lint
petertonysmith94 Jul 11, 2024
a14330c
chore: making the the addition of coin more explicit
petertonysmith94 Jul 12, 2024
f6f6678
chore: moved the gasLimit removal to the Provider
petertonysmith94 Jul 12, 2024
b9058e0
chore: made changeset minor changes
petertonysmith94 Jul 12, 2024
f06fdff
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 12, 2024
7fbd8bd
chore: lint
petertonysmith94 Jul 12, 2024
7034c62
chore: fixing tests
petertonysmith94 Jul 15, 2024
6076df3
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 15, 2024
04b5c27
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 15, 2024
46179a8
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 15, 2024
8776b79
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 15, 2024
e3138f4
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 16, 2024
690914d
Merge branches 'ps/chore/refactor-get-transaction-cost' and 'master' …
petertonysmith94 Jul 22, 2024
1575861
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 22, 2024
0e23032
chore: linting
petertonysmith94 Jul 22, 2024
126107d
docs: fixed `getTransactionCost` docs reference
petertonysmith94 Jul 22, 2024
456429f
chore: added doc-block for `Account.getTransactionCost` method
petertonysmith94 Jul 22, 2024
2962345
chore: make hidden the `Account.getTransactionCost` method for typedocs
petertonysmith94 Jul 22, 2024
4c81e4b
chore: updated transaction cost parameter `quantitiesToContract` -> `…
petertonysmith94 Jul 22, 2024
5c1123b
Merge branch 'master' of https://github.com/FuelLabs/fuels-ts into ps…
petertonysmith94 Jul 22, 2024
0f6e89d
Merge branch 'master' into ps/chore/refactor-get-transaction-cost
petertonysmith94 Jul 22, 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
8 changes: 8 additions & 0 deletions .changeset/short-sheep-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@fuel-ts/account": minor
"@fuel-ts/interfaces": minor
"@fuel-ts/contract": minor
"@fuel-ts/program": minor
---

chore!: refactored the `getTransactionCost` method
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('Custom Transactions from Contract Calls', () => {
// Add coin output for the recipient
transactionRequest.addCoinOutput(receiverWallet.address, amountToRecipient, baseAssetId);

const txCost = await senderWallet.provider.getTransactionCost(transactionRequest);
const txCost = await senderWallet.getTransactionCost(transactionRequest);

transactionRequest.gasLimit = txCost.gasUsed;
transactionRequest.maxFee = txCost.maxFee;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,8 @@ describe('Signing transactions', () => {

// Add witnesses including the signer
// Estimate the predicate inputs
const txCost = await provider.getTransactionCost(request, {
const txCost = await predicate.getTransactionCost(request, {
signatureCallback: (tx) => tx.addAccountWitnesses(signer),
resourcesOwner: predicate,
});

request.updatePredicateGasUsed(txCost.estimatedPredicates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('encode and decode', () => {
request.scriptData = encodedArguments;

// Now we can build out the rest of the transaction and then fund it
const txCost = await wallet.provider.getTransactionCost(request);
const txCost = await wallet.getTransactionCost(request);
request.maxFee = txCost.maxFee;
request.gasLimit = txCost.gasUsed;
await wallet.fund(request, txCost);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Provider, WalletUnlocked } from 'fuels';
import type { WalletUnlocked } from 'fuels';
import { ScriptTransactionRequest, bn, Predicate, BN } from 'fuels';
import { seedTestWallet } from 'fuels/test-utils';

Expand All @@ -15,7 +15,6 @@ describe(__filename, () => {
let wallet: WalletUnlocked;
let receiver: WalletUnlocked;
let baseAssetId: string;
let provider: Provider;
let predicate: Predicate<[string]>;

const { abiContents: abi, binHexlified: bin } = getDocsSnippetsForcProject(
Expand All @@ -27,7 +26,6 @@ describe(__filename, () => {
beforeAll(async () => {
wallet = await getTestWallet();
receiver = await getTestWallet();
provider = wallet.provider;

baseAssetId = wallet.provider.getBaseAssetId();

Expand Down Expand Up @@ -65,9 +63,7 @@ describe(__filename, () => {
const transactionRequest = new ScriptTransactionRequest({ gasLimit: 2000, maxFee: bn(0) });
transactionRequest.addCoinOutput(receiver.address, 100, baseAssetId);

const txCost = await provider.getTransactionCost(transactionRequest, {
resourcesOwner: predicate,
});
const txCost = await predicate.getTransactionCost(transactionRequest);

transactionRequest.gasLimit = txCost.gasUsed;
transactionRequest.maxFee = txCost.maxFee;
Expand All @@ -91,9 +87,7 @@ describe(__filename, () => {
const transactionRequest = new ScriptTransactionRequest({ gasLimit: 2000, maxFee: bn(0) });
transactionRequest.addCoinOutput(receiver.address, 1000000, baseAssetId);

const txCost = await provider.getTransactionCost(transactionRequest, {
resourcesOwner: predicate,
});
const txCost = await predicate.getTransactionCost(transactionRequest);

transactionRequest.gasLimit = txCost.gasUsed;
transactionRequest.maxFee = txCost.maxFee;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe(__filename, () => {
const quantities = [coinQuantityfy([1000, ASSET_A]), coinQuantityfy([500, ASSET_B])];

// 5. Calculate the transaction fee
const txCost = await provider.getTransactionCost(request, { quantitiesToContract: quantities });
const txCost = await wallet.getTransactionCost(request, { quantitiesToContract: quantities });

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('Transaction Response', () => {
transactionRequest.setData(scriptAbi, scriptMainFunctionArguments);

// Fund the transaction
const txCost = await provider.getTransactionCost(transactionRequest);
const txCost = await wallet.getTransactionCost(transactionRequest);

transactionRequest.maxFee = txCost.maxFee;
transactionRequest.gasLimit = txCost.gasUsed;
Expand All @@ -79,7 +79,7 @@ describe('Transaction Response', () => {
});
transactionRequest.setData(scriptAbi, scriptMainFunctionArguments);

const txCost = await provider.getTransactionCost(transactionRequest);
const txCost = await wallet.getTransactionCost(transactionRequest);

transactionRequest.maxFee = txCost.maxFee;
transactionRequest.gasLimit = txCost.gasUsed;
Expand Down
4 changes: 2 additions & 2 deletions apps/docs-snippets/src/guide/wallets/signing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe(__filename, () => {

request.addCoinOutput(Address.fromRandom(), 1000, baseAssetId);

const txCost = await provider.getTransactionCost(request);
const txCost = await wallet.getTransactionCost(request);

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down Expand Up @@ -85,7 +85,7 @@ describe(__filename, () => {

request.addCoinOutput(Address.fromRandom(), 1000, baseAssetId);

const txCost = await provider.getTransactionCost(request);
const txCost = await wallet.getTransactionCost(request);

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down
2 changes: 1 addition & 1 deletion apps/docs-snippets/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const getTestWallet = async (seedQuantities?: CoinQuantityLike[]) => {
.forEach(({ amount, assetId }) => request.addCoinOutput(testWallet.address, amount, assetId));

// get the cost of the transaction
const txCost = await genesisWallet.provider.getTransactionCost(request);
const txCost = await testWallet.getTransactionCost(request);

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down
2 changes: 1 addition & 1 deletion packages/account/src/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ describe('Account', () => {
[amount, assetIdB],
]);

const txCost = await sender.provider.getTransactionCost(request);
const txCost = await sender.getTransactionCost(request);

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down
40 changes: 34 additions & 6 deletions packages/account/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
GetMessagesResponse,
GetBalancesResponse,
Coin,
TransactionCostParams,
} from './providers';
import {
withdrawScript,
Expand All @@ -42,6 +43,7 @@
isRequestInputCoin,
isRequestInputResource,
} from './providers/transaction-request/helpers';
import { mergeQuantities } from './providers/utils/merge-quantities';
import { assembleTransferToContractScript } from './utils/formatTransferToContractScriptData';

export type TxParamsType = Pick<
Expand Down Expand Up @@ -436,8 +438,7 @@

request.addContractInputAndOutput(contractAddress);

const txCost = await this.provider.getTransactionCost(request, {
resourcesOwner: this,
const txCost = await this.getTransactionCost(request, {
quantitiesToContract: [{ amount: bn(amount), assetId: String(assetIdToTransfer) }],
});

Expand Down Expand Up @@ -486,7 +487,7 @@
let request = new ScriptTransactionRequest(params);
const quantitiesToContract = [{ amount: bn(amount), assetId: baseAssetId }];

const txCost = await this.provider.getTransactionCost(request, { quantitiesToContract });
const txCost = await this.getTransactionCost(request, { quantitiesToContract });

request = this.validateGasLimitAndMaxFee({
transactionRequest: request,
Expand All @@ -500,6 +501,35 @@
return this.sendTransaction(request);
}

async getTransactionCost(
transactionRequestLike: TransactionRequestLike,
{ signatureCallback, quantitiesToContract = [] }: TransactionCostParams = {}
Torres-ssf marked this conversation as resolved.
Show resolved Hide resolved
): Promise<TransactionCost> {
const txRequestClone = clone(transactionRequestify(transactionRequestLike));
const baseAssetId = this.provider.getBaseAssetId();

// Fund with fake UTXOs to avoid not enough funds error
// Getting coin quantities from amounts being transferred
const coinOutputsQuantities = txRequestClone.getCoinOutputsQuantities();
// Combining coin quantities from amounts being transferred and forwarding to contracts
const requiredQuantities = mergeQuantities(coinOutputsQuantities, quantitiesToContract);
// An arbitrary amount of the base asset is added to cover the transaction fee during dry runs
const transactionFeeForDryRun = [{ assetId: baseAssetId, amount: bn('100000000000000000') }];
const resources = this.generateFakeResources(
mergeQuantities(requiredQuantities, transactionFeeForDryRun)
);
txRequestClone.addResources(resources);

const txCost = await this.provider.getTransactionCost(txRequestClone, {
signatureCallback,
});

return {
...txCost,
requiredQuantities,
};
}

/**
* Sign a message from the account via the connector.
*
Expand Down Expand Up @@ -607,9 +637,7 @@
txParams: TxParamsType
) {
let request = transactionRequest;
const txCost = await this.provider.getTransactionCost(request, {
resourcesOwner: this,
});
const txCost = await this.getTransactionCost(request);
request = this.validateGasLimitAndMaxFee({
transactionRequest: request,
gasUsed: txCost.gasUsed,
Expand Down
7 changes: 4 additions & 3 deletions packages/account/src/providers/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1075,13 +1075,15 @@ Supported fuel-core version: ${mock.supportedVersion}.`
// TODO: validate if this test still makes sense
it.skip('should ensure estimated fee values on getTransactionCost are never 0', async () => {
Torres-ssf marked this conversation as resolved.
Show resolved Hide resolved
using launched = await setupTestProviderAndWallets();
const { provider } = launched;
const {
wallets: [wallet],
} = launched;
const request = new ScriptTransactionRequest();

// forcing calculatePriceWithFactor to return 0
const calculateGasFeeMock = vi.spyOn(gasMod, 'calculateGasFee').mockReturnValue(bn(0));

const { minFee, maxFee } = await provider.getTransactionCost(request);
const { minFee, maxFee } = await wallet.getTransactionCost(request);

expect(calculateGasFeeMock).toHaveBeenCalled();

Expand All @@ -1099,7 +1101,6 @@ Supported fuel-core version: ${mock.supportedVersion}.`
const methodCalls = [
() => provider.getBalance(b256Str, baseAssetId),
() => provider.getCoins(b256Str),
() => provider.getResourcesForTransaction(b256Str, new ScriptTransactionRequest()),
() => provider.getResourcesToSpend(b256Str, []),
() => provider.getContractBalance(b256Str, baseAssetId),
() => provider.getBalances(b256Str),
Expand Down
79 changes: 3 additions & 76 deletions packages/account/src/providers/provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Address } from '@fuel-ts/address';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { AbstractAccount, AbstractAddress, BytesLike } from '@fuel-ts/interfaces';
import type { AbstractAddress, BytesLike } from '@fuel-ts/interfaces';
import { BN, bn } from '@fuel-ts/math';
import type { Transaction } from '@fuel-ts/transactions';
import {
Expand All @@ -17,8 +17,6 @@ import { GraphQLClient } from 'graphql-request';
import type { GraphQLResponse } from 'graphql-request/src/types';
import { clone } from 'ramda';

import type { Predicate } from '../predicate';

import { getSdk as getOperationsSdk } from './__generated__/operations';
import type {
GqlChainInfoFragment,
Expand Down Expand Up @@ -62,7 +60,6 @@ import {
} from './utils';
import type { RetryOptions } from './utils/auto-retry-fetch';
import { autoRetryFetch } from './utils/auto-retry-fetch';
import { mergeQuantities } from './utils/merge-quantities';

const MAX_RETRIES = 10;

Expand Down Expand Up @@ -336,11 +333,6 @@ export type EstimateTransactionParams = {
};

export type TransactionCostParams = EstimateTransactionParams & {
/**
* The account that will provide the resources for the transaction.
*/
resourcesOwner?: AbstractAccount;

/**
* The quantities to forward to the contract.
*/
Expand Down Expand Up @@ -1131,40 +1123,18 @@ Supported fuel-core version: ${supportedVersion}.`
*/
async getTransactionCost(
transactionRequestLike: TransactionRequestLike,
{ resourcesOwner, signatureCallback, quantitiesToContract = [] }: TransactionCostParams = {}
): Promise<TransactionCost> {
{ signatureCallback }: TransactionCostParams = {}
): Promise<Omit<TransactionCost, 'requiredQuantities'>> {
maschad marked this conversation as resolved.
Show resolved Hide resolved
const txRequestClone = clone(transactionRequestify(transactionRequestLike));
const isScriptTransaction = txRequestClone.type === TransactionType.Script;
const baseAssetId = this.getBaseAssetId();
const updateMaxFee = txRequestClone.maxFee.eq(0);
// Fund with fake UTXOs to avoid not enough funds error
// Getting coin quantities from amounts being transferred
const coinOutputsQuantities = txRequestClone.getCoinOutputsQuantities();
// Combining coin quantities from amounts being transferred and forwarding to contracts
const allQuantities = mergeQuantities(coinOutputsQuantities, quantitiesToContract);
// Funding transaction with fake utxos
txRequestClone.fundWithFakeUtxos(allQuantities, baseAssetId, resourcesOwner?.address);

/**
* Estimate predicates gasUsed
*/
// Remove gasLimit to avoid gasLimit when estimating predicates
if (isScriptTransaction) {
txRequestClone.gasLimit = bn(0);
}

/**
* The fake utxos added above can be from a predicate
* If the resources owner is a predicate,
* we need to populate the resources with the predicate's data
* so that predicate estimation can happen.
*/
if (resourcesOwner && 'populateTransactionPredicateData' in resourcesOwner) {
(resourcesOwner as Predicate<[]>).populateTransactionPredicateData(txRequestClone);
}

const signedRequest = clone(txRequestClone) as ScriptTransactionRequest;

let addedSignatures = 0;
if (signatureCallback && isScriptTransaction) {
const lengthBefore = signedRequest.witnesses.length;
Expand Down Expand Up @@ -1213,7 +1183,6 @@ Supported fuel-core version: ${supportedVersion}.`
}

return {
requiredQuantities: allQuantities,
receipts,
gasUsed,
gasPrice,
Expand All @@ -1230,48 +1199,6 @@ Supported fuel-core version: ${supportedVersion}.`
};
}

/**
* Get the required quantities and associated resources for a transaction.
*
* @param owner - address to add resources from.
* @param transactionRequestLike - transaction request to populate resources for.
* @param quantitiesToContract - quantities for the contract (optional).
*
* @returns a promise resolving to the required quantities for the transaction.
*/
async getResourcesForTransaction(
owner: string | AbstractAddress,
transactionRequestLike: TransactionRequestLike,
quantitiesToContract: CoinQuantity[] = []
) {
const ownerAddress = Address.fromAddressOrString(owner);
const transactionRequest = transactionRequestify(clone(transactionRequestLike));
const transactionCost = await this.getTransactionCost(transactionRequest, {
quantitiesToContract,
});

// Add the required resources to the transaction from the owner
transactionRequest.addResources(
await this.getResourcesToSpend(ownerAddress, transactionCost.requiredQuantities)
);
// Refetch transaction costs with the new resources
// TODO: we could find a way to avoid fetch estimatePredicates again, by returning the transaction or
// returning a specific gasUsed by the predicate.
// Also for the dryRun we could have the same issue as we are going to run twice the dryRun and the
// estimateTxDependencies as we don't have access to the transaction, maybe returning the transaction would
// be better.
const { requiredQuantities, ...txCost } = await this.getTransactionCost(transactionRequest, {
quantitiesToContract,
});
const resources = await this.getResourcesToSpend(ownerAddress, requiredQuantities);

return {
resources,
requiredQuantities,
...txCost,
};
}

/**
* Returns coins for the given owner.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/account/src/test-utils/seedTestWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const seedTestWallet = async (
})
);

const txCost = await genesisWallet.provider.getTransactionCost(request);
const txCost = await genesisWallet.getTransactionCost(request);

request.gasLimit = txCost.gasUsed;
request.maxFee = txCost.maxFee;
Expand Down
Loading
Loading