diff --git a/.changeset/sharp-islands-collect.md b/.changeset/sharp-islands-collect.md new file mode 100644 index 00000000000..17c594e15b3 --- /dev/null +++ b/.changeset/sharp-islands-collect.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": patch +--- + +feat: added `onBeforeSend` hook to the connector interface diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 63399b918d5..8ab6ecf20e6 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -10,7 +10,7 @@ import type { BytesLike } from '@fuel-ts/utils'; import { arrayify, hexlify, isDefined } from '@fuel-ts/utils'; import { clone } from 'ramda'; -import type { FuelConnector } from './connectors'; +import type { FuelConnector, FuelConnectorSendTxParams } from './connectors'; import type { TransactionRequest, CoinQuantityLike, @@ -23,7 +23,6 @@ import type { EstimateTransactionParams, CursorPaginationArgs, TransactionRequestLike, - ProviderSendTxParams, CallResult, GetCoinsResponse, GetMessagesResponse, @@ -31,6 +30,7 @@ import type { Coin, TransactionCostParams, TransactionResponse, + ProviderSendTxParams, } from './providers'; import { withdrawScript, @@ -66,6 +66,8 @@ export type ContractTransferParams = { assetId: BytesLike; }; +export type AccountSendTxParams = ProviderSendTxParams & FuelConnectorSendTxParams; + export type EstimatedTxParams = Pick< TransactionCost, 'estimatedPredicates' | 'addedSignatures' | 'requiredQuantities' | 'updateMaxFee' | 'gasPrice' @@ -649,11 +651,14 @@ export class Account extends AbstractAccount implements WithAddress { */ async sendTransaction( transactionRequestLike: TransactionRequestLike, - { estimateTxDependencies = true }: ProviderSendTxParams = {} + { estimateTxDependencies = true, onBeforeSend, skipCustomFee = false }: AccountSendTxParams = {} ): Promise { if (this._connector) { return this.provider.getTransactionResponse( - await this._connector.sendTransaction(this.address.toString(), transactionRequestLike) + await this._connector.sendTransaction(this.address.toString(), transactionRequestLike, { + onBeforeSend, + skipCustomFee, + }) ); } const transactionRequest = transactionRequestify(transactionRequestLike); diff --git a/packages/account/src/connectors/fuel-connector.ts b/packages/account/src/connectors/fuel-connector.ts index 92d4346e932..0b0fd24f30a 100644 --- a/packages/account/src/connectors/fuel-connector.ts +++ b/packages/account/src/connectors/fuel-connector.ts @@ -14,6 +14,7 @@ import type { FuelEventArg, Version, SelectNetworkArguments, + FuelConnectorSendTxParams, } from './types'; interface Connector { @@ -42,7 +43,11 @@ interface Connector { signTransaction(address: string, transaction: TransactionRequestLike): Promise; // #endregion fuel-connector-method-signTransaction // #region fuel-connector-method-sendTransaction - sendTransaction(address: string, transaction: TransactionRequestLike): Promise; + sendTransaction( + address: string, + transaction: TransactionRequestLike, + params?: FuelConnectorSendTxParams + ): Promise; // #endregion fuel-connector-method-sendTransaction // #region fuel-connector-method-currentAccount currentAccount(): Promise; @@ -193,10 +198,14 @@ export abstract class FuelConnector extends EventEmitter implements Connector { * * @param address - The address to sign the transaction * @param transaction - The transaction to send - * + * @param params - Optional parameters to send the transaction * @returns The transaction id */ - async sendTransaction(_address: string, _transaction: TransactionRequestLike): Promise { + async sendTransaction( + _address: string, + _transaction: TransactionRequestLike, + _params?: FuelConnectorSendTxParams + ): Promise { throw new FuelError(FuelError.CODES.NOT_IMPLEMENTED, 'Method not implemented.'); } diff --git a/packages/account/src/connectors/types/data-type.ts b/packages/account/src/connectors/types/data-type.ts index 04a63ad028d..f4a6f85fa6c 100644 --- a/packages/account/src/connectors/types/data-type.ts +++ b/packages/account/src/connectors/types/data-type.ts @@ -1,6 +1,8 @@ import type { JsonAbi } from '@fuel-ts/abi-coder'; import type { RequireAtLeastOne } from 'type-fest'; +import type { TransactionRequest } from '../../providers'; + /** * @name Version */ @@ -42,3 +44,11 @@ export type SelectNetworkArguments = RequireAtLeastOne Promise; +}; diff --git a/packages/account/test/fixtures/mocked-connector.ts b/packages/account/test/fixtures/mocked-connector.ts index 09932d9a893..e8231278257 100644 --- a/packages/account/test/fixtures/mocked-connector.ts +++ b/packages/account/test/fixtures/mocked-connector.ts @@ -9,6 +9,7 @@ import type { ConnectorMetadata, Network, SelectNetworkArguments, + AccountSendTxParams, } from '../../src'; import { FuelConnector } from '../../src/connectors/fuel-connector'; import { FuelConnectorEventTypes } from '../../src/connectors/types'; @@ -105,12 +106,16 @@ export class MockConnector extends FuelConnector { return wallet.signMessage(_message); } - override async sendTransaction(_address: string, _transaction: TransactionRequestLike) { + override async sendTransaction( + _address: string, + _transaction: TransactionRequestLike, + _params: AccountSendTxParams + ) { const wallet = this._wallets.find((w) => w.address.toString() === _address); if (!wallet) { throw new Error('Wallet is not found!'); } - const { id } = await wallet.sendTransaction(_transaction); + const { id } = await wallet.sendTransaction(_transaction, _params); return id; } diff --git a/packages/account/test/fuel-wallet-connector.test.ts b/packages/account/test/fuel-wallet-connector.test.ts index 3bc9acf861c..0c56dcc8547 100644 --- a/packages/account/test/fuel-wallet-connector.test.ts +++ b/packages/account/test/fuel-wallet-connector.test.ts @@ -8,10 +8,10 @@ import type { BytesLike } from '@fuel-ts/utils'; import { TESTNET_NETWORK_URL } from '@internal/utils'; import { EventEmitter } from 'events'; -import type { Network, ProviderOptions, SelectNetworkArguments } from '../src'; +import type { AccountSendTxParams, Network, ProviderOptions, SelectNetworkArguments } from '../src'; import { Fuel } from '../src/connectors/fuel'; import { FuelConnectorEventType } from '../src/connectors/types'; -import { Provider, TransactionStatus } from '../src/providers'; +import { Provider, ScriptTransactionRequest, TransactionStatus } from '../src/providers'; import { setupTestProviderAndWallets, TestMessage } from '../src/test-utils'; import { Wallet } from '../src/wallet'; @@ -669,4 +669,39 @@ describe('Fuel Connector', () => { new FuelError(ErrorCode.INVALID_PROVIDER, 'Provider is not valid.') ); }); + + it('should ensure sendTransaction works just fine', async () => { + using launched = await setupTestProviderAndWallets(); + const { + provider, + wallets: [connectorWallet], + } = launched; + const connector = new MockConnector({ + wallets: [connectorWallet], + }); + const fuel = await new Fuel({ + connectors: [connector], + }); + + const sendTransactionSpy = vi.spyOn(connectorWallet, 'sendTransaction'); + + const request = new ScriptTransactionRequest(); + const resources = await connectorWallet.getResourcesToSpend([ + { assetId: await provider.getBaseAssetId(), amount: 1000 }, + ]); + request.addResources(resources); + await request.autoCost(connectorWallet); + + const params: AccountSendTxParams = { + onBeforeSend: vi.fn(), + skipCustomFee: true, + }; + const response = await fuel.sendTransaction( + connectorWallet.address.toString(), + request, + params + ); + expect(response).toBeDefined(); + expect(sendTransactionSpy).toHaveBeenCalledWith(request, params); + }); });