diff --git a/.changeset/short-sheep-divide.md b/.changeset/short-sheep-divide.md new file mode 100644 index 00000000000..dc6a43c3e1d --- /dev/null +++ b/.changeset/short-sheep-divide.md @@ -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 diff --git a/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts b/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts index 9cf3d2248a6..609f43654f0 100644 --- a/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts @@ -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; diff --git a/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts b/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts index 45893a1d7e5..24855ad5bfc 100644 --- a/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts @@ -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); diff --git a/apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts b/apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts index 94a3ec18b31..a5040ee8ba4 100644 --- a/apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts +++ b/apps/docs-snippets/src/guide/encoding/encode-and-decode.test.ts @@ -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); diff --git a/apps/docs-snippets/src/guide/predicates/interacting-with-predicates.test.ts b/apps/docs-snippets/src/guide/predicates/interacting-with-predicates.test.ts index 8a6c8ac5873..2763751ffe5 100644 --- a/apps/docs-snippets/src/guide/predicates/interacting-with-predicates.test.ts +++ b/apps/docs-snippets/src/guide/predicates/interacting-with-predicates.test.ts @@ -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'; @@ -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( @@ -27,7 +26,6 @@ describe(__filename, () => { beforeAll(async () => { wallet = await getTestWallet(); receiver = await getTestWallet(); - provider = wallet.provider; baseAssetId = wallet.provider.getBaseAssetId(); @@ -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; @@ -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; diff --git a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts index 942b9ba7e13..036b7759d75 100644 --- a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts +++ b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts @@ -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, { quantities }); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/apps/docs-snippets/src/guide/transactions/transaction-response.test.ts b/apps/docs-snippets/src/guide/transactions/transaction-response.test.ts index 8bb9495e1e8..d4d120bc34f 100644 --- a/apps/docs-snippets/src/guide/transactions/transaction-response.test.ts +++ b/apps/docs-snippets/src/guide/transactions/transaction-response.test.ts @@ -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; @@ -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; diff --git a/apps/docs-snippets/src/guide/wallets/signing.test.ts b/apps/docs-snippets/src/guide/wallets/signing.test.ts index 891e0a64702..8d05d5d76cb 100644 --- a/apps/docs-snippets/src/guide/wallets/signing.test.ts +++ b/apps/docs-snippets/src/guide/wallets/signing.test.ts @@ -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; @@ -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; diff --git a/apps/docs-snippets/src/utils.ts b/apps/docs-snippets/src/utils.ts index 3e7a35a009d..57e26200a87 100644 --- a/apps/docs-snippets/src/utils.ts +++ b/apps/docs-snippets/src/utils.ts @@ -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; diff --git a/apps/docs/src/guide/contracts/cost-estimation.md b/apps/docs/src/guide/contracts/cost-estimation.md index 533e18d095c..7190bf53612 100644 --- a/apps/docs/src/guide/contracts/cost-estimation.md +++ b/apps/docs/src/guide/contracts/cost-estimation.md @@ -1,10 +1,10 @@ # Estimating Contract Call Cost -The `getTransactionCost` function provided by the [Provider](../../api/Account/Provider.md) allows you to estimate the cost of a specific contract call. The return type, `TransactionCost`, is an object containing relevant information for the estimation: +The `getTransactionCost` function provided by the [Account](../../api/Account/Account.md) allows you to estimate the cost of a specific contract call. The return type, `TransactionCost`, is an object containing relevant information for the estimation: <<< @/../../../packages/account/src/providers/provider.ts#cost-estimation-1{ts:line-numbers} -The following example demonstrate how to get the estimated transaction cost for: +The following example demonstrates how to get the estimated transaction cost for: ## 1. Single contract call transaction: diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 78c496ce2e3..7e64ce8501b 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -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; diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 302694a6ab9..f83f75fc491 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -29,6 +29,7 @@ import type { GetMessagesResponse, GetBalancesResponse, Coin, + TransactionCostParams, } from './providers'; import { withdrawScript, @@ -42,6 +43,7 @@ import { isRequestInputCoin, isRequestInputResource, } from './providers/transaction-request/helpers'; +import { mergeQuantities } from './providers/utils/merge-quantities'; import { assembleTransferToContractScript } from './utils/formatTransferToContractScriptData'; export type TxParamsType = Pick< @@ -436,9 +438,8 @@ export class Account extends AbstractAccount { request.addContractInputAndOutput(contractAddress); - const txCost = await this.provider.getTransactionCost(request, { - resourcesOwner: this, - quantitiesToContract: [{ amount: bn(amount), assetId: String(assetIdToTransfer) }], + const txCost = await this.getTransactionCost(request, { + quantities: [{ amount: bn(amount), assetId: String(assetIdToTransfer) }], }); request = this.validateGasLimitAndMaxFee({ @@ -484,9 +485,9 @@ export class Account extends AbstractAccount { const baseAssetId = this.provider.getBaseAssetId(); let request = new ScriptTransactionRequest(params); - const quantitiesToContract = [{ amount: bn(amount), assetId: baseAssetId }]; + const quantities = [{ amount: bn(amount), assetId: baseAssetId }]; - const txCost = await this.provider.getTransactionCost(request, { quantitiesToContract }); + const txCost = await this.getTransactionCost(request, { quantities }); request = this.validateGasLimitAndMaxFee({ transactionRequest: request, @@ -500,6 +501,45 @@ export class Account extends AbstractAccount { return this.sendTransaction(request); } + /** + * Returns a transaction cost to enable user + * to set gasLimit and also reserve balance amounts + * on the transaction. + * + * @param transactionRequestLike - The transaction request object. + * @param transactionCostParams - The transaction cost parameters (optional). + * + * @returns A promise that resolves to the transaction cost object. + */ + async getTransactionCost( + transactionRequestLike: TransactionRequestLike, + { signatureCallback, quantities = [] }: TransactionCostParams = {} + ): Promise { + 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, quantities); + // 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. * @@ -607,9 +647,7 @@ export class Account extends AbstractAccount { 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, diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 525322c4b12..1969e7b70ee 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -1076,14 +1076,15 @@ Supported fuel-core version: ${mock.supportedVersion}.` using launched = await setupTestProviderAndWallets({ nodeOptions: { args: ['--min-gas-price', '0'] }, }); - const { provider } = launched; + const { + wallets: [wallet], + } = launched; const request = new ScriptTransactionRequest(); - const { minFee, maxFee, gasPrice } = await provider.getTransactionCost(request); + const { minFee, maxFee, gasPrice } = await wallet.getTransactionCost(request); expect(gasPrice.eq(0)).toBeTruthy(); - expect(maxFee.eq(0)).not.toBeTruthy(); expect(minFee.eq(0)).not.toBeTruthy(); }); @@ -1098,7 +1099,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), diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index cc26c3b27ff..093783d64a5 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -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 { @@ -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, @@ -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; @@ -336,15 +333,10 @@ 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. */ - quantitiesToContract?: CoinQuantity[]; + quantities?: CoinQuantity[]; /** * A callback to sign the transaction. @@ -1120,6 +1112,8 @@ Supported fuel-core version: ${supportedVersion}.` } /** + * @hidden + * * Returns a transaction cost to enable user * to set gasLimit and also reserve balance amounts * on the transaction. @@ -1131,40 +1125,18 @@ Supported fuel-core version: ${supportedVersion}.` */ async getTransactionCost( transactionRequestLike: TransactionRequestLike, - { resourcesOwner, signatureCallback, quantitiesToContract = [] }: TransactionCostParams = {} - ): Promise { + { signatureCallback }: TransactionCostParams = {} + ): Promise> { 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; @@ -1213,7 +1185,6 @@ Supported fuel-core version: ${supportedVersion}.` } return { - requiredQuantities: allQuantities, receipts, gasUsed, gasPrice, @@ -1230,48 +1201,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. * diff --git a/packages/account/src/test-utils/seedTestWallet.ts b/packages/account/src/test-utils/seedTestWallet.ts index 67b837d1ef4..2da650334f5 100644 --- a/packages/account/src/test-utils/seedTestWallet.ts +++ b/packages/account/src/test-utils/seedTestWallet.ts @@ -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; diff --git a/packages/contract/src/contract-factory.ts b/packages/contract/src/contract-factory.ts index f24f03d1d7d..0de99deb295 100644 --- a/packages/contract/src/contract-factory.ts +++ b/packages/contract/src/contract-factory.ts @@ -233,7 +233,7 @@ export default class ContractFactory { const account = this.getAccount(); - const txCost = await account.provider.getTransactionCost(transactionRequest); + const txCost = await account.getTransactionCost(transactionRequest); const { maxFee: setMaxFee } = deployContractOptions; diff --git a/packages/fuel-gauge/src/advanced-logging.test.ts b/packages/fuel-gauge/src/advanced-logging.test.ts index ec5512b9da5..d5946392915 100644 --- a/packages/fuel-gauge/src/advanced-logging.test.ts +++ b/packages/fuel-gauge/src/advanced-logging.test.ts @@ -249,9 +249,7 @@ describe('Advanced Logging', () => { ]) .getTransactionRequest(); - const txCost = await launched.provider.getTransactionCost(request, { - resourcesOwner: wallet, - }); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -344,9 +342,7 @@ describe('Advanced Logging', () => { .addContracts([advancedLogContract, otherAdvancedLogContract]) .getTransactionRequest(); - const txCost = await launched.provider.getTransactionCost(request, { - resourcesOwner: wallet, - }); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 672d9bd14a6..49cc6a0f4a4 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -739,7 +739,6 @@ describe('Contract', () => { it('Parse create TX to JSON and parse back to create TX', async () => { using launched = await launchTestNode(); const { - provider, wallets: [wallet], } = launched; @@ -757,7 +756,7 @@ describe('Contract', () => { txRequestParsed ) as ScriptTransactionRequest; - const txCost = await provider.getTransactionCost(transactionRequestParsed); + const txCost = await wallet.getTransactionCost(transactionRequestParsed); transactionRequestParsed.gasLimit = txCost.gasUsed; transactionRequestParsed.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/coverage-contract.test.ts b/packages/fuel-gauge/src/coverage-contract.test.ts index 8478298f215..0ff3698f24e 100644 --- a/packages/fuel-gauge/src/coverage-contract.test.ts +++ b/packages/fuel-gauge/src/coverage-contract.test.ts @@ -609,7 +609,7 @@ describe('Coverage Contract', () => { request.addCoinOutput(recipient.address, 10, provider.getBaseAssetId()); - const txCost = await sender.provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/fee.test.ts b/packages/fuel-gauge/src/fee.test.ts index d597321e6ca..db875abb072 100644 --- a/packages/fuel-gauge/src/fee.test.ts +++ b/packages/fuel-gauge/src/fee.test.ts @@ -135,9 +135,7 @@ describe('Fee', () => { request.addCoinOutput(destination2.address, amountToTransfer, ASSET_A); request.addCoinOutput(destination3.address, amountToTransfer, ASSET_B); - const txCost = await provider.getTransactionCost(request, { - resourcesOwner: wallet, - }); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -161,7 +159,6 @@ describe('Fee', () => { using launched = await launchTestNode(); const { - provider, wallets: [wallet], } = launched; @@ -173,7 +170,7 @@ describe('Fee', () => { wallet ); const { transactionRequest } = factory.createTransactionRequest(); - const txCost = await provider.getTransactionCost(transactionRequest); + const txCost = await wallet.getTransactionCost(transactionRequest); transactionRequest.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/funding-transaction.test.ts b/packages/fuel-gauge/src/funding-transaction.test.ts index 322bf5ea276..23e7838fa9c 100644 --- a/packages/fuel-gauge/src/funding-transaction.test.ts +++ b/packages/fuel-gauge/src/funding-transaction.test.ts @@ -34,7 +34,7 @@ describe('Funding Transactions', () => { const resources = await mainWallet.getResourcesToSpend([[totalAmount + 2_000, baseAssetId]]); request.addResources(resources); - const txCost = await mainWallet.provider.getTransactionCost(request); + const txCost = await mainWallet.getTransactionCost(request); request.maxFee = txCost.maxFee; request.gasLimit = txCost.gasUsed; @@ -75,7 +75,7 @@ describe('Funding Transactions', () => { request.addCoinOutput(receiver.address, amountToTransfer, provider.getBaseAssetId()); - const txCost = await provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); @@ -132,7 +132,7 @@ describe('Funding Transactions', () => { request.addCoinOutput(receiver.address, amountToTransfer, provider.getBaseAssetId()); request.addResources(enoughtResources); - const txCost = await provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); // TX request already carries enough resources, it does not need to be funded expect(request.inputs.length).toBe(1); @@ -186,7 +186,7 @@ describe('Funding Transactions', () => { const amountToTransfer = 1000; request.addCoinOutput(receiver.address, amountToTransfer, provider.getBaseAssetId()); - const txCost = await provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); // TX request does NOT carry any resources, it needs to be funded expect(request.inputs.length).toBe(0); @@ -242,7 +242,7 @@ describe('Funding Transactions', () => { const amountToTransfer = 1000; request.addCoinOutput(receiver.address, amountToTransfer, provider.getBaseAssetId()); - const txCost = await provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); expect(request.inputs.length).toBe(0); @@ -308,7 +308,7 @@ describe('Funding Transactions', () => { transactionRequest.addCoinOutput(receiver.address, totalInAssetA, assetA); // Executing getTransactionCost to proper estimate maxFee and gasLimit - const txCost = await provider.getTransactionCost(transactionRequest); + const txCost = await wallet1.getTransactionCost(transactionRequest); transactionRequest.gasLimit = txCost.gasUsed; transactionRequest.maxFee = txCost.maxFee; @@ -369,7 +369,7 @@ describe('Funding Transactions', () => { transactionRequest.addCoinOutput(receiver.address, 3000, assetA); transactionRequest.addCoinOutput(receiver.address, 4500, assetB); - const txCost = await provider.getTransactionCost(transactionRequest); + const txCost = await fundedWallet.getTransactionCost(transactionRequest); transactionRequest.gasLimit = txCost.gasUsed; transactionRequest.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/min-gas.test.ts b/packages/fuel-gauge/src/min-gas.test.ts index 39a56b19d48..d1b7826f14c 100644 --- a/packages/fuel-gauge/src/min-gas.test.ts +++ b/packages/fuel-gauge/src/min-gas.test.ts @@ -55,7 +55,7 @@ describe('Minimum gas tests', () => { /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const { maxFee } = await provider.getTransactionCost(request); + const { maxFee } = await wallet.getTransactionCost(request); request.maxFee = maxFee; @@ -89,7 +89,7 @@ describe('Minimum gas tests', () => { /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const txCost = await provider.getTransactionCost(request); + const txCost = await sender.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -134,7 +134,7 @@ describe('Minimum gas tests', () => { /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const txCost = await provider.getTransactionCost(request, { resourcesOwner: predicate }); + const txCost = await predicate.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -193,9 +193,7 @@ describe('Minimum gas tests', () => { // add account transfer request.addCoinOutput(Address.fromRandom(), bn(100), baseAssetId); - const txCost = await provider.getTransactionCost(request, { - resourcesOwner: predicate, - }); + const txCost = await predicate.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/policies.test.ts b/packages/fuel-gauge/src/policies.test.ts index 3ccc1853f82..d3428143010 100644 --- a/packages/fuel-gauge/src/policies.test.ts +++ b/packages/fuel-gauge/src/policies.test.ts @@ -128,7 +128,7 @@ describe('Policies', () => { txRequest.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); - const txCost = await provider.getTransactionCost(txRequest); + const txCost = await wallet.getTransactionCost(txRequest); txRequest.gasLimit = txCost.gasUsed; txRequest.maxFee = txCost.maxFee; @@ -152,7 +152,6 @@ describe('Policies', () => { using launched = await launchTestNode(); const { - provider, wallets: [wallet], } = launched; @@ -170,7 +169,7 @@ describe('Policies', () => { const { transactionRequest: txRequest } = factory.createTransactionRequest(txParams); - const txCost = await provider.getTransactionCost(txRequest); + const txCost = await wallet.getTransactionCost(txRequest); txRequest.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts index 976a41a59ff..a1bbb321839 100644 --- a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts +++ b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts @@ -47,7 +47,7 @@ describe('PredicateConditionalInputs', () => { .addResources(predicateResoruces) .addCoinOutput(aliceWallet.address, amountToTransfer, ASSET_A); - const txCost = await aliceWallet.provider.getTransactionCost(request, { + const txCost = await aliceWallet.getTransactionCost(request, { resourcesOwner: aliceWallet, }); @@ -132,7 +132,7 @@ describe('PredicateConditionalInputs', () => { .addResources(predicateResources) .addCoinOutput(aliceWallet.address, amountToTransfer, ASSET_A); - const txCost = await aliceWallet.provider.getTransactionCost(request); + const txCost = await aliceWallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts index d23d89e5226..ae37ba15489 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts @@ -18,7 +18,7 @@ export const fundPredicate = async ( ); } - const txCost = await wallet.provider.getTransactionCost(request); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; await wallet.fund(request, txCost); diff --git a/packages/fuel-gauge/src/revert-error.test.ts b/packages/fuel-gauge/src/revert-error.test.ts index dd53b87a1a8..a1e27f325f1 100644 --- a/packages/fuel-gauge/src/revert-error.test.ts +++ b/packages/fuel-gauge/src/revert-error.test.ts @@ -196,7 +196,6 @@ describe('Revert Error Testing', () => { const { wallets: [wallet], - provider, } = launched; const factory = new ContractFactory(TokenContractAbiHex, TokenContractAbi__factory.abi, wallet); @@ -216,7 +215,7 @@ describe('Revert Error Testing', () => { ]) .getTransactionRequest(); - const txCost = await provider.getTransactionCost(request); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/fuel-gauge/src/transaction-response.test.ts b/packages/fuel-gauge/src/transaction-response.test.ts index 926a465e9eb..1ad07b059b2 100644 --- a/packages/fuel-gauge/src/transaction-response.test.ts +++ b/packages/fuel-gauge/src/transaction-response.test.ts @@ -229,7 +229,7 @@ describe('TransactionResponse', () => { request.addCoinOutput(Wallet.generate(), 100, provider.getBaseAssetId()); - const txCost = await genesisWallet.provider.getTransactionCost(request); + const txCost = await genesisWallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -272,7 +272,7 @@ describe('TransactionResponse', () => { request.addCoinOutput(Wallet.generate(), 100, provider.getBaseAssetId()); - const txCost = await genesisWallet.provider.getTransactionCost(request, { + const txCost = await genesisWallet.getTransactionCost(request, { signatureCallback: (tx) => tx.addAccountWitnesses(genesisWallet), }); diff --git a/packages/fuel-gauge/src/transaction-summary.test.ts b/packages/fuel-gauge/src/transaction-summary.test.ts index 840eafae653..89bfae3935a 100644 --- a/packages/fuel-gauge/src/transaction-summary.test.ts +++ b/packages/fuel-gauge/src/transaction-summary.test.ts @@ -73,7 +73,7 @@ describe('TransactionSummary', () => { request.addCoinOutput(destination.address, amountToTransfer, provider.getBaseAssetId()); - const txCost = await adminWallet.provider.getTransactionCost(request); + const txCost = await adminWallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -162,7 +162,7 @@ describe('TransactionSummary', () => { gasLimit: 10000, }); - const txCost = await adminWallet.provider.getTransactionCost(request); + const txCost = await adminWallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; @@ -566,7 +566,7 @@ describe('TransactionSummary', () => { }); }); - const txCost = await provider.getTransactionCost(request); + const txCost = await wallet.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee; diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index 45aa8d169cf..527027fb7ef 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -63,6 +63,7 @@ export abstract class AbstractAccount { abstract getResourcesToSpend(quantities: any[], options?: any): any; abstract sendTransaction(transactionRequest: any, options?: any): any; abstract simulateTransaction(transactionRequest: any, options?: any): any; + abstract getTransactionCost(transactionRequest: any, options?: any): Promise; abstract fund(transactionRequest: any, txCost: any): Promise; } /** @@ -76,6 +77,7 @@ export abstract class AbstractProgram { abstract provider: { sendTransaction(transactionRequest: any, options?: any): any; + getTransactionCost(transactionRequest: any, options?: any): Promise; } | null; } diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index f5bbcda27a0..4594069cb03 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -8,8 +8,9 @@ import type { Account, TransferParams, TransactionResponse, + TransactionCost, } from '@fuel-ts/account'; -import { ScriptTransactionRequest } from '@fuel-ts/account'; +import { ScriptTransactionRequest, Wallet } from '@fuel-ts/account'; import { Address } from '@fuel-ts/address'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { AbstractAccount, AbstractContract, AbstractProgram } from '@fuel-ts/interfaces'; @@ -228,22 +229,19 @@ export class BaseInvocationScope { } /** - * Gets the transaction cost ny dry running the transaction. + * Gets the transaction cost for dry running the transaction. * * @param options - Optional transaction cost options. * @returns The transaction cost details. */ - async getTransactionCost() { - const provider = this.getProvider(); - - const request = await this.getTransactionRequest(); - const txCost = await provider.getTransactionCost(request, { - resourcesOwner: this.program.account as AbstractAccount, - quantitiesToContract: this.getRequiredCoins(), + async getTransactionCost(): Promise { + const request = clone(await this.getTransactionRequest()); + const account: AbstractAccount = + this.program.account ?? Wallet.generate({ provider: this.getProvider() }); + return account.getTransactionCost(request, { + quantities: this.getRequiredCoins(), signatureCallback: this.addSignersCallback, }); - - return txCost; } /** diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index f11dfa59bb9..ef107a70911 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -45,7 +45,7 @@ const callScript = async ( // Keep a list of coins we need to input to this transaction - const txCost = await account.provider.getTransactionCost(request); + const txCost = await account.getTransactionCost(request); request.gasLimit = txCost.gasUsed; request.maxFee = txCost.maxFee;