diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index 08c1805b..093db29f 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -35,11 +35,10 @@ import { Registry, } from "@cosmjs/proto-signing"; import { + AminoTypes, BroadcastTxFailure, BroadcastTxResponse, codec, - getMsgType, - getMsgTypeUrl, isBroadcastTxFailure, parseRawLog, } from "@cosmjs/stargate"; @@ -110,6 +109,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { private readonly fees: CosmosFeeTable; private readonly registry: Registry; private readonly signer: OfflineSigner; + private readonly aminoTypes = new AminoTypes(); public static async connectWithWallet( endpoint: string, @@ -368,14 +368,14 @@ export class SigningCosmWasmClient extends CosmWasmClient { // Amino signer const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON; const msgs = messages.map((msg) => ({ - type: getMsgType(msg.typeUrl), + type: this.aminoTypes.toAmino(msg.typeUrl), value: msg.value, })); const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence); const { signature, signed } = await this.signer.signAmino(address, signDoc); const signedTxBody = { messages: signed.msgs.map((msg) => ({ - typeUrl: getMsgTypeUrl(msg.type), + typeUrl: this.aminoTypes.fromAmino(msg.type), value: msg.value, })), memo: signed.memo, diff --git a/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts b/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts index 9bd1dcf6..df7c1bb1 100644 --- a/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts +++ b/packages/cosmwasm-stargate/types/signingcosmwasmclient.d.ts @@ -25,6 +25,7 @@ export declare class SigningCosmWasmClient extends CosmWasmClient { private readonly fees; private readonly registry; private readonly signer; + private readonly aminoTypes; static connectWithWallet( endpoint: string, signer: OfflineSigner, diff --git a/packages/stargate/src/aminotypes.spec.ts b/packages/stargate/src/aminotypes.spec.ts new file mode 100644 index 00000000..3053370d --- /dev/null +++ b/packages/stargate/src/aminotypes.spec.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { AminoTypes } from "./aminotypes"; + +describe("AminoTypes", () => { + describe("toAmino", () => { + it("works for known type url", () => { + const msgType = new AminoTypes().toAmino("/cosmos.staking.v1beta1.MsgDelegate"); + expect(msgType).toEqual("cosmos-sdk/MsgDelegate"); + }); + + it("throws for unknown type url", () => { + expect(() => new AminoTypes().toAmino("/xxx.Unknown")).toThrowError( + /Type URL does not exist in the Amino message type register./i, + ); + }); + }); + + describe("fromAmino", () => { + it("works for known type url", () => { + const msgUrl = new AminoTypes().fromAmino("cosmos-sdk/MsgDelegate"); + expect(msgUrl).toEqual("/cosmos.staking.v1beta1.MsgDelegate"); + }); + + it("throws for unknown type url", () => { + expect(() => new AminoTypes().fromAmino("cosmos-sdk/MsgUnknown")).toThrowError( + /Type does not exist in the Amino message type register./i, + ); + }); + }); +}); diff --git a/packages/stargate/src/encoding.ts b/packages/stargate/src/aminotypes.ts similarity index 50% rename from packages/stargate/src/encoding.ts rename to packages/stargate/src/aminotypes.ts index 71ffe880..0fa3a378 100644 --- a/packages/stargate/src/encoding.ts +++ b/packages/stargate/src/aminotypes.ts @@ -1,4 +1,4 @@ -const typeRegister: Record = { +const defaultTypes: Record = { "/cosmos.bank.v1beta1.MsgSend": "cosmos-sdk/MsgSend", "/cosmos.bank.v1beta1.MsgMultiSend": "cosmos-sdk/MsgMultiSend", "/cosmos.crisis.v1beta1.MsgVerifyInvariant": "cosmos-sdk/MsgVerifyInvariant", @@ -19,18 +19,38 @@ const typeRegister: Record = { "/cosmos.vesting.v1beta1.MsgCreateVestingAccount": "cosmos-sdk/MsgCreateVestingAccount", }; -export function getMsgType(typeUrl: string): string { - const type = typeRegister[typeUrl]; - if (!type) { - throw new Error("Type URL not known"); - } - return type; -} +/** + * A map from Stargate message types as used in the messages's `Any` type + * to Amino types. + */ +export class AminoTypes { + private readonly register: Record; -export function getMsgTypeUrl(type: string): string { - const [typeUrl] = Object.entries(typeRegister).find(([_typeUrl, value]) => value === type) ?? []; - if (!typeUrl) { - throw new Error("Type not known"); + public constructor(additions: Record = {}) { + this.register = { ...defaultTypes, ...additions }; + } + + public toAmino(typeUrl: string): string { + const type = defaultTypes[typeUrl]; + if (!type) { + throw new Error( + "Type URL does not exist in the Amino message type register. " + + "If you need support for this message type, you can pass in additional entries to the AminoTypes constructor. " + + "If you think this message type should be included by default, please open an issue at https://github.com/cosmos/cosmjs/issues.", + ); + } + return type; + } + + public fromAmino(type: string): string { + const [typeUrl] = Object.entries(defaultTypes).find(([_typeUrl, value]) => value === type) ?? []; + if (!typeUrl) { + throw new Error( + "Type does not exist in the Amino message type register. " + + "If you need support for this message type, you can pass in additional entries to the AminoTypes constructor. " + + "If you think this message type should be included by default, please open an issue at https://github.com/cosmos/cosmjs/issues.", + ); + } + return typeUrl; } - return typeUrl; } diff --git a/packages/stargate/src/encoding.spec.ts b/packages/stargate/src/encoding.spec.ts deleted file mode 100644 index d36b1f18..00000000 --- a/packages/stargate/src/encoding.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import { getMsgType } from "./encoding"; - -describe("encoding", () => { - describe("getMsgType", () => { - it("works for known type url", () => { - const msgType = getMsgType("/cosmos.staking.v1beta1.MsgDelegate"); - expect(msgType).toEqual("cosmos-sdk/MsgDelegate"); - }); - - it("throws for unknown type url", () => { - expect(() => getMsgType("/xxx.Unknown")).toThrowError(/type url not known/i); - }); - }); -}); diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index bbc91839..4254360a 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -1,5 +1,5 @@ export * as codec from "./codec"; -export { getMsgType, getMsgTypeUrl } from "./encoding"; +export { AminoTypes } from "./aminotypes"; export { parseRawLog } from "./logs"; export { AuthExtension, diff --git a/packages/stargate/src/signingstargateclient.ts b/packages/stargate/src/signingstargateclient.ts index 67a84ab5..dd808cff 100644 --- a/packages/stargate/src/signingstargateclient.ts +++ b/packages/stargate/src/signingstargateclient.ts @@ -23,8 +23,8 @@ import { } from "@cosmjs/proto-signing"; import { adaptor34, Client as TendermintClient } from "@cosmjs/tendermint-rpc"; +import { AminoTypes } from "./aminotypes"; import { cosmos } from "./codec"; -import { getMsgType, getMsgTypeUrl } from "./encoding"; import { BroadcastTxResponse, StargateClient } from "./stargateclient"; const { TxRaw } = cosmos.tx.v1beta1; @@ -48,6 +48,7 @@ export class SigningStargateClient extends StargateClient { private readonly fees: CosmosFeeTable; private readonly registry: Registry; private readonly signer: OfflineSigner; + private readonly aminoTypes = new AminoTypes(); public static async connectWithWallet( endpoint: string, @@ -136,14 +137,14 @@ export class SigningStargateClient extends StargateClient { // Amino signer const signMode = cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_LEGACY_AMINO_JSON; const msgs = messages.map((msg) => ({ - type: getMsgType(msg.typeUrl), + type: this.aminoTypes.toAmino(msg.typeUrl), value: msg.value, })); const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence); const { signature, signed } = await this.signer.signAmino(address, signDoc); const signedTxBody = { messages: signed.msgs.map((msg) => ({ - typeUrl: getMsgTypeUrl(msg.type), + typeUrl: this.aminoTypes.fromAmino(msg.type), value: msg.value, })), memo: signed.memo, diff --git a/packages/stargate/types/aminotypes.d.ts b/packages/stargate/types/aminotypes.d.ts new file mode 100644 index 00000000..473b3797 --- /dev/null +++ b/packages/stargate/types/aminotypes.d.ts @@ -0,0 +1,10 @@ +/** + * A map from Stargate message types as used in the messages's `Any` type + * to Amino types. + */ +export declare class AminoTypes { + private readonly register; + constructor(additions?: Record); + toAmino(typeUrl: string): string; + fromAmino(type: string): string; +} diff --git a/packages/stargate/types/encoding.d.ts b/packages/stargate/types/encoding.d.ts deleted file mode 100644 index af3b9e44..00000000 --- a/packages/stargate/types/encoding.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare function getMsgType(typeUrl: string): string; -export declare function getMsgTypeUrl(type: string): string; diff --git a/packages/stargate/types/index.d.ts b/packages/stargate/types/index.d.ts index bbc91839..4254360a 100644 --- a/packages/stargate/types/index.d.ts +++ b/packages/stargate/types/index.d.ts @@ -1,5 +1,5 @@ export * as codec from "./codec"; -export { getMsgType, getMsgTypeUrl } from "./encoding"; +export { AminoTypes } from "./aminotypes"; export { parseRawLog } from "./logs"; export { AuthExtension, diff --git a/packages/stargate/types/signingstargateclient.d.ts b/packages/stargate/types/signingstargateclient.d.ts index e782543b..cc8eb7bb 100644 --- a/packages/stargate/types/signingstargateclient.d.ts +++ b/packages/stargate/types/signingstargateclient.d.ts @@ -15,6 +15,7 @@ export declare class SigningStargateClient extends StargateClient { private readonly fees; private readonly registry; private readonly signer; + private readonly aminoTypes; static connectWithWallet( endpoint: string, signer: OfflineSigner,