diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index fff66281..833ec275 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -21,18 +21,21 @@ import { GasLimits, GasPrice, logs, + makeSignDoc as makeSignDocAmino, StdFee, } from "@cosmjs/launchpad"; import { Int53, Uint53 } from "@cosmjs/math"; import { EncodeObject, encodePubkey, + isOfflineDirectSigner, makeAuthInfoBytes, makeSignDoc, - OfflineDirectSigner, + OfflineSigner, Registry, } from "@cosmjs/proto-signing"; import { + AminoTypes, BroadcastTxFailure, BroadcastTxResponse, codec, @@ -43,10 +46,20 @@ import { adaptor34, Client as TendermintClient } from "@cosmjs/tendermint-rpc"; import Long from "long"; import pako from "pako"; +import { defaultTypes } from "./aminotypes"; import { cosmwasm } from "./codec"; import { CosmWasmClient } from "./cosmwasmclient"; +const { SignMode } = codec.cosmos.tx.signing.v1beta1; const { TxRaw } = codec.cosmos.tx.v1beta1; +const { MsgMultiSend } = codec.cosmos.bank.v1beta1; +const { + MsgBeginRedelegate, + MsgCreateValidator, + MsgDelegate, + MsgEditValidator, + MsgUndelegate, +} = codec.cosmos.staking.v1beta1; const { MsgClearAdmin, MsgExecuteContract, @@ -81,6 +94,12 @@ function createBroadcastTxErrorMessage(result: BroadcastTxFailure): string { function createDefaultRegistry(): Registry { return new Registry([ + ["/cosmos.bank.v1beta1.MsgMultiSend", MsgMultiSend], + ["/cosmos.staking.v1beta1.MsgBeginRedelegate", MsgBeginRedelegate], + ["/cosmos.staking.v1beta1.MsgCreateValidator", MsgCreateValidator], + ["/cosmos.staking.v1beta1.MsgDelegate", MsgDelegate], + ["/cosmos.staking.v1beta1.MsgEditValidator", MsgEditValidator], + ["/cosmos.staking.v1beta1.MsgUndelegate", MsgUndelegate], ["/cosmwasm.wasm.v1beta1.MsgClearAdmin", MsgClearAdmin], ["/cosmwasm.wasm.v1beta1.MsgExecuteContract", MsgExecuteContract], ["/cosmwasm.wasm.v1beta1.MsgMigrateContract", MsgMigrateContract], @@ -92,6 +111,8 @@ function createDefaultRegistry(): Registry { export interface SigningCosmWasmClientOptions { readonly registry?: Registry; + readonly aminoTypes?: AminoTypes; + readonly prefix?: string; readonly gasPrice?: GasPrice; readonly gasLimits?: GasLimits; } @@ -99,16 +120,18 @@ export interface SigningCosmWasmClientOptions { /** Use for testing only */ export interface PrivateSigningCosmWasmClient { readonly fees: CosmWasmFeeTable; + readonly registry: Registry; } export class SigningCosmWasmClient extends CosmWasmClient { private readonly fees: CosmosFeeTable; private readonly registry: Registry; - private readonly signer: OfflineDirectSigner; + private readonly signer: OfflineSigner; + private readonly aminoTypes: AminoTypes; public static async connectWithSigner( endpoint: string, - signer: OfflineDirectSigner, + signer: OfflineSigner, options: SigningCosmWasmClientOptions = {}, ): Promise { const tmClient = await TendermintClient.connect(endpoint, adaptor34); @@ -117,17 +140,19 @@ export class SigningCosmWasmClient extends CosmWasmClient { private constructor( tmClient: TendermintClient, - signer: OfflineDirectSigner, + signer: OfflineSigner, options: SigningCosmWasmClientOptions, ) { super(tmClient); const { registry = createDefaultRegistry(), + aminoTypes = new AminoTypes({ additions: defaultTypes, prefix: options.prefix }), gasPrice = defaultGasPrice, gasLimits = defaultGasLimits, } = options; this.fees = buildFeeTable(gasPrice, defaultGasLimits, gasLimits); this.registry = registry; + this.aminoTypes = aminoTypes; this.signer = signer; } @@ -355,12 +380,45 @@ export class SigningCosmWasmClient extends CosmWasmClient { }); const gasLimit = Int53.fromString(fee.gas).toNumber(); - const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence); - const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber); - const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc); + if (isOfflineDirectSigner(this.signer)) { + const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence); + const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber); + const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc); + const txRaw = TxRaw.create({ + bodyBytes: signed.bodyBytes, + authInfoBytes: signed.authInfoBytes, + signatures: [fromBase64(signature.signature)], + }); + const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish()); + return this.broadcastTx(signedTx); + } + // Amino signer + + // Amino signer + const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON; + const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg)); + const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence); + const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc); + const signedTxBody = { + messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)), + memo: signed.memo, + }; + const signedTxBodyBytes = this.registry.encode({ + typeUrl: "/cosmos.tx.v1beta1.TxBody", + value: signedTxBody, + }); + const signedGasLimit = Int53.fromString(signed.fee.gas).toNumber(); + const signedSequence = Int53.fromString(signed.sequence).toNumber(); + const signedAuthInfoBytes = makeAuthInfoBytes( + [pubkeyAny], + signed.fee.amount, + signedGasLimit, + signedSequence, + signMode, + ); const txRaw = TxRaw.create({ - bodyBytes: signed.bodyBytes, - authInfoBytes: signed.authInfoBytes, + bodyBytes: signedTxBodyBytes, + authInfoBytes: signedAuthInfoBytes, signatures: [fromBase64(signature.signature)], }); const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish()); diff --git a/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts b/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts index 41f160bc..c6d66c4e 100644 --- a/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts +++ b/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts @@ -9,25 +9,29 @@ import { UploadResult, } from "@cosmjs/cosmwasm-launchpad"; import { Coin, CosmosFeeTable, GasLimits, GasPrice, StdFee } from "@cosmjs/launchpad"; -import { EncodeObject, OfflineDirectSigner, Registry } from "@cosmjs/proto-signing"; -import { BroadcastTxResponse } from "@cosmjs/stargate"; +import { EncodeObject, OfflineSigner, Registry } from "@cosmjs/proto-signing"; +import { AminoTypes, BroadcastTxResponse } from "@cosmjs/stargate"; import { CosmWasmClient } from "./cosmwasmclient"; export interface SigningCosmWasmClientOptions { readonly registry?: Registry; + readonly aminoTypes?: AminoTypes; + readonly prefix?: string; readonly gasPrice?: GasPrice; readonly gasLimits?: GasLimits; } /** Use for testing only */ export interface PrivateSigningCosmWasmClient { readonly fees: CosmWasmFeeTable; + readonly registry: Registry; } export declare class SigningCosmWasmClient extends CosmWasmClient { private readonly fees; private readonly registry; private readonly signer; + private readonly aminoTypes; static connectWithSigner( endpoint: string, - signer: OfflineDirectSigner, + signer: OfflineSigner, options?: SigningCosmWasmClientOptions, ): Promise; private constructor();