From a69006b8c3d253f0143c01bd6847e568e367e57f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Sat, 25 Jul 2020 15:09:28 +0200 Subject: [PATCH 1/5] Add uint64ToNumber and uint64ToString --- packages/sdk38/src/index.ts | 2 + packages/sdk38/src/lcdapi/index.ts | 5 ++ packages/sdk38/src/lcdapi/utils.spec.ts | 67 +++++++++++++++++++++++++ packages/sdk38/src/lcdapi/utils.ts | 23 +++++++++ packages/sdk38/types/index.d.ts | 2 + packages/sdk38/types/lcdapi/index.d.ts | 1 + packages/sdk38/types/lcdapi/utils.d.ts | 14 ++++++ 7 files changed, 114 insertions(+) create mode 100644 packages/sdk38/src/lcdapi/utils.spec.ts create mode 100644 packages/sdk38/src/lcdapi/utils.ts create mode 100644 packages/sdk38/types/lcdapi/utils.d.ts diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index 4afe6c26..305cdbee 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -78,6 +78,8 @@ export { StakingPoolResponse, SupplyExtension, TxsResponse, + uint64ToNumber, + uint64ToString, } from "./lcdapi"; export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs"; export { decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey"; diff --git a/packages/sdk38/src/lcdapi/index.ts b/packages/sdk38/src/lcdapi/index.ts index 5a3fc580..767f3cd6 100644 --- a/packages/sdk38/src/lcdapi/index.ts +++ b/packages/sdk38/src/lcdapi/index.ts @@ -77,3 +77,8 @@ export { TxsResponse, } from "./base"; export { LcdApiArray, LcdClient, normalizeLcdApiArray } from "./lcdclient"; + +// +// Utils for interacting with the client/API +// +export { uint64ToNumber, uint64ToString } from "./utils"; diff --git a/packages/sdk38/src/lcdapi/utils.spec.ts b/packages/sdk38/src/lcdapi/utils.spec.ts new file mode 100644 index 00000000..a4628096 --- /dev/null +++ b/packages/sdk38/src/lcdapi/utils.spec.ts @@ -0,0 +1,67 @@ +import { uint64ToNumber, uint64ToString } from "./utils"; + +describe("utils", () => { + describe("uint64ToNumber", () => { + it("works for numeric inputs", () => { + expect(uint64ToNumber(0)).toEqual(0); + expect(uint64ToNumber(1)).toEqual(1); + expect(uint64ToNumber(Number.MAX_SAFE_INTEGER)).toEqual(Number.MAX_SAFE_INTEGER); + }); + + it("works for string inputs", () => { + expect(uint64ToNumber("0")).toEqual(0); + expect(uint64ToNumber("1")).toEqual(1); + expect(uint64ToNumber("9007199254740991")).toEqual(Number.MAX_SAFE_INTEGER); + }); + + it("throws for invalid numbers", () => { + expect(() => uint64ToNumber(NaN)).toThrow(); + expect(() => uint64ToNumber(1.1)).toThrow(); + expect(() => uint64ToNumber(-1)).toThrow(); + expect(() => uint64ToNumber(Number.MAX_SAFE_INTEGER + 1)).toThrow(); + }); + + it("throws for invalid strings", () => { + expect(() => uint64ToNumber("")).toThrow(); + expect(() => uint64ToNumber("0x22")).toThrow(); + expect(() => uint64ToNumber("-1")).toThrow(); + expect(() => uint64ToNumber("1.1")).toThrow(); + expect(() => uint64ToNumber("9007199254740992")).toThrow(); + }); + }); + + describe("uint64ToString", () => { + it("works for numeric inputs", () => { + expect(uint64ToString(0)).toEqual("0"); + expect(uint64ToString(1)).toEqual("1"); + expect(uint64ToString(Number.MAX_SAFE_INTEGER)).toEqual("9007199254740991"); + }); + + it("works for string inputs", () => { + expect(uint64ToString("0")).toEqual("0"); + expect(uint64ToString("1")).toEqual("1"); + expect(uint64ToString("9007199254740991")).toEqual("9007199254740991"); + }); + + it("works for large string values", () => { + // for the string -> string version, the full uint64 range is supported + expect(uint64ToString("9007199254740992")).toEqual("9007199254740992"); + expect(uint64ToString("18446744073709551615")).toEqual("18446744073709551615"); + }); + + it("throws for invalid numbers", () => { + expect(() => uint64ToString(NaN)).toThrow(); + expect(() => uint64ToString(1.1)).toThrow(); + expect(() => uint64ToString(-1)).toThrow(); + expect(() => uint64ToString(Number.MAX_SAFE_INTEGER + 1)).toThrow(); + }); + + it("throws for invalid strings", () => { + expect(() => uint64ToString("")).toThrow(); + expect(() => uint64ToString("0x22")).toThrow(); + expect(() => uint64ToString("-1")).toThrow(); + expect(() => uint64ToString("1.1")).toThrow(); + expect(() => uint64ToString("18446744073709551616")).toThrow(); + }); + }); +}); diff --git a/packages/sdk38/src/lcdapi/utils.ts b/packages/sdk38/src/lcdapi/utils.ts new file mode 100644 index 00000000..4268fc13 --- /dev/null +++ b/packages/sdk38/src/lcdapi/utils.ts @@ -0,0 +1,23 @@ +import { Uint64 } from "@cosmjs/math"; + +/** + * Converts an integer expressed as number or string to a number. + * Throws if input is not a valid uint64 or if the value exceeds MAX_SAFE_INTEGER. + * + * This is needed for supporting Comsos SDK 0.37/0.38/0.39 with one client. + */ +export function uint64ToNumber(input: number | string): number { + const value = typeof input === "number" ? Uint64.fromNumber(input) : Uint64.fromString(input); + return value.toNumber(); +} + +/** + * Converts an integer expressed as number or string to a string. + * Throws if input is not a valid uint64. + * + * This is needed for supporting Comsos SDK 0.37/0.38/0.39 with one client. + */ +export function uint64ToString(input: number | string): string { + const value = typeof input === "number" ? Uint64.fromNumber(input) : Uint64.fromString(input); + return value.toString(); +} diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index d84be9f2..b375c43e 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -76,6 +76,8 @@ export { StakingPoolResponse, SupplyExtension, TxsResponse, + uint64ToNumber, + uint64ToString, } from "./lcdapi"; export { isMsgDelegate, isMsgSend, Msg, MsgDelegate, MsgSend } from "./msgs"; export { decodeBech32Pubkey, encodeBech32Pubkey, encodeSecp256k1Pubkey } from "./pubkey"; diff --git a/packages/sdk38/types/lcdapi/index.d.ts b/packages/sdk38/types/lcdapi/index.d.ts index 6a06331d..38460f39 100644 --- a/packages/sdk38/types/lcdapi/index.d.ts +++ b/packages/sdk38/types/lcdapi/index.d.ts @@ -68,3 +68,4 @@ export { TxsResponse, } from "./base"; export { LcdApiArray, LcdClient, normalizeLcdApiArray } from "./lcdclient"; +export { uint64ToNumber, uint64ToString } from "./utils"; diff --git a/packages/sdk38/types/lcdapi/utils.d.ts b/packages/sdk38/types/lcdapi/utils.d.ts new file mode 100644 index 00000000..a7be38a5 --- /dev/null +++ b/packages/sdk38/types/lcdapi/utils.d.ts @@ -0,0 +1,14 @@ +/** + * Converts an integer expressed as number or string to a number. + * Throws if input is not a valid uint64 or if the value exceeds MAX_SAFE_INTEGER. + * + * This is needed for supporting Comsos SDK 0.37/0.38/0.39 with one client. + */ +export declare function uint64ToNumber(input: number | string): number; +/** + * Converts an integer expressed as number or string to a string. + * Throws if input is not a valid uint64. + * + * This is needed for supporting Comsos SDK 0.37/0.38/0.39 with one client. + */ +export declare function uint64ToString(input: number | string): string; From 29e98ec1560dff80b625a3b9eb9ed23df39b6606 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Sat, 25 Jul 2020 15:57:46 +0200 Subject: [PATCH 2/5] Rename CosmosSdkAccount to BaseAccount --- CHANGELOG.md | 1 + packages/sdk38/src/index.ts | 1 + packages/sdk38/src/lcdapi/auth.ts | 12 ++++++++++-- packages/sdk38/src/lcdapi/index.ts | 2 +- packages/sdk38/types/index.d.ts | 1 + packages/sdk38/types/lcdapi/auth.d.ts | 12 ++++++++++-- packages/sdk38/types/lcdapi/index.d.ts | 2 +- 7 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1768da89..4b9a1daa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - @cosmjs/sdk38: Remove `Pen` type in favour of `OfflineSigner` and remove `Secp256k1Pen` class in favour of `Secp256k1Wallet` which takes an `OfflineSigner` instead of a `SigningCallback`. +- @cosmjs/sdk38: Rename `CosmosSdkAccount` to `BaseAccount` and export the type. - @cosmjs/math: Add missing integer check to `Uint64.fromNumber`. Before `Uint64.fromNumber(1.1)` produced some result. - @cosmjs/sdk38: Add `SigningCosmosClient.signAndPost` as a mid-level diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index 305cdbee..9d38062d 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -30,6 +30,7 @@ export { AuthExtension, BankBalancesResponse, BankExtension, + BaseAccount, BlockResponse, BroadcastMode, DistributionCommunityPoolResponse, diff --git a/packages/sdk38/src/lcdapi/auth.ts b/packages/sdk38/src/lcdapi/auth.ts index 942d117b..c882c557 100644 --- a/packages/sdk38/src/lcdapi/auth.ts +++ b/packages/sdk38/src/lcdapi/auth.ts @@ -2,7 +2,15 @@ import { Coin } from "../coins"; import { LcdClient } from "./lcdclient"; -export interface CosmosSdkAccount { +/** + * A Cosmos SDK base account. + * + * This type describes the base account representation as returned + * by the Cosmos SDK 0.37–0.39 LCD API. + * + * @see https://docs.cosmos.network/master/modules/auth/02_state.html#base-account + */ +export interface BaseAccount { /** Bech32 account address */ readonly address: string; readonly coins: readonly Coin[]; @@ -16,7 +24,7 @@ export interface AuthAccountsResponse { readonly height: string; readonly result: { readonly type: "cosmos-sdk/Account"; - readonly value: CosmosSdkAccount; + readonly value: BaseAccount; }; } diff --git a/packages/sdk38/src/lcdapi/index.ts b/packages/sdk38/src/lcdapi/index.ts index 767f3cd6..e305cf46 100644 --- a/packages/sdk38/src/lcdapi/index.ts +++ b/packages/sdk38/src/lcdapi/index.ts @@ -2,7 +2,7 @@ // Standard modules (see tracking issue https://github.com/CosmWasm/cosmjs/issues/276) // -export { AuthExtension, AuthAccountsResponse, setupAuthExtension } from "./auth"; +export { AuthExtension, AuthAccountsResponse, BaseAccount, setupAuthExtension } from "./auth"; export { BankBalancesResponse, BankExtension, setupBankExtension } from "./bank"; export { DistributionCommunityPoolResponse, diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index b375c43e..b6312441 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -28,6 +28,7 @@ export { AuthExtension, BankBalancesResponse, BankExtension, + BaseAccount, BlockResponse, BroadcastMode, DistributionCommunityPoolResponse, diff --git a/packages/sdk38/types/lcdapi/auth.d.ts b/packages/sdk38/types/lcdapi/auth.d.ts index 95f404d3..2166627e 100644 --- a/packages/sdk38/types/lcdapi/auth.d.ts +++ b/packages/sdk38/types/lcdapi/auth.d.ts @@ -1,6 +1,14 @@ import { Coin } from "../coins"; import { LcdClient } from "./lcdclient"; -export interface CosmosSdkAccount { +/** + * A Cosmos SDK base account. + * + * This type describes the base account representation as returned + * by the Cosmos SDK 0.37–0.39 LCD API. + * + * @see https://docs.cosmos.network/master/modules/auth/02_state.html#base-account + */ +export interface BaseAccount { /** Bech32 account address */ readonly address: string; readonly coins: readonly Coin[]; @@ -13,7 +21,7 @@ export interface AuthAccountsResponse { readonly height: string; readonly result: { readonly type: "cosmos-sdk/Account"; - readonly value: CosmosSdkAccount; + readonly value: BaseAccount; }; } export interface AuthExtension { diff --git a/packages/sdk38/types/lcdapi/index.d.ts b/packages/sdk38/types/lcdapi/index.d.ts index 38460f39..3d14ccf2 100644 --- a/packages/sdk38/types/lcdapi/index.d.ts +++ b/packages/sdk38/types/lcdapi/index.d.ts @@ -1,4 +1,4 @@ -export { AuthExtension, AuthAccountsResponse, setupAuthExtension } from "./auth"; +export { AuthExtension, AuthAccountsResponse, BaseAccount, setupAuthExtension } from "./auth"; export { BankBalancesResponse, BankExtension, setupBankExtension } from "./bank"; export { DistributionCommunityPoolResponse, From 4dca3619de8564764b4f6a0d7a7b21763c704fb7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Sat, 25 Jul 2020 15:58:17 +0200 Subject: [PATCH 3/5] Change account_number/sequence type to number | string --- CHANGELOG.md | 3 +++ packages/cosmwasm/src/cosmwasmclient.ts | 5 +++-- packages/sdk38/src/cosmosclient.ts | 6 +++--- packages/sdk38/src/encoding.ts | 9 +++++---- packages/sdk38/src/lcdapi/auth.ts | 22 ++++++++++++++++++++-- packages/sdk38/types/encoding.d.ts | 4 ++-- packages/sdk38/types/lcdapi/auth.d.ts | 22 ++++++++++++++++++++-- 7 files changed, 56 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9a1daa..26d09893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ `Secp256k1Pen` class in favour of `Secp256k1Wallet` which takes an `OfflineSigner` instead of a `SigningCallback`. - @cosmjs/sdk38: Rename `CosmosSdkAccount` to `BaseAccount` and export the type. +- @cosmjs/sdk38: `BaseAccount` now uses `number | string` as the type for + `account_number` and `sequence`. The new helpers `uint64ToNumber` and + `uint64ToString` allow you to normalize the mixed input. - @cosmjs/math: Add missing integer check to `Uint64.fromNumber`. Before `Uint64.fromNumber(1.1)` produced some result. - @cosmjs/sdk38: Add `SigningCosmosClient.signAndPost` as a mid-level diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index f2543c97..b404422b 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -13,6 +13,7 @@ import { PubKey, setupAuthExtension, StdTx, + uint64ToNumber, } from "@cosmjs/sdk38"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; @@ -234,8 +235,8 @@ export class CosmWasmClient { address: value.address, balance: value.coins, pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined, - accountNumber: value.account_number, - sequence: value.sequence, + accountNumber: uint64ToNumber(value.account_number), + sequence: uint64ToNumber(value.sequence), }; } } diff --git a/packages/sdk38/src/cosmosclient.ts b/packages/sdk38/src/cosmosclient.ts index 34ee4fe0..cf90cd19 100644 --- a/packages/sdk38/src/cosmosclient.ts +++ b/packages/sdk38/src/cosmosclient.ts @@ -3,7 +3,7 @@ import { fromBase64, fromHex, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { Coin } from "./coins"; -import { AuthExtension, BroadcastMode, LcdClient, setupAuthExtension } from "./lcdapi"; +import { AuthExtension, BroadcastMode, LcdClient, setupAuthExtension, uint64ToNumber } from "./lcdapi"; import { Log, parseLogs } from "./logs"; import { decodeBech32Pubkey } from "./pubkey"; import { CosmosSdkTx, PubKey, StdTx } from "./types"; @@ -235,8 +235,8 @@ export class CosmosClient { address: value.address, balance: value.coins, pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined, - accountNumber: value.account_number, - sequence: value.sequence, + accountNumber: uint64ToNumber(value.account_number), + sequence: uint64ToNumber(value.sequence), }; } } diff --git a/packages/sdk38/src/encoding.ts b/packages/sdk38/src/encoding.ts index 70ef1f23..17f8de77 100644 --- a/packages/sdk38/src/encoding.ts +++ b/packages/sdk38/src/encoding.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { toUtf8 } from "@cosmjs/encoding"; +import { uint64ToString } from "./lcdapi"; import { Msg } from "./msgs"; import { StdFee } from "./types"; @@ -41,16 +42,16 @@ export function makeSignBytes( fee: StdFee, chainId: string, memo: string, - accountNumber: number, - sequence: number, + accountNumber: number | string, + sequence: number | string, ): Uint8Array { const signDoc: StdSignDoc = { - account_number: accountNumber.toString(), + account_number: uint64ToString(accountNumber), chain_id: chainId, fee: fee, memo: memo, msgs: msgs, - sequence: sequence.toString(), + sequence: uint64ToString(sequence), }; const sortedSignDoc = sortJson(signDoc); return toUtf8(JSON.stringify(sortedSignDoc)); diff --git a/packages/sdk38/src/lcdapi/auth.ts b/packages/sdk38/src/lcdapi/auth.ts index c882c557..21da0e80 100644 --- a/packages/sdk38/src/lcdapi/auth.ts +++ b/packages/sdk38/src/lcdapi/auth.ts @@ -16,8 +16,26 @@ export interface BaseAccount { readonly coins: readonly Coin[]; /** Bech32 encoded pubkey */ readonly public_key: string; - readonly account_number: number; - readonly sequence: number; + /** + * The account number assigned by the blockchain. + * + * This was string encoded in Cosmos SDK 0.37, changed to number in Cosmos SDK 0.38 ([1]) + * and changed back to string in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly account_number: number | string; + /** + * The sequence number for replay protection. + * + * This was string encoded in Cosmos SDK 0.37, changed to number in Cosmos SDK 0.38 ([1]) + * and changed back to string in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly sequence: number | string; } export interface AuthAccountsResponse { diff --git a/packages/sdk38/types/encoding.d.ts b/packages/sdk38/types/encoding.d.ts index 6eece8ca..35885e4d 100644 --- a/packages/sdk38/types/encoding.d.ts +++ b/packages/sdk38/types/encoding.d.ts @@ -5,6 +5,6 @@ export declare function makeSignBytes( fee: StdFee, chainId: string, memo: string, - accountNumber: number, - sequence: number, + accountNumber: number | string, + sequence: number | string, ): Uint8Array; diff --git a/packages/sdk38/types/lcdapi/auth.d.ts b/packages/sdk38/types/lcdapi/auth.d.ts index 2166627e..dc5261b5 100644 --- a/packages/sdk38/types/lcdapi/auth.d.ts +++ b/packages/sdk38/types/lcdapi/auth.d.ts @@ -14,8 +14,26 @@ export interface BaseAccount { readonly coins: readonly Coin[]; /** Bech32 encoded pubkey */ readonly public_key: string; - readonly account_number: number; - readonly sequence: number; + /** + * The account number assigned by the blockchain. + * + * This was string encoded in Cosmos SDK 0.37, changed to number in Cosmos SDK 0.38 ([1]) + * and changed back to string in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly account_number: number | string; + /** + * The sequence number for replay protection. + * + * This was string encoded in Cosmos SDK 0.37, changed to number in Cosmos SDK 0.38 ([1]) + * and changed back to string in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly sequence: number | string; } export interface AuthAccountsResponse { readonly height: string; From 2b52c8e75dca35d85f53a27a0667a9071049f96e Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Sat, 25 Jul 2020 16:12:21 +0200 Subject: [PATCH 4/5] Add normalizePubkey --- packages/sdk38/src/index.ts | 1 + packages/sdk38/src/lcdapi/index.ts | 2 +- packages/sdk38/src/lcdapi/utils.spec.ts | 29 ++++++++++++++++++++++++- packages/sdk38/src/lcdapi/utils.ts | 15 +++++++++++++ packages/sdk38/types/index.d.ts | 1 + packages/sdk38/types/lcdapi/index.d.ts | 2 +- packages/sdk38/types/lcdapi/utils.d.ts | 8 +++++++ 7 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index 9d38062d..05adf9ce 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -61,6 +61,7 @@ export { MintParametersResponse, NodeInfoResponse, normalizeLcdApiArray, + normalizePubkey, PostTxsResponse, SearchTxsResponse, setupAuthExtension, diff --git a/packages/sdk38/src/lcdapi/index.ts b/packages/sdk38/src/lcdapi/index.ts index e305cf46..db3bdb73 100644 --- a/packages/sdk38/src/lcdapi/index.ts +++ b/packages/sdk38/src/lcdapi/index.ts @@ -81,4 +81,4 @@ export { LcdApiArray, LcdClient, normalizeLcdApiArray } from "./lcdclient"; // // Utils for interacting with the client/API // -export { uint64ToNumber, uint64ToString } from "./utils"; +export { normalizePubkey, uint64ToNumber, uint64ToString } from "./utils"; diff --git a/packages/sdk38/src/lcdapi/utils.spec.ts b/packages/sdk38/src/lcdapi/utils.spec.ts index a4628096..ace1c60e 100644 --- a/packages/sdk38/src/lcdapi/utils.spec.ts +++ b/packages/sdk38/src/lcdapi/utils.spec.ts @@ -1,4 +1,5 @@ -import { uint64ToNumber, uint64ToString } from "./utils"; +import { PubKey } from "../types"; +import { normalizePubkey, uint64ToNumber, uint64ToString } from "./utils"; describe("utils", () => { describe("uint64ToNumber", () => { @@ -64,4 +65,30 @@ describe("utils", () => { expect(() => uint64ToString("18446744073709551616")).toThrow(); }); }); + + describe("normalizePubkey", () => { + it("interprets empty bech32 string as unset", () => { + expect(normalizePubkey("")).toBeNull(); + }); + + it("decodes bech32 pubkey", () => { + const input = "cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5"; + expect(normalizePubkey(input)).toEqual({ + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }); + }); + + it("interprets null as unset", () => { + expect(normalizePubkey(null)).toBeNull(); + }); + + it("passes PubKey unchanged", () => { + const original: PubKey = { + type: "tendermint/PubKeySecp256k1", + value: "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ", + }; + expect(original).toEqual(original); + }); + }); }); diff --git a/packages/sdk38/src/lcdapi/utils.ts b/packages/sdk38/src/lcdapi/utils.ts index 4268fc13..5f797746 100644 --- a/packages/sdk38/src/lcdapi/utils.ts +++ b/packages/sdk38/src/lcdapi/utils.ts @@ -1,5 +1,8 @@ import { Uint64 } from "@cosmjs/math"; +import { decodeBech32Pubkey } from "../pubkey"; +import { PubKey } from "../types"; + /** * Converts an integer expressed as number or string to a number. * Throws if input is not a valid uint64 or if the value exceeds MAX_SAFE_INTEGER. @@ -21,3 +24,15 @@ export function uint64ToString(input: number | string): string { const value = typeof input === "number" ? Uint64.fromNumber(input) : Uint64.fromString(input); return value.toString(); } + +/** + * Normalizes a pubkey as in `BaseAccount.public_key` to allow supporting + * Comsos SDK 0.37–0.39. + * + * Returns null when unset. + */ +export function normalizePubkey(input: string | PubKey | null): PubKey | null { + if (!input) return null; + if (typeof input === "string") return decodeBech32Pubkey(input); + return input; +} diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index b6312441..b136e0d0 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -59,6 +59,7 @@ export { MintParametersResponse, NodeInfoResponse, normalizeLcdApiArray, + normalizePubkey, PostTxsResponse, SearchTxsResponse, setupAuthExtension, diff --git a/packages/sdk38/types/lcdapi/index.d.ts b/packages/sdk38/types/lcdapi/index.d.ts index 3d14ccf2..07b83300 100644 --- a/packages/sdk38/types/lcdapi/index.d.ts +++ b/packages/sdk38/types/lcdapi/index.d.ts @@ -68,4 +68,4 @@ export { TxsResponse, } from "./base"; export { LcdApiArray, LcdClient, normalizeLcdApiArray } from "./lcdclient"; -export { uint64ToNumber, uint64ToString } from "./utils"; +export { normalizePubkey, uint64ToNumber, uint64ToString } from "./utils"; diff --git a/packages/sdk38/types/lcdapi/utils.d.ts b/packages/sdk38/types/lcdapi/utils.d.ts index a7be38a5..d3268564 100644 --- a/packages/sdk38/types/lcdapi/utils.d.ts +++ b/packages/sdk38/types/lcdapi/utils.d.ts @@ -1,3 +1,4 @@ +import { PubKey } from "../types"; /** * Converts an integer expressed as number or string to a number. * Throws if input is not a valid uint64 or if the value exceeds MAX_SAFE_INTEGER. @@ -12,3 +13,10 @@ export declare function uint64ToNumber(input: number | string): number; * This is needed for supporting Comsos SDK 0.37/0.38/0.39 with one client. */ export declare function uint64ToString(input: number | string): string; +/** + * Normalizes a pubkey as in `BaseAccount.public_key` to allow supporting + * Comsos SDK 0.37–0.39. + * + * Returns null when unset. + */ +export declare function normalizePubkey(input: string | PubKey | null): PubKey | null; From 5ad11bdef6c42a93fd212939574155af93ced2bf Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 28 Jul 2020 12:39:33 +0200 Subject: [PATCH 5/5] Use string | PubKey | null as public key type --- CHANGELOG.md | 3 +++ packages/cosmwasm/src/cosmwasmclient.ts | 4 ++-- packages/sdk38/src/cosmosclient.ts | 12 +++++++++--- packages/sdk38/src/lcdapi/auth.ts | 14 ++++++++++++-- packages/sdk38/types/lcdapi/auth.d.ts | 14 ++++++++++++-- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26d09893..f5305260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ - @cosmjs/sdk38: `BaseAccount` now uses `number | string` as the type for `account_number` and `sequence`. The new helpers `uint64ToNumber` and `uint64ToString` allow you to normalize the mixed input. +- @cosmjs/sdk38: `BaseAccount` now uses `string | PubKey | null` as the type for + `public_key`. The new helper `normalizePubkey` allows you to normalize the + mixed input. - @cosmjs/math: Add missing integer check to `Uint64.fromNumber`. Before `Uint64.fromNumber(1.1)` produced some result. - @cosmjs/sdk38: Add `SigningCosmosClient.signAndPost` as a mid-level diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index b404422b..c16a8965 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -6,9 +6,9 @@ import { BroadcastMode, Coin, CosmosSdkTx, - decodeBech32Pubkey, IndexedTx, LcdClient, + normalizePubkey, PostTxResult, PubKey, setupAuthExtension, @@ -234,7 +234,7 @@ export class CosmWasmClient { return { address: value.address, balance: value.coins, - pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined, + pubkey: normalizePubkey(value.public_key) || undefined, accountNumber: uint64ToNumber(value.account_number), sequence: uint64ToNumber(value.sequence), }; diff --git a/packages/sdk38/src/cosmosclient.ts b/packages/sdk38/src/cosmosclient.ts index cf90cd19..555afd43 100644 --- a/packages/sdk38/src/cosmosclient.ts +++ b/packages/sdk38/src/cosmosclient.ts @@ -3,9 +3,15 @@ import { fromBase64, fromHex, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { Coin } from "./coins"; -import { AuthExtension, BroadcastMode, LcdClient, setupAuthExtension, uint64ToNumber } from "./lcdapi"; +import { + AuthExtension, + BroadcastMode, + LcdClient, + normalizePubkey, + setupAuthExtension, + uint64ToNumber, +} from "./lcdapi"; import { Log, parseLogs } from "./logs"; -import { decodeBech32Pubkey } from "./pubkey"; import { CosmosSdkTx, PubKey, StdTx } from "./types"; export interface GetSequenceResult { @@ -234,7 +240,7 @@ export class CosmosClient { return { address: value.address, balance: value.coins, - pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined, + pubkey: normalizePubkey(value.public_key) || undefined, accountNumber: uint64ToNumber(value.account_number), sequence: uint64ToNumber(value.sequence), }; diff --git a/packages/sdk38/src/lcdapi/auth.ts b/packages/sdk38/src/lcdapi/auth.ts index 21da0e80..6b316466 100644 --- a/packages/sdk38/src/lcdapi/auth.ts +++ b/packages/sdk38/src/lcdapi/auth.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Coin } from "../coins"; +import { PubKey } from "../types"; import { LcdClient } from "./lcdclient"; /** @@ -14,8 +15,17 @@ export interface BaseAccount { /** Bech32 account address */ readonly address: string; readonly coins: readonly Coin[]; - /** Bech32 encoded pubkey */ - readonly public_key: string; + /** + * The public key of the account. This is not available on-chain as long as the account + * did not send a transaction. + * + * This was a type/value object in Cosmos SDK 0.37, changed to bech32 in Cosmos SDK 0.38 ([1]) + * and changed back to type/value object in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly public_key: string | PubKey | null; /** * The account number assigned by the blockchain. * diff --git a/packages/sdk38/types/lcdapi/auth.d.ts b/packages/sdk38/types/lcdapi/auth.d.ts index dc5261b5..e20b7102 100644 --- a/packages/sdk38/types/lcdapi/auth.d.ts +++ b/packages/sdk38/types/lcdapi/auth.d.ts @@ -1,4 +1,5 @@ import { Coin } from "../coins"; +import { PubKey } from "../types"; import { LcdClient } from "./lcdclient"; /** * A Cosmos SDK base account. @@ -12,8 +13,17 @@ export interface BaseAccount { /** Bech32 account address */ readonly address: string; readonly coins: readonly Coin[]; - /** Bech32 encoded pubkey */ - readonly public_key: string; + /** + * The public key of the account. This is not available on-chain as long as the account + * did not send a transaction. + * + * This was a type/value object in Cosmos SDK 0.37, changed to bech32 in Cosmos SDK 0.38 ([1]) + * and changed back to type/value object in Cosmos SDK 0.39 ([2]). + * + * [1]: https://github.com/cosmos/cosmos-sdk/pull/5280 + * [2]: https://github.com/cosmos/cosmos-sdk/pull/6749 + */ + readonly public_key: string | PubKey | null; /** * The account number assigned by the blockchain. *