diff --git a/.changeset/shaggy-zebras-obey.md b/.changeset/shaggy-zebras-obey.md new file mode 100644 index 00000000000..8432ac5f5a5 --- /dev/null +++ b/.changeset/shaggy-zebras-obey.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/account": minor +"@fuel-ts/program": minor +--- + +feat!: `autoCost` for transaction estimation and funding diff --git a/apps/docs/src/guide/cookbook/snippets/custom-contract-calls.ts b/apps/docs/src/guide/cookbook/snippets/custom-contract-calls.ts index 407895191ab..f232d38c23d 100644 --- a/apps/docs/src/guide/cookbook/snippets/custom-contract-calls.ts +++ b/apps/docs/src/guide/cookbook/snippets/custom-contract-calls.ts @@ -32,12 +32,8 @@ transactionRequest.addCoinOutput( provider.getBaseAssetId() ); -const txCost = await wallet.getTransactionCost(transactionRequest); - -transactionRequest.gasLimit = txCost.gasUsed; -transactionRequest.maxFee = txCost.maxFee; - -await wallet.fund(transactionRequest, txCost); +// Estimate and fund the transaction +await transactionRequest.autoCost(wallet); // Submit the transaction const response = await wallet.sendTransaction(transactionRequest); diff --git a/apps/docs/src/guide/cookbook/snippets/signing-transactions/predicate.ts b/apps/docs/src/guide/cookbook/snippets/signing-transactions/predicate.ts index 7960be54fd5..a60d8f72870 100644 --- a/apps/docs/src/guide/cookbook/snippets/signing-transactions/predicate.ts +++ b/apps/docs/src/guide/cookbook/snippets/signing-transactions/predicate.ts @@ -46,23 +46,15 @@ const resources = await predicate.getResourcesToSpend([ amount: amountToReceiver, }, ]); - request.addResources(resources); -request.addWitness('0x'); -// Add witnesses including the signer -// Estimate the predicate inputs -const txCost = await predicate.getTransactionCost(request, { +// Estimate and fund the request +request.addWitness('0x'); +await request.autoCost(predicate, { signatureCallback: (txRequest) => txRequest.addAccountWitnesses(signer), }); -request.updatePredicateGasUsed(txCost.estimatedPredicates); - -request.gasLimit = txCost.gasUsed; -request.maxFee = txCost.maxFee; - -await predicate.fund(request, txCost); - +// Add the signer as a witness await request.addAccountWitnesses(signer); // Send the transaction diff --git a/apps/docs/src/guide/encoding/snippets/encode-and-decode.ts b/apps/docs/src/guide/encoding/snippets/encode-and-decode.ts index 785d379b190..f715c15029d 100644 --- a/apps/docs/src/guide/encoding/snippets/encode-and-decode.ts +++ b/apps/docs/src/guide/encoding/snippets/encode-and-decode.ts @@ -56,11 +56,8 @@ const encodedArguments = abiInterface.encodeType(argument, [argumentToAdd]); // The encoded value can now be set on the transaction via the script data property request.scriptData = encodedArguments; -// Now we can build out the rest of the transaction and then fund it -const txCost = await wallet.getTransactionCost(request); -request.maxFee = txCost.maxFee; -request.gasLimit = txCost.gasUsed; -await wallet.fund(request, txCost); +// Now we can estimate and fund the transaction +await request.autoCost(wallet); // Finally, submit the built transaction const response = await wallet.sendTransaction(request); diff --git a/apps/docs/src/guide/predicates/snippets/custom-transactions.ts b/apps/docs/src/guide/predicates/snippets/custom-transactions.ts index cbf976af3a0..d87dbc8b35f 100644 --- a/apps/docs/src/guide/predicates/snippets/custom-transactions.ts +++ b/apps/docs/src/guide/predicates/snippets/custom-transactions.ts @@ -42,10 +42,7 @@ customRequest.addResources(predicateResources); customRequest.addCoinOutput(receiver.address, amountToReceiver, assetId); // Estimate the transaction cost and fund accordingly -const txCost = await predicate.getTransactionCost(customRequest); -customRequest.gasLimit = txCost.gasUsed; -customRequest.maxFee = txCost.maxFee; -await predicate.fund(customRequest, txCost); +await customRequest.autoCost(predicate); // Submit the transaction and await it's result const predicateTx = await predicate.sendTransaction(customRequest); diff --git a/apps/docs/src/guide/predicates/snippets/methods/send-transaction.ts b/apps/docs/src/guide/predicates/snippets/methods/send-transaction.ts index cfcab9cbfb9..8da669cae83 100644 --- a/apps/docs/src/guide/predicates/snippets/methods/send-transaction.ts +++ b/apps/docs/src/guide/predicates/snippets/methods/send-transaction.ts @@ -33,12 +33,8 @@ const predicateCoins = await predicate.getResourcesToSpend([ // Add the predicate input and resources. transactionRequest.addResources(predicateCoins); -const txCost = await predicate.getTransactionCost(transactionRequest); - -transactionRequest.gasLimit = txCost.gasUsed; -transactionRequest.maxFee = txCost.maxFee; - -await predicate.fund(transactionRequest, txCost); +// Estimate and fund the transaction +await transactionRequest.autoCost(predicate); // Send the transaction using the predicate const result = await predicate.sendTransaction(transactionRequest); diff --git a/apps/docs/src/guide/predicates/snippets/methods/simulate-transaction.ts b/apps/docs/src/guide/predicates/snippets/methods/simulate-transaction.ts index ed8012819ca..c92254357ca 100644 --- a/apps/docs/src/guide/predicates/snippets/methods/simulate-transaction.ts +++ b/apps/docs/src/guide/predicates/snippets/methods/simulate-transaction.ts @@ -37,12 +37,8 @@ transactionRequest.addCoinOutput( provider.getBaseAssetId() ); -const txCost = await predicate.getTransactionCost(transactionRequest); - -transactionRequest.gasLimit = txCost.gasUsed; -transactionRequest.maxFee = txCost.maxFee; - -await predicate.fund(transactionRequest, txCost); +// Estimate and fund the transaction +await transactionRequest.autoCost(predicate); const result = await predicate.simulateTransaction(transactionRequest); diff --git a/apps/docs/src/guide/scripts/snippets/script-custom-transaction.ts b/apps/docs/src/guide/scripts/snippets/script-custom-transaction.ts index db74eca5637..7401e4c25f7 100644 --- a/apps/docs/src/guide/scripts/snippets/script-custom-transaction.ts +++ b/apps/docs/src/guide/scripts/snippets/script-custom-transaction.ts @@ -47,13 +47,8 @@ const quantities = [ coinQuantityfy([500, ASSET_B]), ]; -// 5. Calculate the transaction fee -const txCost = await wallet.getTransactionCost(request, { quantities }); - -request.gasLimit = txCost.gasUsed; -request.maxFee = txCost.maxFee; - -await wallet.fund(request, txCost); +// 5. Estimate and fund the transaction +await request.autoCost(wallet, { quantities }); // 6. Send the transaction const tx = await wallet.sendTransaction(request); diff --git a/apps/docs/src/guide/transactions/snippets/transaction-request/auto-cost.ts b/apps/docs/src/guide/transactions/snippets/transaction-request/auto-cost.ts new file mode 100644 index 00000000000..15da0622c38 --- /dev/null +++ b/apps/docs/src/guide/transactions/snippets/transaction-request/auto-cost.ts @@ -0,0 +1,17 @@ +import { Provider, ScriptTransactionRequest, Wallet } from 'fuels'; + +import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../../../../env'; +import { ScriptSum } from '../../../../typegend'; + +const provider = await Provider.create(LOCAL_NETWORK_URL); +const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); + +// #region auto-cost +const transactionRequest = new ScriptTransactionRequest({ + script: ScriptSum.bytecode, +}); + +await transactionRequest.autoCost(wallet); + +await wallet.sendTransaction(transactionRequest); +// #endregion auto-cost diff --git a/apps/docs/src/guide/transactions/snippets/transaction-response/from-submitted-request.ts b/apps/docs/src/guide/transactions/snippets/transaction-response/from-submitted-request.ts index a66a82ac260..40e48710850 100644 --- a/apps/docs/src/guide/transactions/snippets/transaction-response/from-submitted-request.ts +++ b/apps/docs/src/guide/transactions/snippets/transaction-response/from-submitted-request.ts @@ -25,12 +25,7 @@ const scriptMainFunctionArguments = [1]; transactionRequest.setData(ScriptSum.abi, scriptMainFunctionArguments); // Fund the transaction -const txCost = await wallet.getTransactionCost(transactionRequest); - -transactionRequest.maxFee = txCost.maxFee; -transactionRequest.gasLimit = txCost.gasUsed; - -await wallet.fund(transactionRequest, txCost); +await transactionRequest.autoCost(wallet); // Submit the transaction const response = await wallet.sendTransaction(transactionRequest); diff --git a/apps/docs/src/guide/transactions/transaction-request.md b/apps/docs/src/guide/transactions/transaction-request.md index 6d7b7337a82..121ee218485 100644 --- a/apps/docs/src/guide/transactions/transaction-request.md +++ b/apps/docs/src/guide/transactions/transaction-request.md @@ -38,11 +38,17 @@ Including `OutputCoin`s in the transaction request specifies the UTXOs that will ### Estimating and Funding the Transaction Request -Before submitting a transaction, it is essential to ensure it is properly funded to meet its requirements and cover the associated fee: +Before submitting a transaction, it is essential to ensure it is properly funded to meet its requirements and cover the associated fee. The SDK offers two approaches for this, one is to use the `autoCost` helper: + +<<< @./snippets/transaction-request/auto-cost.ts#auto-cost{ts:line-numbers} + +This approach provides a simple one-liner for estimating and funding the transaction request. Ensuring that the `gasLimit` and `maxFee` are accurately calculated and that the required amounts for `OutputCoin`s are fulfilled, as well as fetching and adding any missing resources from the calling account. + +The other more manual approach is as so: <<< @./snippets/transaction-request/estimate-and-fund.ts#transaction-request-4{ts:line-numbers} -This is the recommended approach for manually estimating and funding a transaction before submission. It ensures that the `gasLimit` and `maxFee` are accurately calculated and that the required amounts for `OutputCoin`s are fulfilled. The `fund` method automatically fetches any missing resource amounts from the calling account and adds them to the transaction request. +This approach provides the same behaviour as the `autoCost` helper, but gives more granular control over the transaction request. The `getTransactionCost` method also returns various information about the simulated request that you may want to use to further modify the transaction request, more on that can be found in the [API reference](https://fuels-ts-docs-api.vercel.app/types/_fuel_ts_account.TransactionCost.html). ### Manually Fetching Resources diff --git a/apps/docs/src/guide/wallets/snippets/signing/fund-transaction.ts b/apps/docs/src/guide/wallets/snippets/signing/fund-transaction.ts index ce6df960d24..785653af82b 100644 --- a/apps/docs/src/guide/wallets/snippets/signing/fund-transaction.ts +++ b/apps/docs/src/guide/wallets/snippets/signing/fund-transaction.ts @@ -13,12 +13,7 @@ const request = new ScriptTransactionRequest({ request.addCoinOutput(receiverAddress, 1000, provider.getBaseAssetId()); -const txCost = await sender.getTransactionCost(request); - -request.gasLimit = txCost.gasUsed; -request.maxFee = txCost.maxFee; - -await sender.fund(request, txCost); +await request.autoCost(sender); const tx = await sender.sendTransaction(request); await tx.waitForResult(); diff --git a/apps/docs/src/guide/wallets/snippets/signing/sign-transaction.ts b/apps/docs/src/guide/wallets/snippets/signing/sign-transaction.ts index dabaab4a0f1..47f9dff7183 100644 --- a/apps/docs/src/guide/wallets/snippets/signing/sign-transaction.ts +++ b/apps/docs/src/guide/wallets/snippets/signing/sign-transaction.ts @@ -19,12 +19,7 @@ const request = new ScriptTransactionRequest({ request.addCoinOutput(receiverAddress, 1000, provider.getBaseAssetId()); -const txCost = await sender.getTransactionCost(request); - -request.gasLimit = txCost.gasUsed; -request.maxFee = txCost.maxFee; - -await sender.fund(request, txCost); +await request.autoCost(sender); const signedTransaction = await sender.signTransaction(request); const transactionId = request.getTransactionId(provider.getChainId()); diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index afdf434f5d4..952421917f9 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -610,12 +610,7 @@ describe('Account', () => { [amount, assetIdB], ]); - const txCost = await sender.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await sender.fund(request, txCost); + await request.autoCost(sender); const response = await sender.sendTransaction(request); @@ -722,12 +717,7 @@ describe('Account', () => { request.addCoinOutput(sender.address, amount.div(3), provider.getBaseAssetId()); } - const txCost = await fundingWallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await fundingWallet.fund(request, txCost); + await request.autoCost(fundingWallet); const tx1 = await fundingWallet.sendTransaction(request); await tx1.waitForResult(); @@ -799,12 +789,7 @@ describe('Account', () => { request.addCoinOutput(sender.address, fundingAmount.div(3), provider.getBaseAssetId()); } - const txCost = await fundingWallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await fundingWallet.fund(request, txCost); + await request.autoCost(fundingWallet); const tx1 = await fundingWallet.sendTransaction(request); await tx1.waitForResult(); @@ -967,12 +952,7 @@ describe('Account', () => { const request = new ScriptTransactionRequest(); request.addCoinOutput(wallet.address, 30_000, provider.getBaseAssetId()); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await expectToThrowFuelError(() => wallet.fund(request, txCost), { + await expectToThrowFuelError(() => request.autoCost(wallet), { 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.', diff --git a/packages/account/src/providers/transaction-request/script-transaction-request.ts b/packages/account/src/providers/transaction-request/script-transaction-request.ts index 07dc474cc4b..db3ae35157d 100644 --- a/packages/account/src/providers/transaction-request/script-transaction-request.ts +++ b/packages/account/src/providers/transaction-request/script-transaction-request.ts @@ -10,7 +10,8 @@ import { InputType, OutputType, TransactionType } from '@fuel-ts/transactions'; import { arrayify, hexlify } from '@fuel-ts/utils'; import { clone } from 'ramda'; -import type { ChainInfo, GasCosts } from '../provider'; +import type { Account } from '../../account'; +import type { ChainInfo, GasCosts, TransactionCostParams } from '../provider'; import { calculateMetadataGasForTxScript, getMaxGas } from '../utils/gas'; import { hashTransaction } from './hash-transaction'; @@ -67,6 +68,27 @@ export class ScriptTransactionRequest extends BaseTransactionRequest { this.abis = rest.abis; } + /** + * Helper function to fund the transaction request with a specified account. + * + * @param account - The account to fund the transaction. + * @param params - The parameters for the transaction cost. + * @returns The current instance of the `ScriptTransactionRequest` funded. + */ + async autoCost( + account: Account, + { signatureCallback, quantities = [] }: TransactionCostParams = {} + ): Promise { + const txCost = await account.getTransactionCost(this, { signatureCallback, quantities }); + + this.maxFee = txCost.maxFee; + this.gasLimit = txCost.gasUsed; + + await account.fund(this, txCost); + + return this; + } + /** * Converts the transaction request to a `TransactionScript`. * diff --git a/packages/fuel-gauge/src/advanced-logging.test.ts b/packages/fuel-gauge/src/advanced-logging.test.ts index 44d6b51d469..3bc591c95cd 100644 --- a/packages/fuel-gauge/src/advanced-logging.test.ts +++ b/packages/fuel-gauge/src/advanced-logging.test.ts @@ -233,12 +233,7 @@ describe('Advanced Logging', () => { ]) .getTransactionRequest(); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await wallet.fund(request, txCost); + await request.autoCost(wallet); const tx = await wallet.sendTransaction(request, { estimateTxDependencies: false }); @@ -312,12 +307,7 @@ describe('Advanced Logging', () => { .addContracts([advancedLogContract, otherAdvancedLogContract]) .getTransactionRequest(); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await wallet.fund(request, txCost); + await request.autoCost(wallet); const tx = await wallet.sendTransaction(request); diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 04fe5dffc7d..27db5599b50 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -553,7 +553,7 @@ describe('Contract', () => { const struct = { a: true, b: 1337 }; const invocationScopes = [contract.functions.foo(num), contract.functions.boo(struct)]; const multiCallScope = contract.multiCall(invocationScopes); - const transactionRequest = await multiCallScope.fundWithRequiredCoins(); + const transactionRequest = await multiCallScope.autoCost(); const txRequest = JSON.stringify(transactionRequest); const txRequestParsed = JSON.parse(txRequest); diff --git a/packages/fuel-gauge/src/coverage-contract.test.ts b/packages/fuel-gauge/src/coverage-contract.test.ts index 0e8646708da..071ce89c778 100644 --- a/packages/fuel-gauge/src/coverage-contract.test.ts +++ b/packages/fuel-gauge/src/coverage-contract.test.ts @@ -665,12 +665,7 @@ describe('Coverage Contract', { timeout: 15_000 }, () => { request.addCoinOutput(recipient.address, 10, provider.getBaseAssetId()); - const txCost = await sender.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await sender.fund(request, txCost); + await request.autoCost(sender); const response = await sender.sendTransaction(request); const result = await response.waitForResult(); diff --git a/packages/fuel-gauge/src/fee.test.ts b/packages/fuel-gauge/src/fee.test.ts index f5c5a53440e..b5e48c8dafe 100644 --- a/packages/fuel-gauge/src/fee.test.ts +++ b/packages/fuel-gauge/src/fee.test.ts @@ -145,12 +145,7 @@ describe('Fee', () => { request.addCoinOutput(destination2.address, amountToTransfer, ASSET_A); request.addCoinOutput(destination3.address, amountToTransfer, ASSET_B); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await wallet.fund(request, txCost); + await request.autoCost(wallet); const tx = await wallet.sendTransaction(request); const { fee } = await tx.wait(); diff --git a/packages/fuel-gauge/src/funding-transaction.test.ts b/packages/fuel-gauge/src/funding-transaction.test.ts index 3891decd239..f771894a697 100644 --- a/packages/fuel-gauge/src/funding-transaction.test.ts +++ b/packages/fuel-gauge/src/funding-transaction.test.ts @@ -4,6 +4,8 @@ import type { Account, CoinTransactionRequestInput } from 'fuels'; import { DEFAULT_RESOURCE_CACHE_TTL, ScriptTransactionRequest, Wallet, bn, sleep } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; +import { CallTestContractFactory } from '../test/typegen'; + /** * @group node * @group browser @@ -514,4 +516,85 @@ describe('Funding Transactions', () => { /Transaction input validation failed: Transaction id already exists \(id: .*\)/ ); }, 15_000); + + it('funds a script transaction using autoCost', async () => { + using launched = await launchTestNode(); + + const { + provider, + wallets: [sender, receiver], + } = launched; + + const request = new ScriptTransactionRequest().addCoinOutput( + receiver.address, + 1000, + provider.getBaseAssetId() + ); + + expect(request.inputs.length).toBe(0); + expect(request.maxFee.toNumber()).toBe(0); + expect(request.gasLimit.toNumber()).toBe(0); + + await request.autoCost(sender); + + expect(request.inputs.length).toBe(1); + expect(request.maxFee.toNumber()).toBeGreaterThan(0); + expect(request.gasLimit.toNumber()).toBeGreaterThan(0); + + const tx = await sender.sendTransaction(request); + const result = await tx.waitForResult(); + + expect(result.isStatusSuccess).toBeTruthy(); + }); + + it('funds a script tx from contract call using autoCost', async () => { + using launched = await launchTestNode({ + contractsConfigs: [{ factory: CallTestContractFactory }], + }); + + const { + wallets: [sender], + contracts: [contract], + } = launched; + + const request = await contract.functions.no_params().getTransactionRequest(); + + expect(request.inputs.length).toBe(1); + expect(request.maxFee.toNumber()).toBe(0); + expect(request.gasLimit.toNumber()).toBe(0); + + await request.autoCost(sender); + + expect(request.inputs.length).toBe(2); + expect(request.maxFee.toNumber()).toBeGreaterThan(0); + expect(request.gasLimit.toNumber()).toBeGreaterThan(0); + + const tx = await sender.sendTransaction(request); + const result = await tx.waitForResult(); + + expect(result.isStatusSuccess).toBeTruthy(); + }); + + it('funds a contract call using autoCost', async () => { + using launched = await launchTestNode({ + contractsConfigs: [{ factory: CallTestContractFactory }], + }); + + const { + wallets: [sender], + contracts: [contract], + } = launched; + + const scope = await contract.functions.no_params(); + const request = await scope.autoCost(); + + expect(request.inputs.length).toBe(2); + expect(request.maxFee.toNumber()).toBeGreaterThan(0); + expect(request.gasLimit.toNumber()).toBeGreaterThan(0); + + const tx = await sender.sendTransaction(request); + const result = await tx.waitForResult(); + + expect(result.isStatusSuccess).toBeTruthy(); + }); }); diff --git a/packages/fuel-gauge/src/policies.test.ts b/packages/fuel-gauge/src/policies.test.ts index dd0db917c30..87cfc03eaaf 100644 --- a/packages/fuel-gauge/src/policies.test.ts +++ b/packages/fuel-gauge/src/policies.test.ts @@ -127,12 +127,7 @@ describe('Policies', () => { txRequest.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); - const txCost = await wallet.getTransactionCost(txRequest); - - txRequest.gasLimit = txCost.gasUsed; - txRequest.maxFee = txCost.maxFee; - - await wallet.fund(txRequest, txCost); + await txRequest.autoCost(wallet); const tx = await wallet.sendTransaction(txRequest); diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/fundAccount.ts b/packages/fuel-gauge/src/predicate/utils/predicate/fundAccount.ts index 26587ab0de7..4e90a3feb95 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/fundAccount.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/fundAccount.ts @@ -14,10 +14,7 @@ export const fundAccount = async ( request.addCoinOutput(accountToBeFunded.address, new BN(amount).div(utxosAmount), baseAssetId); } - const txCost = await fundedAccount.getTransactionCost(request); - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - await fundedAccount.fund(request, txCost); + await request.autoCost(fundedAccount); const submit = await fundedAccount.sendTransaction(request); await submit.waitForResult(); diff --git a/packages/fuel-gauge/src/revert-error.test.ts b/packages/fuel-gauge/src/revert-error.test.ts index 7fa401c33e6..7bb2921f2f3 100644 --- a/packages/fuel-gauge/src/revert-error.test.ts +++ b/packages/fuel-gauge/src/revert-error.test.ts @@ -211,12 +211,7 @@ describe('Revert Error Testing', () => { ]) .getTransactionRequest(); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await wallet.fund(request, txCost); + await request.autoCost(wallet); const tx = await wallet.sendTransaction(request, { estimateTxDependencies: false, diff --git a/packages/fuel-gauge/src/transaction-response.test.ts b/packages/fuel-gauge/src/transaction-response.test.ts index a9763a3112a..b1c2e7d8043 100644 --- a/packages/fuel-gauge/src/transaction-response.test.ts +++ b/packages/fuel-gauge/src/transaction-response.test.ts @@ -239,12 +239,7 @@ describe('TransactionResponse', () => { request.addCoinOutput(Wallet.generate(), 100, provider.getBaseAssetId()); - const txCost = await genesisWallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await genesisWallet.fund(request, txCost); + await request.autoCost(genesisWallet); request.updateWitnessByOwner( genesisWallet.address, @@ -291,15 +286,10 @@ describe('TransactionResponse', () => { request.addCoinOutput(Wallet.generate(), 100, provider.getBaseAssetId()); - const txCost = await genesisWallet.getTransactionCost(request, { + await request.autoCost(genesisWallet, { signatureCallback: (tx) => tx.addAccountWitnesses(genesisWallet), }); - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await genesisWallet.fund(request, txCost); - request.updateWitnessByOwner( genesisWallet.address, await genesisWallet.signTransaction(request) diff --git a/packages/fuel-gauge/src/transaction-summary.test.ts b/packages/fuel-gauge/src/transaction-summary.test.ts index ca8d53e9acd..b230bdd69da 100644 --- a/packages/fuel-gauge/src/transaction-summary.test.ts +++ b/packages/fuel-gauge/src/transaction-summary.test.ts @@ -235,12 +235,7 @@ describe('TransactionSummary', () => { gasLimit: 10000, }); - const txCost = await sender.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await sender.fund(request, txCost); + await request.autoCost(sender); const transactionRequest = await sender.populateTransactionWitnessesSignature(request); @@ -770,12 +765,7 @@ describe('TransactionSummary', () => { }); }); - const txCost = await wallet.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await wallet.fund(request, txCost); + await request.autoCost(wallet); const tx = await wallet.sendTransaction(request); diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts index 3befa770c10..f26204ae61b 100644 --- a/packages/fuel-gauge/src/transaction.test.ts +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -64,12 +64,7 @@ describe('Transaction', () => { const request = await contract.functions.foo(10).getTransactionRequest(); request.addMessageInput(message); - const cost = await fundedWallet.getTransactionCost(request); - - request.gasLimit = cost.gasUsed; - request.maxFee = cost.maxFee; - - await fundedWallet.fund(request, cost); + await request.autoCost(fundedWallet); const tx = await fundedWallet.sendTransaction(request); @@ -120,12 +115,7 @@ describe('Transaction', () => { const request = await contract.functions.foo(10).getTransactionRequest(); request.addMessageInput(message); - const cost = await fundedWallet.getTransactionCost(request); - - request.gasLimit = cost.gasUsed; - request.maxFee = cost.maxFee; - - await fundedWallet.fund(request, cost); + await request.autoCost(fundedWallet); const tx = await fundedWallet.sendTransaction(request); diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index e578954d9a0..7312fdaec0c 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -245,11 +245,11 @@ export class BaseInvocationScope { } /** - * Funds the transaction with the required coins. + * Costs and funds the underlying transaction request. * - * @returns The current instance of the class. + * @returns The invocation scope as a funded transaction request. */ - async fundWithRequiredCoins() { + async autoCost(): Promise { let transactionRequest = await this.getTransactionRequest(); transactionRequest = clone(transactionRequest); @@ -380,7 +380,7 @@ export class BaseInvocationScope { }> { assert(this.program.account, 'Wallet is required!'); - const transactionRequest = await this.fundWithRequiredCoins(); + const transactionRequest = await this.autoCost(); const response = (await this.program.account.sendTransaction(transactionRequest, { estimateTxDependencies: false, @@ -414,7 +414,7 @@ export class BaseInvocationScope { 'An unlocked wallet is required to simulate a contract call.' ); } - const transactionRequest = await this.fundWithRequiredCoins(); + const transactionRequest = await this.autoCost(); const callResult = await this.program.account.simulateTransaction(transactionRequest, { estimateTxDependencies: false, diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index 069c02c0429..70bf1655b5a 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -36,13 +36,7 @@ const callScript = async ( // Keep a list of coins we need to input to this transaction - const txCost = await account.getTransactionCost(request); - - request.gasLimit = txCost.gasUsed; - request.maxFee = txCost.maxFee; - - await account.fund(request, txCost); - + await request.autoCost(account); const response = await account.sendTransaction(request); const transactionResult = await response.waitForResult(); const result = script.decodeCallResult(transactionResult);