diff --git a/packages/stargate/src/signingstargateclient.spec.ts b/packages/stargate/src/signingstargateclient.spec.ts index 8996a29f..dbe54498 100644 --- a/packages/stargate/src/signingstargateclient.spec.ts +++ b/packages/stargate/src/signingstargateclient.spec.ts @@ -42,6 +42,34 @@ describe("SigningStargateClient", () => { }); }); + describe("simulate", () => { + it("works", async () => { + pendingWithoutSimapp(); + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic); + const client = await SigningStargateClient.connectWithSigner( + simapp.tendermintUrl, + wallet, + defaultSigningClientOptions, + ); + + const msg = MsgDelegate.fromPartial({ + delegatorAddress: faucet.address0, + validatorAddress: validator.validatorAddress, + amount: coin(1234, "ustake"), + }); + const msgAny: MsgDelegateEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgDelegate", + value: msg, + }; + const memo = "Use your power wisely"; + const gasUsed = await client.simulate(faucet.address0, [msgAny], memo); + expect(gasUsed).toBeGreaterThanOrEqual(101_000); + expect(gasUsed).toBeLessThanOrEqual(106_000); + + client.disconnect(); + }); + }); + describe("sendTokens", () => { it("works with direct signer", async () => { pendingWithoutSimapp(); diff --git a/packages/stargate/src/signingstargateclient.ts b/packages/stargate/src/signingstargateclient.ts index 607cc212..120603f8 100644 --- a/packages/stargate/src/signingstargateclient.ts +++ b/packages/stargate/src/signingstargateclient.ts @@ -1,6 +1,6 @@ import { encodeSecp256k1Pubkey, makeSignDoc as makeSignDocAmino, StdFee } from "@cosmjs/amino"; import { fromBase64 } from "@cosmjs/encoding"; -import { Int53 } from "@cosmjs/math"; +import { Int53, Uint53 } from "@cosmjs/math"; import { EncodeObject, encodePubkey, @@ -13,7 +13,7 @@ import { TxBodyEncodeObject, } from "@cosmjs/proto-signing"; import { Tendermint34Client } from "@cosmjs/tendermint-rpc"; -import { assert } from "@cosmjs/utils"; +import { assert, assertDefined } from "@cosmjs/utils"; import { MsgMultiSend } from "cosmjs-types/cosmos/bank/v1beta1/tx"; import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"; import { @@ -181,6 +181,25 @@ export class SigningStargateClient extends StargateClient { this.broadcastPollIntervalMs = options.broadcastPollIntervalMs; } + public async simulate( + signerAddress: string, + messages: readonly EncodeObject[], + memo: string | undefined, + ): Promise { + const anyMsgs = messages.map((m) => this.registry.encodeAsAny(m)); + const accountFromSigner = (await this.signer.getAccounts()).find( + (account) => account.address === signerAddress, + ); + if (!accountFromSigner) { + throw new Error("Failed to retrieve account from signer"); + } + const pubkey = encodeSecp256k1Pubkey(accountFromSigner.pubkey); + const { sequence } = await this.getSequence(signerAddress); + const { gasInfo } = await this.forceGetQueryClient().tx.simulate(anyMsgs, memo, pubkey, sequence); + assertDefined(gasInfo); + return Uint53.fromString(gasInfo.gasUsed.toString()).toNumber(); + } + public async sendTokens( senderAddress: string, recipientAddress: string, diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index dde63ba6..0f1ebf3e 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -14,7 +14,9 @@ import { setupAuthExtension, setupBankExtension, setupStakingExtension, + setupTxExtension, StakingExtension, + TxExtension, } from "./queries"; import { isSearchByHeightQuery, @@ -146,7 +148,9 @@ export interface PrivateStargateClient { export class StargateClient { private readonly tmClient: Tendermint34Client | undefined; - private readonly queryClient: (QueryClient & AuthExtension & BankExtension & StakingExtension) | undefined; + private readonly queryClient: + | (QueryClient & AuthExtension & BankExtension & StakingExtension & TxExtension) + | undefined; private chainId: string | undefined; public static async connect(endpoint: string): Promise { @@ -162,6 +166,7 @@ export class StargateClient { setupAuthExtension, setupBankExtension, setupStakingExtension, + setupTxExtension, ); } } @@ -179,11 +184,17 @@ export class StargateClient { return this.tmClient; } - protected getQueryClient(): (QueryClient & AuthExtension & BankExtension & StakingExtension) | undefined { + protected getQueryClient(): + | (QueryClient & AuthExtension & BankExtension & StakingExtension & TxExtension) + | undefined { return this.queryClient; } - protected forceGetQueryClient(): QueryClient & AuthExtension & BankExtension & StakingExtension { + protected forceGetQueryClient(): QueryClient & + AuthExtension & + BankExtension & + StakingExtension & + TxExtension { if (!this.queryClient) { throw new Error("Query client not available. You cannot use online functionality in offline mode."); }