From 8f3ea55eb1e23cefc0419902a2ebbe10ee373ccb Mon Sep 17 00:00:00 2001 From: Iris Date: Tue, 20 Dec 2022 17:49:43 +0100 Subject: [PATCH] feat: update simulate tx --- __tests__/account.test.ts | 10 ++++++++++ src/account/default.ts | 33 +++++++++++++++++++++++++++++++++ src/account/interface.ts | 16 ++++++++++++++++ src/provider/default.ts | 9 +++++++++ src/provider/interface.ts | 8 ++++++++ src/provider/rpc.ts | 9 +++++++++ src/provider/sequencer.ts | 4 ++-- 7 files changed, 87 insertions(+), 2 deletions(-) diff --git a/__tests__/account.test.ts b/__tests__/account.test.ts index e5be2c23d..57b7ba7d8 100644 --- a/__tests__/account.test.ts +++ b/__tests__/account.test.ts @@ -65,6 +65,16 @@ describe('deploy and test Wallet', () => { innerInvokeEstFeeSpy.mockClear(); }); + test('simulate transaction', async () => { + const res = await account.simulateTransaction({ + contractAddress: erc20Address, + entrypoint: 'transfer', + calldata: [erc20.address, '10', '0'], + }); + expect(res).toHaveProperty('fee_estimation'); + expect(res).toHaveProperty('trace'); + }); + test('read balance of wallet', async () => { const x = await erc20.balanceOf(account.address); diff --git a/src/account/default.ts b/src/account/default.ts index 955d3d31a..141b0fe81 100644 --- a/src/account/default.ts +++ b/src/account/default.ts @@ -24,6 +24,7 @@ import { InvokeFunctionResponse, KeyPair, MultiDeployContractResponse, + Sequencer, Signature, UniversalDeployerContractPayload, } from '../types'; @@ -498,4 +499,36 @@ export class Account extends Provider implements AccountInterface { return feeEstimate.suggestedMaxFee.toString(); } + + public async simulateTransaction( + calls: AllowArray, + { nonce: providedNonce, blockIdentifier }: EstimateFeeDetails = {} + ): Promise { + const transactions = Array.isArray(calls) ? calls : [calls]; + const nonce = toBN(providedNonce ?? (await this.getNonce())); + const version = toBN(feeTransactionVersion); + const chainId = await this.getChainId(); + + const signerDetails: InvocationsSignerDetails = { + walletAddress: this.address, + nonce, + maxFee: ZERO, + version, + chainId, + }; + + const signature = await this.signer.signTransaction(transactions, signerDetails); + + const calldata = fromCallsToExecuteCalldata(transactions); + const response: any = await super.getSimulateTransaction( + { contractAddress: this.address, calldata, signature }, + { version, nonce }, + blockIdentifier + ); + + const suggestedMaxFee = estimatedFeeToMaxFee(response.fee_estimation.overall_fee); + response.fee_estimation.suggestedMaxFee = suggestedMaxFee; + + return response; + } } diff --git a/src/account/interface.ts b/src/account/interface.ts index 9e5f17826..6a8e771ba 100644 --- a/src/account/interface.ts +++ b/src/account/interface.ts @@ -18,6 +18,7 @@ import { InvocationsDetails, InvokeFunctionResponse, MultiDeployContractResponse, + Sequencer, Signature, UniversalDeployerContractPayload, } from '../types'; @@ -308,4 +309,19 @@ export abstract class AccountInterface extends ProviderInterface { estimateFeeAction: EstimateFeeAction, details: EstimateFeeDetails ): Promise; + + /** + * Estimate Fee for executing an INVOKE transaction on starknet + * + * @param calls the invocation object containing: + * - contractAddress - the address of the contract + * - entrypoint - the entrypoint of the contract + * - calldata - (defaults to []) the calldata + * + * @returns response from estimate_fee + */ + public abstract simulateTransaction( + calls: AllowArray, + estimateFeeDetails?: EstimateFeeDetails + ): Promise; } diff --git a/src/provider/default.ts b/src/provider/default.ts index a0e16e171..a057ec8e1 100644 --- a/src/provider/default.ts +++ b/src/provider/default.ts @@ -15,6 +15,7 @@ import { Invocation, InvocationsDetailsWithNonce, InvokeFunctionResponse, + Sequencer, Status, } from '../types'; import { BigNumberish } from '../utils/number'; @@ -184,4 +185,12 @@ export class Provider implements ProviderInterface { ): Promise { return this.provider.waitForTransaction(txHash, retryInterval, successStates); } + + public async getSimulateTransaction( + invocation: Invocation, + invocationDetails: InvocationsDetailsWithNonce, + blockIdentifier?: BlockIdentifier + ): Promise { + return this.provider.getSimulateTransaction(invocation, invocationDetails, blockIdentifier); + } } diff --git a/src/provider/interface.ts b/src/provider/interface.ts index e24f86fcc..47341ec9f 100644 --- a/src/provider/interface.ts +++ b/src/provider/interface.ts @@ -16,6 +16,7 @@ import type { Invocation, InvocationsDetailsWithNonce, InvokeFunctionResponse, + Sequencer, Status, } from '../types'; import type { BigNumberish } from '../utils/number'; @@ -278,4 +279,11 @@ export abstract class ProviderInterface { retryInterval?: number, successStates?: Array ): Promise; + + // todo documentation + public abstract getSimulateTransaction( + invocation: Invocation, + invocationDetails: InvocationsDetailsWithNonce, + blockIdentifier?: BlockIdentifier + ): Promise; } diff --git a/src/provider/rpc.ts b/src/provider/rpc.ts index faaeecb3f..9c2ff6e5f 100644 --- a/src/provider/rpc.ts +++ b/src/provider/rpc.ts @@ -14,6 +14,7 @@ import { InvocationsDetailsWithNonce, InvokeFunctionResponse, RPC, + Sequencer, } from '../types'; import fetch from '../utils/fetchPonyfill'; import { getSelectorFromName } from '../utils/hash'; @@ -481,4 +482,12 @@ export class RpcProvider implements ProviderInterface { public async getEvents(eventFilter: RPC.EventFilter): Promise { return this.fetchEndpoint('starknet_getEvents', { filter: eventFilter }); } + + public async getSimulateTransaction( + _invocation: Invocation, + _invocationDetails: InvocationsDetailsWithNonce, + _blockIdentifier?: BlockIdentifier + ): Promise { + throw new Error('RPC does not implement simulateTransaction function'); + } } diff --git a/src/provider/sequencer.ts b/src/provider/sequencer.ts index 5bbfff485..edeb82348 100644 --- a/src/provider/sequencer.ts +++ b/src/provider/sequencer.ts @@ -522,10 +522,10 @@ export class SequencerProvider implements ProviderInterface { return this.fetchEndpoint('estimate_message_fee', { blockIdentifier }, validCallL1Handler); } - public async simulateTransaction( + public async getSimulateTransaction( invocation: Invocation, invocationDetails: InvocationsDetailsWithNonce, - blockIdentifier: BlockIdentifier = 'pending' + blockIdentifier: BlockIdentifier = this.blockIdentifier ): Promise { return this.fetchEndpoint( 'simulate_transaction',