diff --git a/packages/proto-signing/scripts/define-proto.sh b/packages/proto-signing/scripts/define-proto.sh index ed906572..3b5017f3 100755 --- a/packages/proto-signing/scripts/define-proto.sh +++ b/packages/proto-signing/scripts/define-proto.sh @@ -20,6 +20,7 @@ protoc \ "$COSMOS_PROTO_DIR/cosmos/bank/v1beta1/bank.proto" \ "$COSMOS_PROTO_DIR/cosmos/bank/v1beta1/tx.proto" \ "$COSMOS_PROTO_DIR/cosmos/crypto/multisig/v1beta1/multisig.proto" \ + "$COSMOS_PROTO_DIR/cosmos/crypto/multisig/keys.proto" \ "$COSMOS_PROTO_DIR/cosmos/crypto/secp256k1/keys.proto" \ "$COSMOS_PROTO_DIR/cosmos/tx/v1beta1/tx.proto" \ "$COSMOS_PROTO_DIR/cosmos/tx/signing/v1beta1/signing.proto" \ diff --git a/packages/proto-signing/src/codec/cosmos/crypto/multisig/keys.ts b/packages/proto-signing/src/codec/cosmos/crypto/multisig/keys.ts new file mode 100644 index 00000000..6d692d92 --- /dev/null +++ b/packages/proto-signing/src/codec/cosmos/crypto/multisig/keys.ts @@ -0,0 +1,106 @@ +/* eslint-disable */ +import { Any } from "../../../google/protobuf/any"; +import Long from "long"; +import _m0 from "protobufjs/minimal"; + +export const protobufPackage = "cosmos.crypto.multisig"; + +/** + * LegacyAminoPubKey specifies a public key type + * which nests multiple public keys and a threshold, + * it uses legacy amino address rules. + */ +export interface LegacyAminoPubKey { + threshold: number; + publicKeys: Any[]; +} + +const baseLegacyAminoPubKey: object = { threshold: 0 }; + +export const LegacyAminoPubKey = { + encode(message: LegacyAminoPubKey, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.threshold !== 0) { + writer.uint32(8).uint32(message.threshold); + } + for (const v of message.publicKeys) { + Any.encode(v!, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): LegacyAminoPubKey { + const reader = input instanceof Uint8Array ? new _m0.Reader(input) : input; + let end = length === undefined ? reader.len : reader.pos + length; + const message = { ...baseLegacyAminoPubKey } as LegacyAminoPubKey; + message.publicKeys = []; + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.threshold = reader.uint32(); + break; + case 2: + message.publicKeys.push(Any.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, + + fromJSON(object: any): LegacyAminoPubKey { + const message = { ...baseLegacyAminoPubKey } as LegacyAminoPubKey; + message.publicKeys = []; + if (object.threshold !== undefined && object.threshold !== null) { + message.threshold = Number(object.threshold); + } else { + message.threshold = 0; + } + if (object.publicKeys !== undefined && object.publicKeys !== null) { + for (const e of object.publicKeys) { + message.publicKeys.push(Any.fromJSON(e)); + } + } + return message; + }, + + toJSON(message: LegacyAminoPubKey): unknown { + const obj: any = {}; + message.threshold !== undefined && (obj.threshold = message.threshold); + if (message.publicKeys) { + obj.publicKeys = message.publicKeys.map((e) => (e ? Any.toJSON(e) : undefined)); + } else { + obj.publicKeys = []; + } + return obj; + }, + + fromPartial(object: DeepPartial): LegacyAminoPubKey { + const message = { ...baseLegacyAminoPubKey } as LegacyAminoPubKey; + message.publicKeys = []; + if (object.threshold !== undefined && object.threshold !== null) { + message.threshold = object.threshold; + } else { + message.threshold = 0; + } + if (object.publicKeys !== undefined && object.publicKeys !== null) { + for (const e of object.publicKeys) { + message.publicKeys.push(Any.fromPartial(e)); + } + } + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | undefined | Long; +export type DeepPartial = T extends Builtin + ? T + : T extends Array + ? Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial; diff --git a/packages/proto-signing/src/pubkey.ts b/packages/proto-signing/src/pubkey.ts index faa88ac4..ebf9f0c5 100644 --- a/packages/proto-signing/src/pubkey.ts +++ b/packages/proto-signing/src/pubkey.ts @@ -1,27 +1,42 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { encodeSecp256k1Pubkey, SinglePubkey as AminoPubKey } from "@cosmjs/amino"; +import { + encodeSecp256k1Pubkey, + isMultisigThresholdPubkey, + isSecp256k1Pubkey, + Pubkey, + SinglePubkey, +} from "@cosmjs/amino"; import { fromBase64 } from "@cosmjs/encoding"; +import { Uint53 } from "@cosmjs/math"; +import { LegacyAminoPubKey } from "./codec/cosmos/crypto/multisig/keys"; import { PubKey } from "./codec/cosmos/crypto/secp256k1/keys"; import { Any } from "./codec/google/protobuf/any"; -export function encodePubkey(pubkey: AminoPubKey): Any { - switch (pubkey.type) { - case "tendermint/PubKeySecp256k1": { - const pubkeyProto = PubKey.fromPartial({ - key: fromBase64(pubkey.value), - }); - return Any.fromPartial({ - typeUrl: "/cosmos.crypto.secp256k1.PubKey", - value: Uint8Array.from(PubKey.encode(pubkeyProto).finish()), - }); - } - default: - throw new Error(`Pubkey type ${pubkey.type} not recognized`); +export function encodePubkey(pubkey: Pubkey): Any { + if (isSecp256k1Pubkey(pubkey)) { + const pubkeyProto = PubKey.fromPartial({ + key: fromBase64(pubkey.value), + }); + return Any.fromPartial({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: Uint8Array.from(PubKey.encode(pubkeyProto).finish()), + }); + } else if (isMultisigThresholdPubkey(pubkey)) { + const pubkeyProto = LegacyAminoPubKey.fromPartial({ + threshold: Uint53.fromString(pubkey.value.threshold).toNumber(), + publicKeys: pubkey.value.pubkeys.map(encodePubkey), + }); + return Any.fromPartial({ + typeUrl: "/cosmos.crypto.multisig.LegacyAminoPubKey", + value: Uint8Array.from(LegacyAminoPubKey.encode(pubkeyProto).finish()), + }); + } else { + throw new Error(`Pubkey type ${pubkey.type} not recognized`); } } -export function decodePubkey(pubkey?: Any | null): AminoPubKey | null { +export function decodePubkey(pubkey?: Any | null): SinglePubkey | null { if (!pubkey || !pubkey.value) { return null; }