diff --git a/packages/proto-signing/src/index.ts b/packages/proto-signing/src/index.ts index c76ba594..fc518bfd 100644 --- a/packages/proto-signing/src/index.ts +++ b/packages/proto-signing/src/index.ts @@ -2,4 +2,5 @@ export { Coin } from "./msgs"; export { cosmosField } from "./decorator"; export { Registry } from "./registry"; export { DirectSecp256k1Wallet } from "./directsecp256k1wallet"; +export { decodePubkey, encodePubkey } from "./pubkey"; export { makeAuthInfo, makeSignBytes } from "./signing"; diff --git a/packages/proto-signing/src/pubkey.spec.ts b/packages/proto-signing/src/pubkey.spec.ts new file mode 100644 index 00000000..09cccd27 --- /dev/null +++ b/packages/proto-signing/src/pubkey.spec.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { fromBase64 } from "@cosmjs/encoding"; + +import { google } from "./codec"; +import { decodePubkey, encodePubkey } from "./pubkey"; + +const { Any } = google.protobuf; + +describe("pubkey", () => { + const defaultPubkeyBase64 = "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP"; + const defaultPubkeyBytes = fromBase64(defaultPubkeyBase64); + const defaultPubkeyProtoBytes = Uint8Array.from([0x0a, defaultPubkeyBytes.length, ...defaultPubkeyBytes]); + + describe("encodePubkey", () => { + it("works for secp256k1", () => { + const pubkey = { type: "tendermint/PubKeySecp256k1", value: defaultPubkeyBase64 }; + expect(encodePubkey(pubkey)).toEqual( + Any.create({ + type_url: "/cosmos.crypto.secp256k1.PubKey", + value: defaultPubkeyProtoBytes, + }), + ); + }); + + it("throws for unsupported pubkey types", () => { + const pubkey = { + type: "tendermint/PubKeyUnknown", + value: defaultPubkeyBase64, + }; + expect(() => encodePubkey(pubkey)).toThrowError(/not recognized/i); + }); + }); + + describe("decodePubkey", () => { + it("works for secp256k1", () => { + const pubkey = { + type_url: "/cosmos.crypto.secp256k1.PubKey", + value: defaultPubkeyProtoBytes, + }; + expect(decodePubkey(pubkey)).toEqual({ + type: "tendermint/PubKeySecp256k1", + value: defaultPubkeyBase64, + }); + }); + + it("throws for unsupported pubkey types", () => { + const pubkey = { + type_url: "/cosmos.crypto.unknown.PubKey", + value: defaultPubkeyProtoBytes, + }; + expect(() => decodePubkey(pubkey)).toThrowError(/not recognized/i); + }); + }); +}); diff --git a/packages/proto-signing/src/pubkey.ts b/packages/proto-signing/src/pubkey.ts new file mode 100644 index 00000000..80da8019 --- /dev/null +++ b/packages/proto-signing/src/pubkey.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { fromBase64 } from "@cosmjs/encoding"; +import { encodeSecp256k1Pubkey, PubKey } from "@cosmjs/launchpad"; + +import { cosmos, google } from "./codec"; + +const { Any } = google.protobuf; + +export function encodePubkey(pubkey: PubKey): google.protobuf.IAny { + switch (pubkey.type) { + case "tendermint/PubKeySecp256k1": { + const pubkeyProto = cosmos.crypto.secp256k1.PubKey.create({ + key: fromBase64(pubkey.value), + }); + return Any.create({ + type_url: "/cosmos.crypto.secp256k1.PubKey", + value: Uint8Array.from(cosmos.crypto.secp256k1.PubKey.encode(pubkeyProto).finish()), + }); + } + default: + throw new Error(`Pubkey type ${pubkey.type} not recognized`); + } +} + +export function decodePubkey(pubkey?: google.protobuf.IAny | null): PubKey | null { + if (!pubkey || !pubkey.value) { + return null; + } + + switch (pubkey.type_url) { + case "/cosmos.crypto.secp256k1.PubKey": { + const { key } = cosmos.crypto.secp256k1.PubKey.decode(pubkey.value); + return encodeSecp256k1Pubkey(key); + } + default: + throw new Error(`Pubkey type_url ${pubkey.type_url} not recognized`); + } +} diff --git a/packages/proto-signing/types/index.d.ts b/packages/proto-signing/types/index.d.ts index c76ba594..fc518bfd 100644 --- a/packages/proto-signing/types/index.d.ts +++ b/packages/proto-signing/types/index.d.ts @@ -2,4 +2,5 @@ export { Coin } from "./msgs"; export { cosmosField } from "./decorator"; export { Registry } from "./registry"; export { DirectSecp256k1Wallet } from "./directsecp256k1wallet"; +export { decodePubkey, encodePubkey } from "./pubkey"; export { makeAuthInfo, makeSignBytes } from "./signing"; diff --git a/packages/proto-signing/types/pubkey.d.ts b/packages/proto-signing/types/pubkey.d.ts new file mode 100644 index 00000000..dcd790d1 --- /dev/null +++ b/packages/proto-signing/types/pubkey.d.ts @@ -0,0 +1,4 @@ +import { PubKey } from "@cosmjs/launchpad"; +import { google } from "./codec"; +export declare function encodePubkey(pubkey: PubKey): google.protobuf.IAny; +export declare function decodePubkey(pubkey?: google.protobuf.IAny | null): PubKey | null;