From a0ee9963c108e0b2020a6309ea9c2e73f05345eb Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 10:21:42 +0200 Subject: [PATCH 01/12] Move OfflineSigner interface to signer module --- packages/launchpad/src/index.ts | 11 ++------ packages/launchpad/src/secp256k1wallet.ts | 4 +-- packages/launchpad/src/signer.ts | 24 ++++++++++++++++++ packages/launchpad/src/signingcosmosclient.ts | 2 +- packages/launchpad/src/wallet.ts | 25 +------------------ packages/launchpad/types/index.d.ts | 11 ++------ packages/launchpad/types/secp256k1wallet.d.ts | 3 ++- packages/launchpad/types/signer.d.ts | 19 ++++++++++++++ .../launchpad/types/signingcosmosclient.d.ts | 2 +- packages/launchpad/types/wallet.d.ts | 19 +------------- 10 files changed, 54 insertions(+), 66 deletions(-) create mode 100644 packages/launchpad/src/signer.ts create mode 100644 packages/launchpad/types/signer.d.ts diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 3701ab33..7cc94695 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -98,15 +98,8 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; +export { AccountData, Algo, PrehashType, OfflineSigner } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; -export { - AccountData, - Algo, - PrehashType, - OfflineSigner, - makeCosmoshubPath, - executeKdf, - KdfConfiguration, -} from "./wallet"; +export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/src/secp256k1wallet.ts b/packages/launchpad/src/secp256k1wallet.ts index 5f5aea9a..e788250a 100644 --- a/packages/launchpad/src/secp256k1wallet.ts +++ b/packages/launchpad/src/secp256k1wallet.ts @@ -14,18 +14,16 @@ import { assert, isNonNullObject } from "@cosmjs/utils"; import { rawSecp256k1PubkeyToAddress } from "./address"; import { encodeSecp256k1Signature } from "./signature"; +import { AccountData, OfflineSigner, PrehashType } from "./signer"; import { StdSignature } from "./types"; import { - AccountData, decrypt, encrypt, EncryptionConfiguration, executeKdf, KdfConfiguration, makeCosmoshubPath, - OfflineSigner, prehash, - PrehashType, supportedAlgorithms, } from "./wallet"; diff --git a/packages/launchpad/src/signer.ts b/packages/launchpad/src/signer.ts new file mode 100644 index 00000000..93e1ce59 --- /dev/null +++ b/packages/launchpad/src/signer.ts @@ -0,0 +1,24 @@ +import { StdSignature } from "./types"; + +export type PrehashType = "sha256" | "sha512" | null; + +export type Algo = "secp256k1" | "ed25519" | "sr25519"; + +export interface AccountData { + /** A printable address (typically bech32 encoded) */ + readonly address: string; + readonly algo: Algo; + readonly pubkey: Uint8Array; +} + +export interface OfflineSigner { + /** + * Get AccountData array from wallet. Rejects if not enabled. + */ + readonly getAccounts: () => Promise; + + /** + * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. + */ + readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; +} diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index 5ffbd236..718e7e48 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -5,8 +5,8 @@ import { makeSignBytes } from "./encoding"; import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg, MsgSend } from "./msgs"; +import { OfflineSigner } from "./signer"; import { StdFee, StdTx } from "./types"; -import { OfflineSigner } from "./wallet"; /** * These fees are used by the higher level methods of SigningCosmosClient diff --git a/packages/launchpad/src/wallet.ts b/packages/launchpad/src/wallet.ts index eaded173..6f4f2b44 100644 --- a/packages/launchpad/src/wallet.ts +++ b/packages/launchpad/src/wallet.ts @@ -11,30 +11,7 @@ import { } from "@cosmjs/crypto"; import { toAscii } from "@cosmjs/encoding"; -import { StdSignature } from "./types"; - -export type PrehashType = "sha256" | "sha512" | null; - -export type Algo = "secp256k1" | "ed25519" | "sr25519"; - -export interface AccountData { - // bech32-encoded - readonly address: string; - readonly algo: Algo; - readonly pubkey: Uint8Array; -} - -export interface OfflineSigner { - /** - * Get AccountData array from wallet. Rejects if not enabled. - */ - readonly getAccounts: () => Promise; - - /** - * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. - */ - readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; -} +import { PrehashType } from "./signer"; export function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array { switch (type) { diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index 9d137f0b..ed0097b2 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -96,15 +96,8 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; +export { AccountData, Algo, PrehashType, OfflineSigner } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; -export { - AccountData, - Algo, - PrehashType, - OfflineSigner, - makeCosmoshubPath, - executeKdf, - KdfConfiguration, -} from "./wallet"; +export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/types/secp256k1wallet.d.ts b/packages/launchpad/types/secp256k1wallet.d.ts index a24a3366..feed1eef 100644 --- a/packages/launchpad/types/secp256k1wallet.d.ts +++ b/packages/launchpad/types/secp256k1wallet.d.ts @@ -1,6 +1,7 @@ import { HdPath } from "@cosmjs/crypto"; +import { AccountData, OfflineSigner, PrehashType } from "./signer"; import { StdSignature } from "./types"; -import { AccountData, EncryptionConfiguration, KdfConfiguration, OfflineSigner, PrehashType } from "./wallet"; +import { EncryptionConfiguration, KdfConfiguration } from "./wallet"; /** * This interface describes a JSON object holding the encrypted wallet and the meta data. * All fields in here must be JSON types. diff --git a/packages/launchpad/types/signer.d.ts b/packages/launchpad/types/signer.d.ts new file mode 100644 index 00000000..d21ed77a --- /dev/null +++ b/packages/launchpad/types/signer.d.ts @@ -0,0 +1,19 @@ +import { StdSignature } from "./types"; +export declare type PrehashType = "sha256" | "sha512" | null; +export declare type Algo = "secp256k1" | "ed25519" | "sr25519"; +export interface AccountData { + /** A printable address (typically bech32 encoded) */ + readonly address: string; + readonly algo: Algo; + readonly pubkey: Uint8Array; +} +export interface OfflineSigner { + /** + * Get AccountData array from wallet. Rejects if not enabled. + */ + readonly getAccounts: () => Promise; + /** + * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. + */ + readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; +} diff --git a/packages/launchpad/types/signingcosmosclient.d.ts b/packages/launchpad/types/signingcosmosclient.d.ts index e1110ad9..839ad665 100644 --- a/packages/launchpad/types/signingcosmosclient.d.ts +++ b/packages/launchpad/types/signingcosmosclient.d.ts @@ -3,8 +3,8 @@ import { Account, BroadcastTxResult, CosmosClient, GetSequenceResult } from "./c import { FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg } from "./msgs"; +import { OfflineSigner } from "./signer"; import { StdFee } from "./types"; -import { OfflineSigner } from "./wallet"; /** * These fees are used by the higher level methods of SigningCosmosClient */ diff --git a/packages/launchpad/types/wallet.d.ts b/packages/launchpad/types/wallet.d.ts index 5c284f5d..f3e49071 100644 --- a/packages/launchpad/types/wallet.d.ts +++ b/packages/launchpad/types/wallet.d.ts @@ -1,22 +1,5 @@ import { HdPath } from "@cosmjs/crypto"; -import { StdSignature } from "./types"; -export declare type PrehashType = "sha256" | "sha512" | null; -export declare type Algo = "secp256k1" | "ed25519" | "sr25519"; -export interface AccountData { - readonly address: string; - readonly algo: Algo; - readonly pubkey: Uint8Array; -} -export interface OfflineSigner { - /** - * Get AccountData array from wallet. Rejects if not enabled. - */ - readonly getAccounts: () => Promise; - /** - * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. - */ - readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; -} +import { PrehashType } from "./signer"; export declare function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array; /** * The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a` From 6c116f3d5a43b11c19e8627448004862ebb47d33 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 11:03:15 +0200 Subject: [PATCH 02/12] Add makeStdSignDoc and serializeSignDoc --- CHANGELOG.md | 2 ++ packages/launchpad/src/encoding.ts | 43 +++++++++++++++++--------- packages/launchpad/src/index.ts | 2 +- packages/launchpad/types/encoding.d.ts | 18 ++++++++--- packages/launchpad/types/index.d.ts | 2 +- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3565f11f..33106c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ `isSearchBySentFromOrToQuery` and `isSearchByTagsQuery`. - @cosmjs/launchpad: Change type of `TxsResponse.logs` and `BroadcastTxsResponse.logs` to `unknown[]`. +- @cosmjs/launchpad: Export `StdSignDoc` and create helpers to make and + serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/launchpad/src/encoding.ts b/packages/launchpad/src/encoding.ts index 3c09e775..6f11b168 100644 --- a/packages/launchpad/src/encoding.ts +++ b/packages/launchpad/src/encoding.ts @@ -29,14 +29,38 @@ function sortJson(json: any): any { * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdsigndoc */ export interface StdSignDoc { - readonly account_number: string; readonly chain_id: string; - readonly fee: StdFee; - readonly memo: string; - readonly msgs: readonly Msg[]; + readonly account_number: string; readonly sequence: string; + readonly fee: StdFee; + readonly msgs: readonly Msg[]; + readonly memo: string; } +export function makeStdSignDoc( + msgs: readonly Msg[], + fee: StdFee, + chainId: string, + memo: string, + accountNumber: number | string, + sequence: number | string, +): StdSignDoc { + return { + chain_id: chainId, + account_number: uint64ToString(accountNumber), + sequence: uint64ToString(sequence), + fee: fee, + msgs: msgs, + memo: memo, + }; +} + +export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array { + const sortedSignDoc = sortJson(signDoc); + return toUtf8(JSON.stringify(sortedSignDoc)); +} + +/** A convenience helper to create the StdSignDoc and serialize it */ export function makeSignBytes( msgs: readonly Msg[], fee: StdFee, @@ -45,14 +69,5 @@ export function makeSignBytes( accountNumber: number | string, sequence: number | string, ): Uint8Array { - const signDoc: StdSignDoc = { - account_number: uint64ToString(accountNumber), - chain_id: chainId, - fee: fee, - memo: memo, - msgs: msgs, - sequence: uint64ToString(sequence), - }; - const sortedSignDoc = sortJson(signDoc); - return toUtf8(JSON.stringify(sortedSignDoc)); + return serializeSignDoc(makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence)); } diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 7cc94695..7cf967f8 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -28,7 +28,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeSignBytes, StdSignDoc } from "./encoding"; +export { makeSignBytes, makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, diff --git a/packages/launchpad/types/encoding.d.ts b/packages/launchpad/types/encoding.d.ts index 51c2c0c4..bb026862 100644 --- a/packages/launchpad/types/encoding.d.ts +++ b/packages/launchpad/types/encoding.d.ts @@ -6,13 +6,23 @@ import { StdFee } from "./types"; * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdsigndoc */ export interface StdSignDoc { - readonly account_number: string; readonly chain_id: string; - readonly fee: StdFee; - readonly memo: string; - readonly msgs: readonly Msg[]; + readonly account_number: string; readonly sequence: string; + readonly fee: StdFee; + readonly msgs: readonly Msg[]; + readonly memo: string; } +export declare function makeStdSignDoc( + msgs: readonly Msg[], + fee: StdFee, + chainId: string, + memo: string, + accountNumber: number | string, + sequence: number | string, +): StdSignDoc; +export declare function serializeSignDoc(signDoc: StdSignDoc): Uint8Array; +/** A convenience helper to create the StdSignDoc and serialize it */ export declare function makeSignBytes( msgs: readonly Msg[], fee: StdFee, diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index ed0097b2..6d9b9ee8 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -26,7 +26,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeSignBytes, StdSignDoc } from "./encoding"; +export { makeSignBytes, makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, From bc890bee73d7c37287ac2d8e36699a5daa5f5bef Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 15:58:34 +0200 Subject: [PATCH 03/12] Let OfflineSigner.sign take a StdSignDoc instead of an encoded message --- CHANGELOG.md | 2 + .../src/cosmwasmclient.searchtx.spec.ts | 6 +- packages/cosmwasm/src/cosmwasmclient.spec.ts | 6 +- packages/cosmwasm/src/lcdapi/wasm.spec.ts | 6 +- .../cosmwasm/src/signingcosmwasmclient.ts | 6 +- packages/launchpad-ledger/demo/index.html | 2 +- packages/launchpad-ledger/src/demo/node.ts | 6 +- packages/launchpad-ledger/src/demo/web.ts | 75 +++++++++++-------- packages/launchpad-ledger/src/ledgersigner.ts | 9 ++- .../launchpad-ledger/types/ledgersigner.d.ts | 4 +- .../src/cosmosclient.searchtx.spec.ts | 6 +- packages/launchpad/src/cosmosclient.spec.ts | 6 +- .../launchpad/src/lcdapi/distribution.spec.ts | 6 +- packages/launchpad/src/lcdapi/gov.spec.ts | 10 +-- .../launchpad/src/lcdapi/lcdclient.spec.ts | 52 ++++++------- packages/launchpad/src/lcdapi/staking.spec.ts | 10 +-- .../launchpad/src/secp256k1wallet.spec.ts | 17 ++++- packages/launchpad/src/secp256k1wallet.ts | 19 ++--- packages/launchpad/src/signer.ts | 10 ++- packages/launchpad/src/signingcosmosclient.ts | 6 +- packages/launchpad/types/secp256k1wallet.d.ts | 5 +- packages/launchpad/types/signer.d.ts | 10 ++- 22 files changed, 160 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33106c95..99187b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ `BroadcastTxsResponse.logs` to `unknown[]`. - @cosmjs/launchpad: Export `StdSignDoc` and create helpers to make and serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`. +- @cosmjs/launchpad: Let `OfflineSigner.sign` take an `StdSignDoc` instead of an + encoded message. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index b9d6d359..bf6ae681 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -6,7 +6,7 @@ import { isBroadcastTxFailure, isMsgSend, LcdClient, - makeSignBytes, + makeStdSignDoc, MsgSend, Secp256k1Wallet, } from "@cosmjs/launchpad"; @@ -103,8 +103,8 @@ describe("CosmWasmClient.searchTx", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(alice.address0, signBytes); + const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(alice.address0, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", value: { diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index 868aa02a..fcdf8e6d 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -3,7 +3,7 @@ import { Sha256 } from "@cosmjs/crypto"; import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding"; import { assertIsBroadcastTxSuccess, - makeSignBytes, + makeStdSignDoc, MsgSend, Secp256k1Wallet, StdFee, @@ -236,8 +236,8 @@ describe("CosmWasmClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(alice.address0); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(alice.address0, signBytes); + const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(alice.address0, signDoc); const signedTx = { msg: [sendMsg], fee: fee, diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index 0614d990..83790e1a 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -10,7 +10,7 @@ import { coin, coins, LcdClient, - makeSignBytes, + makeStdSignDoc, OfflineSigner, Secp256k1Wallet, setupAuthExtension, @@ -125,8 +125,8 @@ async function executeContract( }; const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value; - const signBytes = makeSignBytes([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const signature = await signer.sign(alice.address0, signBytes); + const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); + const signature = await signer.sign(alice.address0, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.broadcastTx(signedTx); } diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index d0fff774..0b27a2c3 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -11,7 +11,7 @@ import { GasLimits, GasPrice, isBroadcastTxFailure, - makeSignBytes, + makeStdSignDoc, Msg, MsgSend, OfflineSigner, @@ -360,8 +360,8 @@ export class SigningCosmWasmClient extends CosmWasmClient { public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signBytes = makeSignBytes(msgs, fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); + const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); + const signature = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, fee: fee, diff --git a/packages/launchpad-ledger/demo/index.html b/packages/launchpad-ledger/demo/index.html index 7a04b1cd..7da23c11 100644 --- a/packages/launchpad-ledger/demo/index.html +++ b/packages/launchpad-ledger/demo/index.html @@ -34,7 +34,7 @@
-
diff --git a/packages/launchpad-ledger/src/demo/node.ts b/packages/launchpad-ledger/src/demo/node.ts index ef3b3bb1..6cd967e2 100644 --- a/packages/launchpad-ledger/src/demo/node.ts +++ b/packages/launchpad-ledger/src/demo/node.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { toBase64 } from "@cosmjs/encoding"; -import { makeCosmoshubPath, makeSignBytes, StdFee, StdSignature } from "@cosmjs/launchpad"; +import { makeCosmoshubPath, makeStdSignDoc, StdFee, StdSignature } from "@cosmjs/launchpad"; import { LedgerSigner } from "../ledgersigner"; @@ -48,7 +48,7 @@ export async function sign( }, }, ]; - const signBytes = makeSignBytes( + const signDoc = makeStdSignDoc( msgs, defaultFee, defaultChainId, @@ -56,5 +56,5 @@ export async function sign( accountNumber, defaultSequence, ); - return signer.sign(fromAddress, signBytes); + return signer.sign(fromAddress, signDoc); } diff --git a/packages/launchpad-ledger/src/demo/web.ts b/packages/launchpad-ledger/src/demo/web.ts index e656a871..c9297c47 100644 --- a/packages/launchpad-ledger/src/demo/web.ts +++ b/packages/launchpad-ledger/src/demo/web.ts @@ -1,5 +1,7 @@ -import { toBase64, toUtf8 } from "@cosmjs/encoding"; -import { AccountData, makeCosmoshubPath } from "@cosmjs/launchpad"; +import { toBase64 } from "@cosmjs/encoding"; +import { AccountData, makeCosmoshubPath, StdSignDoc } from "@cosmjs/launchpad"; +import { Uint53 } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; import { LedgerSigner } from "../ledgersigner"; @@ -8,28 +10,37 @@ declare const document: any; let accounts: readonly AccountData[] = []; -function createMessage(accountNumber: number, address: string): string { - return `{ - "account_number": ${accountNumber}, - "chain_id": "testing", - "fee": { - "amount": [{ "amount": 100, "denom": "ucosm" }], - "gas": 250 +function createSignDoc(accountNumber: number, address: string): string { + const signDoc: StdSignDoc = { + // eslint-disable-next-line @typescript-eslint/naming-convention + chain_id: "testing", + // eslint-disable-next-line @typescript-eslint/naming-convention + account_number: `${accountNumber}`, + sequence: "0", + fee: { + amount: [{ amount: "100", denom: "ucosm" }], + gas: "250", }, - "memo": "Some memo", - "msgs": [{ - "type": "cosmos-sdk/MsgSend", - "value": { - "amount": [{ - "amount": "1234567", - "denom": "ucosm" - }], - "from_address": "${address}", - "to_address": "${address}" - } - }], - "sequence": 0 - }`; + memo: "Some memo", + msgs: [ + { + type: "cosmos-sdk/MsgSend", + value: { + amount: [ + { + amount: "1234567", + denom: "ucosm", + }, + ], + // eslint-disable-next-line @typescript-eslint/naming-convention + from_address: address, + // eslint-disable-next-line @typescript-eslint/naming-convention + to_address: address, + }, + }, + ], + }; + return JSON.stringify(signDoc, null, 2); } const signer = new LedgerSigner({ @@ -37,7 +48,9 @@ const signer = new LedgerSigner({ hdPaths: [makeCosmoshubPath(0), makeCosmoshubPath(1), makeCosmoshubPath(2)], }); -window.updateMessage = (accountNumber: number) => { +window.updateMessage = (accountNumberInput: unknown) => { + assert(typeof accountNumberInput === "string"); + const accountNumber = Uint53.fromString(accountNumberInput).toNumber(); const account = accounts[accountNumber]; if (account === undefined) { return; @@ -46,15 +59,15 @@ window.updateMessage = (accountNumber: number) => { const address = accounts[accountNumber].address; const addressInput = document.getElementById("address"); addressInput.value = address; - const messageTextArea = document.getElementById("message"); - messageTextArea.textContent = createMessage(accountNumber, address); + const signDocTextArea = document.getElementById("sign-doc"); + signDocTextArea.textContent = createSignDoc(accountNumber, address); }; window.getAccounts = async function getAccounts(): Promise { const accountNumberInput = document.getElementById("account-number"); const addressInput = document.getElementById("address"); const accountsDiv = document.getElementById("accounts"); - const messageTextArea = document.getElementById("message"); + const signDocTextArea = document.getElementById("sign-doc"); accountsDiv.textContent = "Loading..."; try { @@ -69,7 +82,7 @@ window.getAccounts = async function getAccounts(): Promise { accountNumberInput.value = accountNumber; const address = accounts[0].address; addressInput.value = address; - messageTextArea.textContent = createMessage(accountNumber, address); + signDocTextArea.textContent = createSignDoc(accountNumber, address); } catch (error) { accountsDiv.textContent = error; } @@ -81,9 +94,9 @@ window.sign = async function sign(): Promise { try { const address = document.getElementById("address").value; - const rawMessage = document.getElementById("message").textContent; - const message = JSON.stringify(JSON.parse(rawMessage)); - const signature = await signer.sign(address, toUtf8(message)); + const signDocJson = document.getElementById("sign-doc").textContent; + const signDoc: StdSignDoc = JSON.parse(signDocJson); + const signature = await signer.sign(address, signDoc); signatureDiv.textContent = JSON.stringify(signature, null, "\t"); } catch (error) { signatureDiv.textContent = error; diff --git a/packages/launchpad-ledger/src/ledgersigner.ts b/packages/launchpad-ledger/src/ledgersigner.ts index da6892ae..c09fc03b 100644 --- a/packages/launchpad-ledger/src/ledgersigner.ts +++ b/packages/launchpad-ledger/src/ledgersigner.ts @@ -5,7 +5,9 @@ import { makeCosmoshubPath, OfflineSigner, StdSignature, + StdSignDoc, } from "@cosmjs/launchpad"; +import { serializeSignDoc } from "@cosmjs/launchpad"; import { LaunchpadLedger, LaunchpadLedgerOptions } from "./launchpadledger"; @@ -34,14 +36,15 @@ export class LedgerSigner implements OfflineSigner { return this.accounts; } - public async sign(address: string, message: Uint8Array): Promise { + public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { const accounts = this.accounts || (await this.getAccounts()); - const accountIndex = accounts.findIndex((account) => account.address === address); + const accountIndex = accounts.findIndex((account) => account.address === signerAddress); if (accountIndex === -1) { - throw new Error(`Address ${address} not found in wallet`); + throw new Error(`Address ${signerAddress} not found in wallet`); } + const message = serializeSignDoc(signDoc); const accountForAddress = accounts[accountIndex]; const hdPath = this.hdPaths[accountIndex]; const signature = await this.ledger.sign(message, hdPath); diff --git a/packages/launchpad-ledger/types/ledgersigner.d.ts b/packages/launchpad-ledger/types/ledgersigner.d.ts index 1ebfdcdd..ffc9a609 100644 --- a/packages/launchpad-ledger/types/ledgersigner.d.ts +++ b/packages/launchpad-ledger/types/ledgersigner.d.ts @@ -1,4 +1,4 @@ -import { AccountData, OfflineSigner, StdSignature } from "@cosmjs/launchpad"; +import { AccountData, OfflineSigner, StdSignature, StdSignDoc } from "@cosmjs/launchpad"; import { LaunchpadLedgerOptions } from "./launchpadledger"; export declare class LedgerSigner implements OfflineSigner { private readonly ledger; @@ -6,5 +6,5 @@ export declare class LedgerSigner implements OfflineSigner { private accounts?; constructor(options?: LaunchpadLedgerOptions); getAccounts(): Promise; - sign(address: string, message: Uint8Array): Promise; + sign(signerAddress: string, signDoc: StdSignDoc): Promise; } diff --git a/packages/launchpad/src/cosmosclient.searchtx.spec.ts b/packages/launchpad/src/cosmosclient.searchtx.spec.ts index f3bbda31..8d247634 100644 --- a/packages/launchpad/src/cosmosclient.searchtx.spec.ts +++ b/packages/launchpad/src/cosmosclient.searchtx.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { coins } from "./coins"; import { CosmosClient, isBroadcastTxFailure } from "./cosmosclient"; -import { makeSignBytes } from "./encoding"; +import { makeStdSignDoc } from "./encoding"; import { LcdClient } from "./lcdapi"; import { isMsgSend, MsgSend } from "./msgs"; import { Secp256k1Wallet } from "./secp256k1wallet"; @@ -55,8 +55,8 @@ describe("CosmosClient.searchTx", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signBytes); + const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(walletAddress, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", value: { diff --git a/packages/launchpad/src/cosmosclient.spec.ts b/packages/launchpad/src/cosmosclient.spec.ts index 03eb672f..47368a87 100644 --- a/packages/launchpad/src/cosmosclient.spec.ts +++ b/packages/launchpad/src/cosmosclient.spec.ts @@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; import { assertIsBroadcastTxSuccess, CosmosClient, PrivateCosmosClient } from "./cosmosclient"; -import { makeSignBytes } from "./encoding"; +import { makeStdSignDoc } from "./encoding"; import { findAttribute } from "./logs"; import { MsgSend } from "./msgs"; import { Secp256k1Wallet } from "./secp256k1wallet"; @@ -229,8 +229,8 @@ describe("CosmosClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(faucet.address); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signBytes); + const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(walletAddress, signDoc); const signedTx = { msg: [sendMsg], fee: fee, diff --git a/packages/launchpad/src/lcdapi/distribution.spec.ts b/packages/launchpad/src/lcdapi/distribution.spec.ts index 1f6165dd..bc68176e 100644 --- a/packages/launchpad/src/lcdapi/distribution.spec.ts +++ b/packages/launchpad/src/lcdapi/distribution.spec.ts @@ -4,7 +4,7 @@ import { sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeSignBytes } from "../encoding"; +import { makeStdSignDoc } from "../encoding"; import { MsgDelegate } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -45,8 +45,8 @@ describe("DistributionExtension", () => { }; const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signBytes); + const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, diff --git a/packages/launchpad/src/lcdapi/gov.spec.ts b/packages/launchpad/src/lcdapi/gov.spec.ts index c6cd10d1..0af73b64 100644 --- a/packages/launchpad/src/lcdapi/gov.spec.ts +++ b/packages/launchpad/src/lcdapi/gov.spec.ts @@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils"; import { coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeSignBytes } from "../encoding"; +import { makeStdSignDoc } from "../encoding"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; import { @@ -50,7 +50,7 @@ describe("GovExtension", () => { }; const proposalMemo = "Test proposal for wasmd"; const { accountNumber: proposalAccountNumber, sequence: proposalSequence } = await client.getSequence(); - const proposalSignBytes = makeSignBytes( + const proposalSignDoc = makeStdSignDoc( [proposalMsg], defaultFee, chainId, @@ -58,7 +58,7 @@ describe("GovExtension", () => { proposalAccountNumber, proposalSequence, ); - const proposalSignature = await wallet.sign(faucet.address, proposalSignBytes); + const proposalSignature = await wallet.sign(faucet.address, proposalSignDoc); const proposalTx = { msg: [proposalMsg], fee: defaultFee, @@ -82,7 +82,7 @@ describe("GovExtension", () => { }; const voteMemo = "Test vote for wasmd"; const { accountNumber: voteAccountNumber, sequence: voteSequence } = await client.getSequence(); - const voteSignBytes = makeSignBytes( + const voteSignDoc = makeStdSignDoc( [voteMsg], defaultFee, chainId, @@ -90,7 +90,7 @@ describe("GovExtension", () => { voteAccountNumber, voteSequence, ); - const voteSignature = await wallet.sign(faucet.address, voteSignBytes); + const voteSignature = await wallet.sign(faucet.address, voteSignDoc); const voteTx = { msg: [voteMsg], fee: defaultFee, diff --git a/packages/launchpad/src/lcdapi/lcdclient.spec.ts b/packages/launchpad/src/lcdapi/lcdclient.spec.ts index 42418e18..a1043d4a 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.spec.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { Coin } from "../coins"; import { isBroadcastTxFailure } from "../cosmosclient"; -import { makeSignBytes } from "../encoding"; +import { makeStdSignDoc } from "../encoding"; import { parseLogs } from "../logs"; import { MsgSend } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; @@ -239,8 +239,8 @@ describe("LcdClient", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signBytes); + const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(walletAddress, signDoc); const signedTx = { msg: [sendMsg], fee: fee, @@ -537,8 +537,8 @@ describe("LcdClient", () => { const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension); const { account_number, sequence } = (await client.auth.account(faucet.address)).result.value; - const signBytes = makeSignBytes([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const signature = await wallet.sign(walletAddress, signBytes); + const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); + const signature = await wallet.sign(walletAddress, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); const result = await client.broadcastTx(signedTx); expect(result.code).toBeUndefined(); @@ -594,12 +594,12 @@ describe("LcdClient", () => { const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; const { account_number: an3, sequence: sequence3 } = (await client.auth.account(address3)).result.value; - const signBytes1 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an1, sequence1); - const signBytes2 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an2, sequence2); - const signBytes3 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an3, sequence3); - const signature1 = await account1.sign(address1, signBytes1); - const signature2 = await account2.sign(address2, signBytes2); - const signature3 = await account3.sign(address3, signBytes3); + const signDoc1 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an2, sequence2); + const signDoc3 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an3, sequence3); + const signature1 = await account1.sign(address1, signDoc1); + const signature2 = await account2.sign(address2, signDoc2); + const signature3 = await account3.sign(address3, signDoc3); const signedTx = { msg: [theMsg], fee: fee, @@ -658,13 +658,13 @@ describe("LcdClient", () => { const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension); const { account_number, sequence } = (await client.auth.account(walletAddress)).result.value; - const signBytes = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); - const signature1 = await wallet.sign(walletAddress, signBytes); + const signDoc = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); + const signature = await wallet.sign(walletAddress, signDoc); const signedTx = { msg: [msg1, msg2], fee: fee, memo: memo, - signatures: [signature1], + signatures: [signature], }; const broadcastResult = await client.broadcastTx(signedTx); expect(broadcastResult.code).toBeUndefined(); @@ -722,10 +722,10 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signBytes1 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); - const signBytes2 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signBytes1); - const signature2 = await account2.sign(address2, signBytes2); + const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); + const signature1 = await account1.sign(address1, signDoc1); + const signature2 = await account2.sign(address2, signDoc2); const signedTx = { msg: [msg2, msg1], fee: fee, @@ -793,10 +793,10 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signBytes1 = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1); - const signBytes2 = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signBytes1); - const signature2 = await account2.sign(address2, signBytes2); + const signDoc1 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2); + const signature1 = await account1.sign(address1, signDoc1); + const signature2 = await account2.sign(address2, signDoc2); const signedTx = { msg: [msg1, msg2], fee: fee, @@ -859,10 +859,10 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signBytes1 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); - const signBytes2 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signBytes1); - const signature2 = await account2.sign(address2, signBytes2); + const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); + const signature1 = await account1.sign(address1, signDoc1); + const signature2 = await account2.sign(address2, signDoc2); const signedTx = { msg: [msg2, msg1], fee: fee, diff --git a/packages/launchpad/src/lcdapi/staking.spec.ts b/packages/launchpad/src/lcdapi/staking.spec.ts index db75603c..5efcff6c 100644 --- a/packages/launchpad/src/lcdapi/staking.spec.ts +++ b/packages/launchpad/src/lcdapi/staking.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeSignBytes } from "../encoding"; +import { makeStdSignDoc } from "../encoding"; import { MsgDelegate, MsgUndelegate } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -46,8 +46,8 @@ describe("StakingExtension", () => { }; const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signBytes); + const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, @@ -69,8 +69,8 @@ describe("StakingExtension", () => { }; const memo = "Test undelegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signBytes); + const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signature = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, diff --git a/packages/launchpad/src/secp256k1wallet.spec.ts b/packages/launchpad/src/secp256k1wallet.spec.ts index a16e8534..d2080321 100644 --- a/packages/launchpad/src/secp256k1wallet.spec.ts +++ b/packages/launchpad/src/secp256k1wallet.spec.ts @@ -1,6 +1,8 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto"; -import { fromBase64, fromHex, toAscii } from "@cosmjs/encoding"; +import { fromBase64, fromHex } from "@cosmjs/encoding"; +import { serializeSignDoc, StdSignDoc } from "./encoding"; import { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; import { base64Matcher } from "./testutils.spec"; import { executeKdf, KdfConfiguration } from "./wallet"; @@ -110,11 +112,18 @@ describe("Secp256k1Wallet", () => { describe("sign", () => { it("resolves to valid signature if enabled", async () => { const wallet = await Secp256k1Wallet.fromMnemonic(defaultMnemonic); - const message = toAscii("foo bar"); - const signature = await wallet.sign(defaultAddress, message); + const signDoc: StdSignDoc = { + msgs: [], + fee: { amount: [], gas: "23" }, + chain_id: "foochain", + memo: "hello, world", + account_number: "7", + sequence: "54", + }; + const signature = await wallet.sign(defaultAddress, signDoc); const valid = await Secp256k1.verifySignature( Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)), - new Sha256(message).digest(), + new Sha256(serializeSignDoc(signDoc)).digest(), defaultPubkey, ); expect(valid).toEqual(true); diff --git a/packages/launchpad/src/secp256k1wallet.ts b/packages/launchpad/src/secp256k1wallet.ts index e788250a..6ffab6fa 100644 --- a/packages/launchpad/src/secp256k1wallet.ts +++ b/packages/launchpad/src/secp256k1wallet.ts @@ -5,6 +5,7 @@ import { pathToString, Random, Secp256k1, + Sha256, Slip10, Slip10Curve, stringToPath, @@ -13,8 +14,9 @@ import { fromBase64, fromUtf8, toBase64, toUtf8 } from "@cosmjs/encoding"; import { assert, isNonNullObject } from "@cosmjs/utils"; import { rawSecp256k1PubkeyToAddress } from "./address"; +import { serializeSignDoc, StdSignDoc } from "./encoding"; import { encodeSecp256k1Signature } from "./signature"; -import { AccountData, OfflineSigner, PrehashType } from "./signer"; +import { AccountData, OfflineSigner } from "./signer"; import { StdSignature } from "./types"; import { decrypt, @@ -23,7 +25,6 @@ import { executeKdf, KdfConfiguration, makeCosmoshubPath, - prehash, supportedAlgorithms, } from "./wallet"; @@ -255,16 +256,12 @@ export class Secp256k1Wallet implements OfflineSigner { ]; } - public async sign( - address: string, - message: Uint8Array, - prehashType: PrehashType = "sha256", - ): Promise { - if (address !== this.address) { - throw new Error(`Address ${address} not found in wallet`); + public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { + if (signerAddress !== this.address) { + throw new Error(`Address ${signerAddress} not found in wallet`); } - const hashedMessage = prehash(message, prehashType); - const signature = await Secp256k1.createSignature(hashedMessage, this.privkey); + const message = new Sha256(serializeSignDoc(signDoc)).digest(); + const signature = await Secp256k1.createSignature(message, this.privkey); const signatureBytes = new Uint8Array([...signature.r(32), ...signature.s(32)]); return encodeSecp256k1Signature(this.pubkey, signatureBytes); } diff --git a/packages/launchpad/src/signer.ts b/packages/launchpad/src/signer.ts index 93e1ce59..1217d8f6 100644 --- a/packages/launchpad/src/signer.ts +++ b/packages/launchpad/src/signer.ts @@ -1,3 +1,4 @@ +import { StdSignDoc } from "./encoding"; import { StdSignature } from "./types"; export type PrehashType = "sha256" | "sha512" | null; @@ -19,6 +20,13 @@ export interface OfflineSigner { /** * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. + * + * @param signerAddress The address of the account that should sign the transaction + * @param signDoc The content that should be signed */ - readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; + readonly sign: ( + signerAddress: string, + signDoc: StdSignDoc, + prehashType?: PrehashType, + ) => Promise; } diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index 718e7e48..fa9ba345 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Coin } from "./coins"; import { Account, BroadcastTxResult, CosmosClient, GetSequenceResult } from "./cosmosclient"; -import { makeSignBytes } from "./encoding"; +import { makeStdSignDoc } from "./encoding"; import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg, MsgSend } from "./msgs"; @@ -88,8 +88,8 @@ export class SigningCosmosClient extends CosmosClient { public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signBytes = makeSignBytes(msgs, fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); + const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); + const signature = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, fee: fee, diff --git a/packages/launchpad/types/secp256k1wallet.d.ts b/packages/launchpad/types/secp256k1wallet.d.ts index feed1eef..aa241a86 100644 --- a/packages/launchpad/types/secp256k1wallet.d.ts +++ b/packages/launchpad/types/secp256k1wallet.d.ts @@ -1,5 +1,6 @@ import { HdPath } from "@cosmjs/crypto"; -import { AccountData, OfflineSigner, PrehashType } from "./signer"; +import { StdSignDoc } from "./encoding"; +import { AccountData, OfflineSigner } from "./signer"; import { StdSignature } from "./types"; import { EncryptionConfiguration, KdfConfiguration } from "./wallet"; /** @@ -86,7 +87,7 @@ export declare class Secp256k1Wallet implements OfflineSigner { get mnemonic(): string; private get address(); getAccounts(): Promise; - sign(address: string, message: Uint8Array, prehashType?: PrehashType): Promise; + sign(signerAddress: string, signDoc: StdSignDoc): Promise; /** * Generates an encrypted serialization of this wallet. * diff --git a/packages/launchpad/types/signer.d.ts b/packages/launchpad/types/signer.d.ts index d21ed77a..2b0948a4 100644 --- a/packages/launchpad/types/signer.d.ts +++ b/packages/launchpad/types/signer.d.ts @@ -1,3 +1,4 @@ +import { StdSignDoc } from "./encoding"; import { StdSignature } from "./types"; export declare type PrehashType = "sha256" | "sha512" | null; export declare type Algo = "secp256k1" | "ed25519" | "sr25519"; @@ -14,6 +15,13 @@ export interface OfflineSigner { readonly getAccounts: () => Promise; /** * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. + * + * @param signerAddress The address of the account that should sign the transaction + * @param signDoc The content that should be signed */ - readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise; + readonly sign: ( + signerAddress: string, + signDoc: StdSignDoc, + prehashType?: PrehashType, + ) => Promise; } From 5f2cf289eb59b64d4a40649c8dad5f7e5a6512fc Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 13:35:12 +0200 Subject: [PATCH 04/12] Remove PrehashType --- CHANGELOG.md | 3 +++ packages/launchpad/src/index.ts | 2 +- packages/launchpad/src/signer.ts | 8 +------- packages/launchpad/src/wallet.ts | 17 ----------------- packages/launchpad/types/index.d.ts | 2 +- packages/launchpad/types/signer.d.ts | 7 +------ packages/launchpad/types/wallet.d.ts | 2 -- 7 files changed, 7 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99187b7d..112dbb0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,9 @@ serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`. - @cosmjs/launchpad: Let `OfflineSigner.sign` take an `StdSignDoc` instead of an encoded message. +- @cosmjs/launchpad: Remove `PrehashType` and the prehash type argument in + `OfflineSigner.sign` because the signer now needs to know how to serialize an + `StdSignDoc`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 7cf967f8..9fd6d7d0 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -98,7 +98,7 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; -export { AccountData, Algo, PrehashType, OfflineSigner } from "./signer"; +export { AccountData, Algo, OfflineSigner } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; diff --git a/packages/launchpad/src/signer.ts b/packages/launchpad/src/signer.ts index 1217d8f6..e2eb4868 100644 --- a/packages/launchpad/src/signer.ts +++ b/packages/launchpad/src/signer.ts @@ -1,8 +1,6 @@ import { StdSignDoc } from "./encoding"; import { StdSignature } from "./types"; -export type PrehashType = "sha256" | "sha512" | null; - export type Algo = "secp256k1" | "ed25519" | "sr25519"; export interface AccountData { @@ -24,9 +22,5 @@ export interface OfflineSigner { * @param signerAddress The address of the account that should sign the transaction * @param signDoc The content that should be signed */ - readonly sign: ( - signerAddress: string, - signDoc: StdSignDoc, - prehashType?: PrehashType, - ) => Promise; + readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; } diff --git a/packages/launchpad/src/wallet.ts b/packages/launchpad/src/wallet.ts index 6f4f2b44..1c64e773 100644 --- a/packages/launchpad/src/wallet.ts +++ b/packages/launchpad/src/wallet.ts @@ -3,29 +3,12 @@ import { HdPath, isArgon2idOptions, Random, - Sha256, - Sha512, Slip10RawIndex, xchacha20NonceLength, Xchacha20poly1305Ietf, } from "@cosmjs/crypto"; import { toAscii } from "@cosmjs/encoding"; -import { PrehashType } from "./signer"; - -export function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array { - switch (type) { - case null: - return new Uint8Array([...bytes]); - case "sha256": - return new Sha256(bytes).digest(); - case "sha512": - return new Sha512(bytes).digest(); - default: - throw new Error("Unknown prehash type"); - } -} - /** * The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a` * with 0-based account index `a`. diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index 6d9b9ee8..de247a1e 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -96,7 +96,7 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; -export { AccountData, Algo, PrehashType, OfflineSigner } from "./signer"; +export { AccountData, Algo, OfflineSigner } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; diff --git a/packages/launchpad/types/signer.d.ts b/packages/launchpad/types/signer.d.ts index 2b0948a4..3a2e17e3 100644 --- a/packages/launchpad/types/signer.d.ts +++ b/packages/launchpad/types/signer.d.ts @@ -1,6 +1,5 @@ import { StdSignDoc } from "./encoding"; import { StdSignature } from "./types"; -export declare type PrehashType = "sha256" | "sha512" | null; export declare type Algo = "secp256k1" | "ed25519" | "sr25519"; export interface AccountData { /** A printable address (typically bech32 encoded) */ @@ -19,9 +18,5 @@ export interface OfflineSigner { * @param signerAddress The address of the account that should sign the transaction * @param signDoc The content that should be signed */ - readonly sign: ( - signerAddress: string, - signDoc: StdSignDoc, - prehashType?: PrehashType, - ) => Promise; + readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; } diff --git a/packages/launchpad/types/wallet.d.ts b/packages/launchpad/types/wallet.d.ts index f3e49071..6c433d32 100644 --- a/packages/launchpad/types/wallet.d.ts +++ b/packages/launchpad/types/wallet.d.ts @@ -1,6 +1,4 @@ import { HdPath } from "@cosmjs/crypto"; -import { PrehashType } from "./signer"; -export declare function prehash(bytes: Uint8Array, type: PrehashType): Uint8Array; /** * The Cosmoshub derivation path in the form `m/44'/118'/0'/0/a` * with 0-based account index `a`. From fbd8bbce9c1429b009176b79409f0fb59925a4a3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 14:17:22 +0200 Subject: [PATCH 05/12] Let OfflineSigner.sign return a SignResponse --- CHANGELOG.md | 3 +- .../src/cosmwasmclient.searchtx.spec.ts | 2 +- packages/cosmwasm/src/cosmwasmclient.spec.ts | 5 ++- packages/cosmwasm/src/lcdapi/wasm.spec.ts | 2 +- .../cosmwasm/src/signingcosmwasmclient.ts | 2 +- packages/launchpad-ledger/src/demo/node.ts | 3 +- packages/launchpad-ledger/src/ledgersigner.ts | 10 +++-- .../launchpad-ledger/types/ledgersigner.d.ts | 5 ++- .../src/cosmosclient.searchtx.spec.ts | 2 +- packages/launchpad/src/cosmosclient.spec.ts | 6 +-- packages/launchpad/src/index.ts | 2 +- .../launchpad/src/lcdapi/distribution.spec.ts | 2 +- packages/launchpad/src/lcdapi/gov.spec.ts | 4 +- .../launchpad/src/lcdapi/lcdclient.spec.ts | 38 +++++++++---------- packages/launchpad/src/lcdapi/staking.spec.ts | 4 +- .../launchpad/src/secp256k1wallet.spec.ts | 2 +- packages/launchpad/src/secp256k1wallet.ts | 10 +++-- packages/launchpad/src/signer.ts | 14 ++++++- packages/launchpad/src/signingcosmosclient.ts | 2 +- packages/launchpad/types/index.d.ts | 2 +- packages/launchpad/types/secp256k1wallet.d.ts | 5 +-- packages/launchpad/types/signer.d.ts | 13 ++++++- 22 files changed, 84 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 112dbb0e..65c13f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,8 @@ - @cosmjs/launchpad: Export `StdSignDoc` and create helpers to make and serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`. - @cosmjs/launchpad: Let `OfflineSigner.sign` take an `StdSignDoc` instead of an - encoded message. + encoded message and return a `SignResponse` that includes the document which + was signed. - @cosmjs/launchpad: Remove `PrehashType` and the prehash type argument in `OfflineSigner.sign` because the signer now needs to know how to serialize an `StdSignDoc`. diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index bf6ae681..66a7eb2c 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -104,7 +104,7 @@ describe("CosmWasmClient.searchTx", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(alice.address0, signDoc); + const { signature } = await wallet.sign(alice.address0, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", value: { diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index fcdf8e6d..5a464b19 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -7,6 +7,7 @@ import { MsgSend, Secp256k1Wallet, StdFee, + StdTx, } from "@cosmjs/launchpad"; import { assert, sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; @@ -237,8 +238,8 @@ describe("CosmWasmClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(alice.address0); const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(alice.address0, signDoc); - const signedTx = { + const { signature } = await wallet.sign(alice.address0, signDoc); + const signedTx: StdTx = { msg: [sendMsg], fee: fee, memo: memo, diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index 83790e1a..69f712cf 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -126,7 +126,7 @@ async function executeContract( const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value; const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const signature = await signer.sign(alice.address0, signDoc); + const { signature } = await signer.sign(alice.address0, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.broadcastTx(signedTx); } diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index 0b27a2c3..6b008d2d 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -361,7 +361,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signDoc); + const { signature } = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, fee: fee, diff --git a/packages/launchpad-ledger/src/demo/node.ts b/packages/launchpad-ledger/src/demo/node.ts index 6cd967e2..c4cff2a6 100644 --- a/packages/launchpad-ledger/src/demo/node.ts +++ b/packages/launchpad-ledger/src/demo/node.ts @@ -56,5 +56,6 @@ export async function sign( accountNumber, defaultSequence, ); - return signer.sign(fromAddress, signDoc); + const { signature } = await signer.sign(fromAddress, signDoc); + return signature; } diff --git a/packages/launchpad-ledger/src/ledgersigner.ts b/packages/launchpad-ledger/src/ledgersigner.ts index c09fc03b..0e00d132 100644 --- a/packages/launchpad-ledger/src/ledgersigner.ts +++ b/packages/launchpad-ledger/src/ledgersigner.ts @@ -4,10 +4,9 @@ import { encodeSecp256k1Signature, makeCosmoshubPath, OfflineSigner, - StdSignature, StdSignDoc, } from "@cosmjs/launchpad"; -import { serializeSignDoc } from "@cosmjs/launchpad"; +import { serializeSignDoc, SignResponse } from "@cosmjs/launchpad"; import { LaunchpadLedger, LaunchpadLedgerOptions } from "./launchpadledger"; @@ -36,7 +35,7 @@ export class LedgerSigner implements OfflineSigner { return this.accounts; } - public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { + public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { const accounts = this.accounts || (await this.getAccounts()); const accountIndex = accounts.findIndex((account) => account.address === signerAddress); @@ -48,6 +47,9 @@ export class LedgerSigner implements OfflineSigner { const accountForAddress = accounts[accountIndex]; const hdPath = this.hdPaths[accountIndex]; const signature = await this.ledger.sign(message, hdPath); - return encodeSecp256k1Signature(accountForAddress.pubkey, signature); + return { + signedDoc: signDoc, + signature: encodeSecp256k1Signature(accountForAddress.pubkey, signature), + }; } } diff --git a/packages/launchpad-ledger/types/ledgersigner.d.ts b/packages/launchpad-ledger/types/ledgersigner.d.ts index ffc9a609..6ddfee8b 100644 --- a/packages/launchpad-ledger/types/ledgersigner.d.ts +++ b/packages/launchpad-ledger/types/ledgersigner.d.ts @@ -1,4 +1,5 @@ -import { AccountData, OfflineSigner, StdSignature, StdSignDoc } from "@cosmjs/launchpad"; +import { AccountData, OfflineSigner, StdSignDoc } from "@cosmjs/launchpad"; +import { SignResponse } from "@cosmjs/launchpad"; import { LaunchpadLedgerOptions } from "./launchpadledger"; export declare class LedgerSigner implements OfflineSigner { private readonly ledger; @@ -6,5 +7,5 @@ export declare class LedgerSigner implements OfflineSigner { private accounts?; constructor(options?: LaunchpadLedgerOptions); getAccounts(): Promise; - sign(signerAddress: string, signDoc: StdSignDoc): Promise; + sign(signerAddress: string, signDoc: StdSignDoc): Promise; } diff --git a/packages/launchpad/src/cosmosclient.searchtx.spec.ts b/packages/launchpad/src/cosmosclient.searchtx.spec.ts index 8d247634..0a99909a 100644 --- a/packages/launchpad/src/cosmosclient.searchtx.spec.ts +++ b/packages/launchpad/src/cosmosclient.searchtx.spec.ts @@ -56,7 +56,7 @@ describe("CosmosClient.searchTx", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signDoc); + const { signature } = await wallet.sign(walletAddress, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", value: { diff --git a/packages/launchpad/src/cosmosclient.spec.ts b/packages/launchpad/src/cosmosclient.spec.ts index 47368a87..bf6571b6 100644 --- a/packages/launchpad/src/cosmosclient.spec.ts +++ b/packages/launchpad/src/cosmosclient.spec.ts @@ -16,7 +16,7 @@ import { unused, wasmd, } from "./testutils.spec"; -import { StdFee } from "./types"; +import { StdFee, StdTx } from "./types"; const blockTime = 1_000; // ms @@ -230,8 +230,8 @@ describe("CosmosClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(faucet.address); const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signDoc); - const signedTx = { + const { signature } = await wallet.sign(walletAddress, signDoc); + const signedTx: StdTx = { msg: [sendMsg], fee: fee, memo: memo, diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 9fd6d7d0..7220683d 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -98,7 +98,7 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; -export { AccountData, Algo, OfflineSigner } from "./signer"; +export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; diff --git a/packages/launchpad/src/lcdapi/distribution.spec.ts b/packages/launchpad/src/lcdapi/distribution.spec.ts index bc68176e..6e5f3647 100644 --- a/packages/launchpad/src/lcdapi/distribution.spec.ts +++ b/packages/launchpad/src/lcdapi/distribution.spec.ts @@ -46,7 +46,7 @@ describe("DistributionExtension", () => { const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signDoc); + const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, diff --git a/packages/launchpad/src/lcdapi/gov.spec.ts b/packages/launchpad/src/lcdapi/gov.spec.ts index 0af73b64..231253b7 100644 --- a/packages/launchpad/src/lcdapi/gov.spec.ts +++ b/packages/launchpad/src/lcdapi/gov.spec.ts @@ -58,7 +58,7 @@ describe("GovExtension", () => { proposalAccountNumber, proposalSequence, ); - const proposalSignature = await wallet.sign(faucet.address, proposalSignDoc); + const { signature: proposalSignature } = await wallet.sign(faucet.address, proposalSignDoc); const proposalTx = { msg: [proposalMsg], fee: defaultFee, @@ -90,7 +90,7 @@ describe("GovExtension", () => { voteAccountNumber, voteSequence, ); - const voteSignature = await wallet.sign(faucet.address, voteSignDoc); + const { signature: voteSignature } = await wallet.sign(faucet.address, voteSignDoc); const voteTx = { msg: [voteMsg], fee: defaultFee, diff --git a/packages/launchpad/src/lcdapi/lcdclient.spec.ts b/packages/launchpad/src/lcdapi/lcdclient.spec.ts index a1043d4a..f2147e25 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.spec.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.spec.ts @@ -20,7 +20,7 @@ import { wasmd, wasmdEnabled, } from "../testutils.spec"; -import { StdFee } from "../types"; +import { StdFee, StdTx } from "../types"; import { makeCosmoshubPath } from "../wallet"; import { setupAuthExtension } from "./auth"; import { TxsResponse } from "./base"; @@ -240,8 +240,8 @@ describe("LcdClient", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(walletAddress, signDoc); - const signedTx = { + const { signature } = await wallet.sign(walletAddress, signDoc); + const signedTx: StdTx = { msg: [sendMsg], fee: fee, memo: memo, @@ -538,7 +538,7 @@ describe("LcdClient", () => { const { account_number, sequence } = (await client.auth.account(faucet.address)).result.value; const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const signature = await wallet.sign(walletAddress, signDoc); + const { signature } = await wallet.sign(walletAddress, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); const result = await client.broadcastTx(signedTx); expect(result.code).toBeUndefined(); @@ -597,10 +597,10 @@ describe("LcdClient", () => { const signDoc1 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an1, sequence1); const signDoc2 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an2, sequence2); const signDoc3 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an3, sequence3); - const signature1 = await account1.sign(address1, signDoc1); - const signature2 = await account2.sign(address2, signDoc2); - const signature3 = await account3.sign(address3, signDoc3); - const signedTx = { + const { signature: signature1 } = await account1.sign(address1, signDoc1); + const { signature: signature2 } = await account2.sign(address2, signDoc2); + const { signature: signature3 } = await account3.sign(address3, signDoc3); + const signedTx: StdTx = { msg: [theMsg], fee: fee, memo: memo, @@ -659,8 +659,8 @@ describe("LcdClient", () => { const { account_number, sequence } = (await client.auth.account(walletAddress)).result.value; const signDoc = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); - const signature = await wallet.sign(walletAddress, signDoc); - const signedTx = { + const { signature } = await wallet.sign(walletAddress, signDoc); + const signedTx: StdTx = { msg: [msg1, msg2], fee: fee, memo: memo, @@ -724,9 +724,9 @@ describe("LcdClient", () => { const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signDoc1); - const signature2 = await account2.sign(address2, signDoc2); - const signedTx = { + const { signature: signature1 } = await account1.sign(address1, signDoc1); + const { signature: signature2 } = await account2.sign(address2, signDoc2); + const signedTx: StdTx = { msg: [msg2, msg1], fee: fee, memo: memo, @@ -795,9 +795,9 @@ describe("LcdClient", () => { const signDoc1 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1); const signDoc2 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signDoc1); - const signature2 = await account2.sign(address2, signDoc2); - const signedTx = { + const { signature: signature1 } = await account1.sign(address1, signDoc1); + const { signature: signature2 } = await account2.sign(address2, signDoc2); + const signedTx: StdTx = { msg: [msg1, msg2], fee: fee, memo: memo, @@ -861,9 +861,9 @@ describe("LcdClient", () => { const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); - const signature1 = await account1.sign(address1, signDoc1); - const signature2 = await account2.sign(address2, signDoc2); - const signedTx = { + const { signature: signature1 } = await account1.sign(address1, signDoc1); + const { signature: signature2 } = await account2.sign(address2, signDoc2); + const signedTx: StdTx = { msg: [msg2, msg1], fee: fee, memo: memo, diff --git a/packages/launchpad/src/lcdapi/staking.spec.ts b/packages/launchpad/src/lcdapi/staking.spec.ts index 5efcff6c..1f1809a9 100644 --- a/packages/launchpad/src/lcdapi/staking.spec.ts +++ b/packages/launchpad/src/lcdapi/staking.spec.ts @@ -47,7 +47,7 @@ describe("StakingExtension", () => { const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signDoc); + const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, @@ -70,7 +70,7 @@ describe("StakingExtension", () => { const memo = "Test undelegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const signature = await wallet.sign(faucet.address, signDoc); + const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], fee: defaultFee, diff --git a/packages/launchpad/src/secp256k1wallet.spec.ts b/packages/launchpad/src/secp256k1wallet.spec.ts index d2080321..87d6c7a9 100644 --- a/packages/launchpad/src/secp256k1wallet.spec.ts +++ b/packages/launchpad/src/secp256k1wallet.spec.ts @@ -120,7 +120,7 @@ describe("Secp256k1Wallet", () => { account_number: "7", sequence: "54", }; - const signature = await wallet.sign(defaultAddress, signDoc); + const { signature } = await wallet.sign(defaultAddress, signDoc); const valid = await Secp256k1.verifySignature( Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)), new Sha256(serializeSignDoc(signDoc)).digest(), diff --git a/packages/launchpad/src/secp256k1wallet.ts b/packages/launchpad/src/secp256k1wallet.ts index 6ffab6fa..dbba6b95 100644 --- a/packages/launchpad/src/secp256k1wallet.ts +++ b/packages/launchpad/src/secp256k1wallet.ts @@ -16,8 +16,7 @@ import { assert, isNonNullObject } from "@cosmjs/utils"; import { rawSecp256k1PubkeyToAddress } from "./address"; import { serializeSignDoc, StdSignDoc } from "./encoding"; import { encodeSecp256k1Signature } from "./signature"; -import { AccountData, OfflineSigner } from "./signer"; -import { StdSignature } from "./types"; +import { AccountData, OfflineSigner, SignResponse } from "./signer"; import { decrypt, encrypt, @@ -256,14 +255,17 @@ export class Secp256k1Wallet implements OfflineSigner { ]; } - public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { + public async sign(signerAddress: string, signDoc: StdSignDoc): Promise { if (signerAddress !== this.address) { throw new Error(`Address ${signerAddress} not found in wallet`); } const message = new Sha256(serializeSignDoc(signDoc)).digest(); const signature = await Secp256k1.createSignature(message, this.privkey); const signatureBytes = new Uint8Array([...signature.r(32), ...signature.s(32)]); - return encodeSecp256k1Signature(this.pubkey, signatureBytes); + return { + signedDoc: signDoc, + signature: encodeSecp256k1Signature(this.pubkey, signatureBytes), + }; } /** diff --git a/packages/launchpad/src/signer.ts b/packages/launchpad/src/signer.ts index e2eb4868..6eff4d13 100644 --- a/packages/launchpad/src/signer.ts +++ b/packages/launchpad/src/signer.ts @@ -10,6 +10,15 @@ export interface AccountData { readonly pubkey: Uint8Array; } +export interface SignResponse { + /** + * The sign doc that was signed. + * This may be different from the input signDoc when the signer modifies it as part of the signing process. + */ + readonly signedDoc: StdSignDoc; + readonly signature: StdSignature; +} + export interface OfflineSigner { /** * Get AccountData array from wallet. Rejects if not enabled. @@ -19,8 +28,11 @@ export interface OfflineSigner { /** * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. * + * The signer implementation may offer the user the ability to override parts of the signDoc. It must + * return the doc that was signed in the response. + * * @param signerAddress The address of the account that should sign the transaction * @param signDoc The content that should be signed */ - readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; + readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; } diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index fa9ba345..a8599fe5 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -89,7 +89,7 @@ export class SigningCosmosClient extends CosmosClient { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signDoc); + const { signature } = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, fee: fee, diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index de247a1e..a767b1ef 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -96,7 +96,7 @@ export { } from "./pubkey"; export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; -export { AccountData, Algo, OfflineSigner } from "./signer"; +export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; diff --git a/packages/launchpad/types/secp256k1wallet.d.ts b/packages/launchpad/types/secp256k1wallet.d.ts index aa241a86..29c7b63d 100644 --- a/packages/launchpad/types/secp256k1wallet.d.ts +++ b/packages/launchpad/types/secp256k1wallet.d.ts @@ -1,7 +1,6 @@ import { HdPath } from "@cosmjs/crypto"; import { StdSignDoc } from "./encoding"; -import { AccountData, OfflineSigner } from "./signer"; -import { StdSignature } from "./types"; +import { AccountData, OfflineSigner, SignResponse } from "./signer"; import { EncryptionConfiguration, KdfConfiguration } from "./wallet"; /** * This interface describes a JSON object holding the encrypted wallet and the meta data. @@ -87,7 +86,7 @@ export declare class Secp256k1Wallet implements OfflineSigner { get mnemonic(): string; private get address(); getAccounts(): Promise; - sign(signerAddress: string, signDoc: StdSignDoc): Promise; + sign(signerAddress: string, signDoc: StdSignDoc): Promise; /** * Generates an encrypted serialization of this wallet. * diff --git a/packages/launchpad/types/signer.d.ts b/packages/launchpad/types/signer.d.ts index 3a2e17e3..60d4aad9 100644 --- a/packages/launchpad/types/signer.d.ts +++ b/packages/launchpad/types/signer.d.ts @@ -7,6 +7,14 @@ export interface AccountData { readonly algo: Algo; readonly pubkey: Uint8Array; } +export interface SignResponse { + /** + * The sign doc that was signed. + * This may be different from the input signDoc when the signer modifies it as part of the signing process. + */ + readonly signedDoc: StdSignDoc; + readonly signature: StdSignature; +} export interface OfflineSigner { /** * Get AccountData array from wallet. Rejects if not enabled. @@ -15,8 +23,11 @@ export interface OfflineSigner { /** * Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled. * + * The signer implementation may offer the user the ability to override parts of the signDoc. It must + * return the doc that was signed in the response. + * * @param signerAddress The address of the account that should sign the transaction * @param signDoc The content that should be signed */ - readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; + readonly sign: (signerAddress: string, signDoc: StdSignDoc) => Promise; } From 4733769f1ade5c27c160a4cd1efe67001ad62b65 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 16:29:56 +0200 Subject: [PATCH 06/12] Rename field to SignResponse.signed --- packages/launchpad-ledger/src/ledgersigner.ts | 2 +- packages/launchpad/src/secp256k1wallet.ts | 2 +- packages/launchpad/src/signer.ts | 2 +- packages/launchpad/types/signer.d.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/launchpad-ledger/src/ledgersigner.ts b/packages/launchpad-ledger/src/ledgersigner.ts index 0e00d132..a7d55bfe 100644 --- a/packages/launchpad-ledger/src/ledgersigner.ts +++ b/packages/launchpad-ledger/src/ledgersigner.ts @@ -48,7 +48,7 @@ export class LedgerSigner implements OfflineSigner { const hdPath = this.hdPaths[accountIndex]; const signature = await this.ledger.sign(message, hdPath); return { - signedDoc: signDoc, + signed: signDoc, signature: encodeSecp256k1Signature(accountForAddress.pubkey, signature), }; } diff --git a/packages/launchpad/src/secp256k1wallet.ts b/packages/launchpad/src/secp256k1wallet.ts index dbba6b95..a515d3de 100644 --- a/packages/launchpad/src/secp256k1wallet.ts +++ b/packages/launchpad/src/secp256k1wallet.ts @@ -263,7 +263,7 @@ export class Secp256k1Wallet implements OfflineSigner { const signature = await Secp256k1.createSignature(message, this.privkey); const signatureBytes = new Uint8Array([...signature.r(32), ...signature.s(32)]); return { - signedDoc: signDoc, + signed: signDoc, signature: encodeSecp256k1Signature(this.pubkey, signatureBytes), }; } diff --git a/packages/launchpad/src/signer.ts b/packages/launchpad/src/signer.ts index 6eff4d13..f7218bb1 100644 --- a/packages/launchpad/src/signer.ts +++ b/packages/launchpad/src/signer.ts @@ -15,7 +15,7 @@ export interface SignResponse { * The sign doc that was signed. * This may be different from the input signDoc when the signer modifies it as part of the signing process. */ - readonly signedDoc: StdSignDoc; + readonly signed: StdSignDoc; readonly signature: StdSignature; } diff --git a/packages/launchpad/types/signer.d.ts b/packages/launchpad/types/signer.d.ts index 60d4aad9..e0e8d1a8 100644 --- a/packages/launchpad/types/signer.d.ts +++ b/packages/launchpad/types/signer.d.ts @@ -12,7 +12,7 @@ export interface SignResponse { * The sign doc that was signed. * This may be different from the input signDoc when the signer modifies it as part of the signing process. */ - readonly signedDoc: StdSignDoc; + readonly signed: StdSignDoc; readonly signature: StdSignature; } export interface OfflineSigner { From 751861e501057f29f753cce08ae31064fcab0896 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 16:37:07 +0200 Subject: [PATCH 07/12] Update CLI testing --- packages/cli/examples/delegate.ts | 4 ++-- packages/cli/src/cli.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/cli/examples/delegate.ts b/packages/cli/examples/delegate.ts index 51892dee..d4399628 100644 --- a/packages/cli/examples/delegate.ts +++ b/packages/cli/examples/delegate.ts @@ -27,8 +27,8 @@ console.log("Connected to chain:", chainId); const { accountNumber, sequence } = await client.getSequence(senderAddress); console.log("Account/sequence:", accountNumber, sequence); -const signBytes = makeSignBytes([msg], fee, chainId, memo, accountNumber, sequence); -const signature = await wallet.sign(senderAddress, signBytes); +const signDoc = makeStdSignDoc([msg], fee, chainId, memo, accountNumber, sequence); +const { signature } = await wallet.sign(senderAddress, signDoc); const signedTx: StdTx = { msg: [msg], fee: fee, diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index b338bce1..6db25cda 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -99,6 +99,7 @@ export async function main(originalArgs: readonly string[]): Promise { "logs", "makeCosmoshubPath", "makeSignBytes", + "makeStdSignDoc", "IndexedTx", "BroadcastTxResult", "Coin", @@ -115,6 +116,7 @@ export async function main(originalArgs: readonly string[]): Promise { "Secp256k1Wallet", "SigningCosmosClient", "StdFee", + "StdSignDoc", "StdTx", ], ], @@ -161,7 +163,13 @@ export async function main(originalArgs: readonly string[]): Promise { const wallet = await Secp256k1Wallet.fromMnemonic(mnemonic, makeCosmoshubPath(0)); const [{ address }] = await wallet.getAccounts(); const data = toAscii("foo bar"); - const signature = await wallet.sign(address, data); + const fee: StdFee = { + amount: coins(5000000, "ucosm"), + gas: "89000000", + }; + const signDoc = makeStdSignDoc([], fee, "chain-xyz", "hello, world", 1, 2); + const { signed, signature } = await wallet.sign(address, signDoc); + assert(signed.memo === "hello, world"); const bechPubkey = "coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq"; assert(encodeBech32Pubkey(decodeBech32Pubkey(bechPubkey), "coralvalconspub") == bechPubkey); From 14c285748ad859a620ff54b784b4f1258e651a08 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 16:52:57 +0200 Subject: [PATCH 08/12] Remove makeSignBytes --- CHANGELOG.md | 2 ++ packages/cli/README.md | 4 ++-- packages/cli/src/cli.ts | 1 - packages/launchpad/README.md | 6 +++--- packages/launchpad/src/encoding.ts | 12 ------------ packages/launchpad/src/index.ts | 2 +- packages/launchpad/src/sequence.ts | 11 +++-------- packages/launchpad/types/encoding.d.ts | 9 --------- packages/launchpad/types/index.d.ts | 2 +- 9 files changed, 12 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65c13f16..56c8ae11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,8 @@ - @cosmjs/launchpad: Remove `PrehashType` and the prehash type argument in `OfflineSigner.sign` because the signer now needs to know how to serialize an `StdSignDoc`. +- @cosmjs/launchpad: Remove `makeSignBytes` in favour of `makeStdSignDoc` and + `serializeSignDoc`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/cli/README.md b/packages/cli/README.md index 67fdef44..fd53192c 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -66,7 +66,7 @@ const sendTokensMsg: MsgSend = { }, }; -const signBytes = makeSignBytes( +const signDoc = makeStdSignDoc( [sendTokensMsg], defaultFee, defaultNetworkId, @@ -74,7 +74,7 @@ const signBytes = makeSignBytes( account_number, sequence, ); -const signature = await pen.sign(signBytes); +const { signature } = await wallet.sign(faucetAddress, signDoc); const signedTx: StdTx = { msg: [sendTokensMsg], fee: defaultFee, diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 6db25cda..d4319745 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -98,7 +98,6 @@ export async function main(originalArgs: readonly string[]): Promise { "encodeSecp256k1Signature", "logs", "makeCosmoshubPath", - "makeSignBytes", "makeStdSignDoc", "IndexedTx", "BroadcastTxResult", diff --git a/packages/launchpad/README.md b/packages/launchpad/README.md index 0985bb06..294c8075 100644 --- a/packages/launchpad/README.md +++ b/packages/launchpad/README.md @@ -173,7 +173,7 @@ import { MsgExecuteContract, setupWasmExtension } from "@cosmjs/cosmwasm"; import { assertIsPostTxSuccess, LcdClient, - makeSignBytes, + makeStdSignDoc, setupAuthExtension, StdFee, StdTx, @@ -205,7 +205,7 @@ const memo = "Time for action"; const { account_number, sequence } = ( await client.auth.account(myAddress) ).result.value; -const signBytes = makeSignBytes( +const signDoc = makeStdSignDoc( [msg], fee, apiUrl, @@ -213,7 +213,7 @@ const signBytes = makeSignBytes( account_number, sequence, ); -const signature = await signer.sign(myAddress, signBytes); +const { signature } = await signer.sign(myAddress, signDoc); const signedTx: StdTx = { msg: [msg], fee: fee, diff --git a/packages/launchpad/src/encoding.ts b/packages/launchpad/src/encoding.ts index 6f11b168..43ae5fd7 100644 --- a/packages/launchpad/src/encoding.ts +++ b/packages/launchpad/src/encoding.ts @@ -59,15 +59,3 @@ export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array { const sortedSignDoc = sortJson(signDoc); return toUtf8(JSON.stringify(sortedSignDoc)); } - -/** A convenience helper to create the StdSignDoc and serialize it */ -export function makeSignBytes( - msgs: readonly Msg[], - fee: StdFee, - chainId: string, - memo: string, - accountNumber: number | string, - sequence: number | string, -): Uint8Array { - return serializeSignDoc(makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence)); -} diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 7220683d..57ac29e5 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -28,7 +28,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeSignBytes, makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; +export { makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, diff --git a/packages/launchpad/src/sequence.ts b/packages/launchpad/src/sequence.ts index cc9a8a38..2b2050e4 100644 --- a/packages/launchpad/src/sequence.ts +++ b/packages/launchpad/src/sequence.ts @@ -1,6 +1,6 @@ import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto"; -import { makeSignBytes } from "./encoding"; +import { makeStdSignDoc, serializeSignDoc } from "./encoding"; import { decodeSignature } from "./signature"; import { CosmosSdkTx } from "./types"; @@ -30,13 +30,8 @@ export async function findSequenceForSignedTx( for (let s = min; s < upperBound; s++) { // console.log(`Trying sequence ${s}`); - const signBytes = makeSignBytes( - tx.value.msg, - tx.value.fee, - chainId, - tx.value.memo || "", - accountNumber, - s, + const signBytes = serializeSignDoc( + makeStdSignDoc(tx.value.msg, tx.value.fee, chainId, tx.value.memo || "", accountNumber, s), ); const prehashed = new Sha256(signBytes).digest(); const valid = await Secp256k1.verifySignature(secp256keSignature, prehashed, pubkey); diff --git a/packages/launchpad/types/encoding.d.ts b/packages/launchpad/types/encoding.d.ts index bb026862..0e672410 100644 --- a/packages/launchpad/types/encoding.d.ts +++ b/packages/launchpad/types/encoding.d.ts @@ -22,12 +22,3 @@ export declare function makeStdSignDoc( sequence: number | string, ): StdSignDoc; export declare function serializeSignDoc(signDoc: StdSignDoc): Uint8Array; -/** A convenience helper to create the StdSignDoc and serialize it */ -export declare function makeSignBytes( - msgs: readonly Msg[], - fee: StdFee, - chainId: string, - memo: string, - accountNumber: number | string, - sequence: number | string, -): Uint8Array; diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index a767b1ef..f80e9a78 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -26,7 +26,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeSignBytes, makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; +export { makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, From 1b0eec8ed32dcbf2d23291a6b3930ac073f637d4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Sep 2020 16:55:47 +0200 Subject: [PATCH 09/12] Simplify name to makeSignDoc --- CHANGELOG.md | 4 +-- packages/cli/README.md | 2 +- packages/cli/examples/delegate.ts | 2 +- packages/cli/src/cli.ts | 4 +-- .../src/cosmwasmclient.searchtx.spec.ts | 4 +-- packages/cosmwasm/src/cosmwasmclient.spec.ts | 4 +-- packages/cosmwasm/src/lcdapi/wasm.spec.ts | 4 +-- .../cosmwasm/src/signingcosmwasmclient.ts | 4 +-- packages/launchpad-ledger/src/demo/node.ts | 11 ++------ packages/launchpad/README.md | 4 +-- .../src/cosmosclient.searchtx.spec.ts | 4 +-- packages/launchpad/src/cosmosclient.spec.ts | 4 +-- packages/launchpad/src/encoding.ts | 2 +- packages/launchpad/src/index.ts | 2 +- .../launchpad/src/lcdapi/distribution.spec.ts | 4 +-- packages/launchpad/src/lcdapi/gov.spec.ts | 6 ++--- .../launchpad/src/lcdapi/lcdclient.spec.ts | 26 +++++++++---------- packages/launchpad/src/lcdapi/staking.spec.ts | 6 ++--- packages/launchpad/src/sequence.ts | 4 +-- packages/launchpad/src/signingcosmosclient.ts | 4 +-- packages/launchpad/types/encoding.d.ts | 2 +- packages/launchpad/types/index.d.ts | 2 +- 22 files changed, 51 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c8ae11..b2f952aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,14 +46,14 @@ - @cosmjs/launchpad: Change type of `TxsResponse.logs` and `BroadcastTxsResponse.logs` to `unknown[]`. - @cosmjs/launchpad: Export `StdSignDoc` and create helpers to make and - serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`. + serialize a `StdSignDoc`: `makeSignDoc` and `serializeSignDoc`. - @cosmjs/launchpad: Let `OfflineSigner.sign` take an `StdSignDoc` instead of an encoded message and return a `SignResponse` that includes the document which was signed. - @cosmjs/launchpad: Remove `PrehashType` and the prehash type argument in `OfflineSigner.sign` because the signer now needs to know how to serialize an `StdSignDoc`. -- @cosmjs/launchpad: Remove `makeSignBytes` in favour of `makeStdSignDoc` and +- @cosmjs/launchpad: Remove `makeSignBytes` in favour of `makeSignDoc` and `serializeSignDoc`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) diff --git a/packages/cli/README.md b/packages/cli/README.md index fd53192c..8c5fbdfb 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -66,7 +66,7 @@ const sendTokensMsg: MsgSend = { }, }; -const signDoc = makeStdSignDoc( +const signDoc = makeSignDoc( [sendTokensMsg], defaultFee, defaultNetworkId, diff --git a/packages/cli/examples/delegate.ts b/packages/cli/examples/delegate.ts index d4399628..199ed2b6 100644 --- a/packages/cli/examples/delegate.ts +++ b/packages/cli/examples/delegate.ts @@ -27,7 +27,7 @@ console.log("Connected to chain:", chainId); const { accountNumber, sequence } = await client.getSequence(senderAddress); console.log("Account/sequence:", accountNumber, sequence); -const signDoc = makeStdSignDoc([msg], fee, chainId, memo, accountNumber, sequence); +const signDoc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(senderAddress, signDoc); const signedTx: StdTx = { msg: [msg], diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index d4319745..32b0ac14 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -98,7 +98,7 @@ export async function main(originalArgs: readonly string[]): Promise { "encodeSecp256k1Signature", "logs", "makeCosmoshubPath", - "makeStdSignDoc", + "makeSignDoc", "IndexedTx", "BroadcastTxResult", "Coin", @@ -166,7 +166,7 @@ export async function main(originalArgs: readonly string[]): Promise { amount: coins(5000000, "ucosm"), gas: "89000000", }; - const signDoc = makeStdSignDoc([], fee, "chain-xyz", "hello, world", 1, 2); + const signDoc = makeSignDoc([], fee, "chain-xyz", "hello, world", 1, 2); const { signed, signature } = await wallet.sign(address, signDoc); assert(signed.memo === "hello, world"); diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index 66a7eb2c..83a9f3c4 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -6,7 +6,7 @@ import { isBroadcastTxFailure, isMsgSend, LcdClient, - makeStdSignDoc, + makeSignDoc, MsgSend, Secp256k1Wallet, } from "@cosmjs/launchpad"; @@ -103,7 +103,7 @@ describe("CosmWasmClient.searchTx", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(alice.address0, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index 5a464b19..c554a4ac 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -3,7 +3,7 @@ import { Sha256 } from "@cosmjs/crypto"; import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding"; import { assertIsBroadcastTxSuccess, - makeStdSignDoc, + makeSignDoc, MsgSend, Secp256k1Wallet, StdFee, @@ -237,7 +237,7 @@ describe("CosmWasmClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(alice.address0); - const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(alice.address0, signDoc); const signedTx: StdTx = { msg: [sendMsg], diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index 69f712cf..199d915a 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -10,7 +10,7 @@ import { coin, coins, LcdClient, - makeStdSignDoc, + makeSignDoc, OfflineSigner, Secp256k1Wallet, setupAuthExtension, @@ -125,7 +125,7 @@ async function executeContract( }; const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value; - const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); + const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); const { signature } = await signer.sign(alice.address0, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); return client.broadcastTx(signedTx); diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index 6b008d2d..07ff9fa8 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -11,7 +11,7 @@ import { GasLimits, GasPrice, isBroadcastTxFailure, - makeStdSignDoc, + makeSignDoc, Msg, MsgSend, OfflineSigner, @@ -360,7 +360,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); const { signature } = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, diff --git a/packages/launchpad-ledger/src/demo/node.ts b/packages/launchpad-ledger/src/demo/node.ts index c4cff2a6..f90e45e4 100644 --- a/packages/launchpad-ledger/src/demo/node.ts +++ b/packages/launchpad-ledger/src/demo/node.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { toBase64 } from "@cosmjs/encoding"; -import { makeCosmoshubPath, makeStdSignDoc, StdFee, StdSignature } from "@cosmjs/launchpad"; +import { makeCosmoshubPath, makeSignDoc, StdFee, StdSignature } from "@cosmjs/launchpad"; import { LedgerSigner } from "../ledgersigner"; @@ -48,14 +48,7 @@ export async function sign( }, }, ]; - const signDoc = makeStdSignDoc( - msgs, - defaultFee, - defaultChainId, - defaultMemo, - accountNumber, - defaultSequence, - ); + const signDoc = makeSignDoc(msgs, defaultFee, defaultChainId, defaultMemo, accountNumber, defaultSequence); const { signature } = await signer.sign(fromAddress, signDoc); return signature; } diff --git a/packages/launchpad/README.md b/packages/launchpad/README.md index 294c8075..0ef2b847 100644 --- a/packages/launchpad/README.md +++ b/packages/launchpad/README.md @@ -173,7 +173,7 @@ import { MsgExecuteContract, setupWasmExtension } from "@cosmjs/cosmwasm"; import { assertIsPostTxSuccess, LcdClient, - makeStdSignDoc, + makeSignDoc, setupAuthExtension, StdFee, StdTx, @@ -205,7 +205,7 @@ const memo = "Time for action"; const { account_number, sequence } = ( await client.auth.account(myAddress) ).result.value; -const signDoc = makeStdSignDoc( +const signDoc = makeSignDoc( [msg], fee, apiUrl, diff --git a/packages/launchpad/src/cosmosclient.searchtx.spec.ts b/packages/launchpad/src/cosmosclient.searchtx.spec.ts index 0a99909a..4a5f7a50 100644 --- a/packages/launchpad/src/cosmosclient.searchtx.spec.ts +++ b/packages/launchpad/src/cosmosclient.searchtx.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { coins } from "./coins"; import { CosmosClient, isBroadcastTxFailure } from "./cosmosclient"; -import { makeStdSignDoc } from "./encoding"; +import { makeSignDoc } from "./encoding"; import { LcdClient } from "./lcdapi"; import { isMsgSend, MsgSend } from "./msgs"; import { Secp256k1Wallet } from "./secp256k1wallet"; @@ -55,7 +55,7 @@ describe("CosmosClient.searchTx", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); const tx: CosmosSdkTx = { type: "cosmos-sdk/StdTx", diff --git a/packages/launchpad/src/cosmosclient.spec.ts b/packages/launchpad/src/cosmosclient.spec.ts index bf6571b6..cdfd95b2 100644 --- a/packages/launchpad/src/cosmosclient.spec.ts +++ b/packages/launchpad/src/cosmosclient.spec.ts @@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; import { assertIsBroadcastTxSuccess, CosmosClient, PrivateCosmosClient } from "./cosmosclient"; -import { makeStdSignDoc } from "./encoding"; +import { makeSignDoc } from "./encoding"; import { findAttribute } from "./logs"; import { MsgSend } from "./msgs"; import { Secp256k1Wallet } from "./secp256k1wallet"; @@ -229,7 +229,7 @@ describe("CosmosClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(faucet.address); - const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); const signedTx: StdTx = { msg: [sendMsg], diff --git a/packages/launchpad/src/encoding.ts b/packages/launchpad/src/encoding.ts index 43ae5fd7..970d69b1 100644 --- a/packages/launchpad/src/encoding.ts +++ b/packages/launchpad/src/encoding.ts @@ -37,7 +37,7 @@ export interface StdSignDoc { readonly memo: string; } -export function makeStdSignDoc( +export function makeSignDoc( msgs: readonly Msg[], fee: StdFee, chainId: string, diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 57ac29e5..83087701 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -28,7 +28,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; +export { makeSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, diff --git a/packages/launchpad/src/lcdapi/distribution.spec.ts b/packages/launchpad/src/lcdapi/distribution.spec.ts index 6e5f3647..df624284 100644 --- a/packages/launchpad/src/lcdapi/distribution.spec.ts +++ b/packages/launchpad/src/lcdapi/distribution.spec.ts @@ -4,7 +4,7 @@ import { sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeStdSignDoc } from "../encoding"; +import { makeSignDoc } from "../encoding"; import { MsgDelegate } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -45,7 +45,7 @@ describe("DistributionExtension", () => { }; const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], diff --git a/packages/launchpad/src/lcdapi/gov.spec.ts b/packages/launchpad/src/lcdapi/gov.spec.ts index 231253b7..5438915d 100644 --- a/packages/launchpad/src/lcdapi/gov.spec.ts +++ b/packages/launchpad/src/lcdapi/gov.spec.ts @@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils"; import { coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeStdSignDoc } from "../encoding"; +import { makeSignDoc } from "../encoding"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; import { @@ -50,7 +50,7 @@ describe("GovExtension", () => { }; const proposalMemo = "Test proposal for wasmd"; const { accountNumber: proposalAccountNumber, sequence: proposalSequence } = await client.getSequence(); - const proposalSignDoc = makeStdSignDoc( + const proposalSignDoc = makeSignDoc( [proposalMsg], defaultFee, chainId, @@ -82,7 +82,7 @@ describe("GovExtension", () => { }; const voteMemo = "Test vote for wasmd"; const { accountNumber: voteAccountNumber, sequence: voteSequence } = await client.getSequence(); - const voteSignDoc = makeStdSignDoc( + const voteSignDoc = makeSignDoc( [voteMsg], defaultFee, chainId, diff --git a/packages/launchpad/src/lcdapi/lcdclient.spec.ts b/packages/launchpad/src/lcdapi/lcdclient.spec.ts index f2147e25..1a837842 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.spec.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { Coin } from "../coins"; import { isBroadcastTxFailure } from "../cosmosclient"; -import { makeStdSignDoc } from "../encoding"; +import { makeSignDoc } from "../encoding"; import { parseLogs } from "../logs"; import { MsgSend } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; @@ -239,7 +239,7 @@ describe("LcdClient", () => { }; const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); - const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); const signedTx: StdTx = { msg: [sendMsg], @@ -537,7 +537,7 @@ describe("LcdClient", () => { const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension); const { account_number, sequence } = (await client.auth.account(faucet.address)).result.value; - const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); + const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); const signedTx = makeSignedTx(theMsg, fee, memo, signature); const result = await client.broadcastTx(signedTx); @@ -594,9 +594,9 @@ describe("LcdClient", () => { const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; const { account_number: an3, sequence: sequence3 } = (await client.auth.account(address3)).result.value; - const signDoc1 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an1, sequence1); - const signDoc2 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an2, sequence2); - const signDoc3 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an3, sequence3); + const signDoc1 = makeSignDoc([theMsg], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeSignDoc([theMsg], fee, wasmd.chainId, memo, an2, sequence2); + const signDoc3 = makeSignDoc([theMsg], fee, wasmd.chainId, memo, an3, sequence3); const { signature: signature1 } = await account1.sign(address1, signDoc1); const { signature: signature2 } = await account2.sign(address2, signDoc2); const { signature: signature3 } = await account3.sign(address3, signDoc3); @@ -658,7 +658,7 @@ describe("LcdClient", () => { const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension); const { account_number, sequence } = (await client.auth.account(walletAddress)).result.value; - const signDoc = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); + const signDoc = makeSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); const signedTx: StdTx = { msg: [msg1, msg2], @@ -722,8 +722,8 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); - const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); + const signDoc1 = makeSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); const { signature: signature1 } = await account1.sign(address1, signDoc1); const { signature: signature2 } = await account2.sign(address2, signDoc2); const signedTx: StdTx = { @@ -793,8 +793,8 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signDoc1 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1); - const signDoc2 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2); + const signDoc1 = makeSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2); const { signature: signature1 } = await account1.sign(address1, signDoc1); const { signature: signature2 } = await account2.sign(address2, signDoc2); const signedTx: StdTx = { @@ -859,8 +859,8 @@ describe("LcdClient", () => { const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value; const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value; - const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); - const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); + const signDoc1 = makeSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1); + const signDoc2 = makeSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2); const { signature: signature1 } = await account1.sign(address1, signDoc1); const { signature: signature2 } = await account2.sign(address2, signDoc2); const signedTx: StdTx = { diff --git a/packages/launchpad/src/lcdapi/staking.spec.ts b/packages/launchpad/src/lcdapi/staking.spec.ts index 1f1809a9..a188fa89 100644 --- a/packages/launchpad/src/lcdapi/staking.spec.ts +++ b/packages/launchpad/src/lcdapi/staking.spec.ts @@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; import { assertIsBroadcastTxSuccess } from "../cosmosclient"; -import { makeStdSignDoc } from "../encoding"; +import { makeSignDoc } from "../encoding"; import { MsgDelegate, MsgUndelegate } from "../msgs"; import { Secp256k1Wallet } from "../secp256k1wallet"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -46,7 +46,7 @@ describe("StakingExtension", () => { }; const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], @@ -69,7 +69,7 @@ describe("StakingExtension", () => { }; const memo = "Test undelegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); - const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(faucet.address, signDoc); const tx = { msg: [msg], diff --git a/packages/launchpad/src/sequence.ts b/packages/launchpad/src/sequence.ts index 2b2050e4..74091372 100644 --- a/packages/launchpad/src/sequence.ts +++ b/packages/launchpad/src/sequence.ts @@ -1,6 +1,6 @@ import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto"; -import { makeStdSignDoc, serializeSignDoc } from "./encoding"; +import { makeSignDoc, serializeSignDoc } from "./encoding"; import { decodeSignature } from "./signature"; import { CosmosSdkTx } from "./types"; @@ -31,7 +31,7 @@ export async function findSequenceForSignedTx( for (let s = min; s < upperBound; s++) { // console.log(`Trying sequence ${s}`); const signBytes = serializeSignDoc( - makeStdSignDoc(tx.value.msg, tx.value.fee, chainId, tx.value.memo || "", accountNumber, s), + makeSignDoc(tx.value.msg, tx.value.fee, chainId, tx.value.memo || "", accountNumber, s), ); const prehashed = new Sha256(signBytes).digest(); const valid = await Secp256k1.verifySignature(secp256keSignature, prehashed, pubkey); diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index a8599fe5..d1e0a8b5 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Coin } from "./coins"; import { Account, BroadcastTxResult, CosmosClient, GetSequenceResult } from "./cosmosclient"; -import { makeStdSignDoc } from "./encoding"; +import { makeSignDoc } from "./encoding"; import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg, MsgSend } from "./msgs"; @@ -88,7 +88,7 @@ export class SigningCosmosClient extends CosmosClient { public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); + const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); const { signature } = await this.signer.sign(this.senderAddress, signDoc); const signedTx: StdTx = { msg: msgs, diff --git a/packages/launchpad/types/encoding.d.ts b/packages/launchpad/types/encoding.d.ts index 0e672410..05f8d8ce 100644 --- a/packages/launchpad/types/encoding.d.ts +++ b/packages/launchpad/types/encoding.d.ts @@ -13,7 +13,7 @@ export interface StdSignDoc { readonly msgs: readonly Msg[]; readonly memo: string; } -export declare function makeStdSignDoc( +export declare function makeSignDoc( msgs: readonly Msg[], fee: StdFee, chainId: string, diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index f80e9a78..c2205839 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -26,7 +26,7 @@ export { isSearchBySentFromOrToQuery, isSearchByTagsQuery, } from "./cosmosclient"; -export { makeStdSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; +export { makeSignDoc, serializeSignDoc, StdSignDoc } from "./encoding"; export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; export { AuthAccountsResponse, From 0f626a23200f04f874b39c205501a43e2720719a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 24 Sep 2020 11:37:15 +0200 Subject: [PATCH 10/12] Cleanup StdTx --- CHANGELOG.md | 3 ++ .../src/cosmwasmclient.searchtx.spec.ts | 8 ++-- packages/cosmwasm/src/cosmwasmclient.spec.ts | 2 + packages/cosmwasm/src/cosmwasmclient.ts | 4 +- packages/cosmwasm/types/cosmwasmclient.d.ts | 4 +- .../src/cosmosclient.searchtx.spec.ts | 6 +-- packages/launchpad/src/cosmosclient.spec.ts | 6 ++- packages/launchpad/src/cosmosclient.ts | 7 +-- packages/launchpad/src/index.ts | 3 +- packages/launchpad/src/lcdapi/base.ts | 4 +- .../launchpad/src/lcdapi/lcdclient.spec.ts | 4 +- packages/launchpad/src/lcdapi/lcdclient.ts | 4 +- packages/launchpad/src/sequence.spec.ts | 11 +++++ packages/launchpad/src/sequence.ts | 4 +- packages/launchpad/src/signingcosmosclient.ts | 3 +- packages/launchpad/src/testutils.spec.ts | 3 +- packages/launchpad/src/tx.ts | 44 +++++++++++++++++++ packages/launchpad/src/types.ts | 25 ----------- packages/launchpad/types/cosmosclient.d.ts | 7 +-- packages/launchpad/types/index.d.ts | 3 +- packages/launchpad/types/lcdapi/base.d.ts | 4 +- .../launchpad/types/lcdapi/lcdclient.d.ts | 4 +- packages/launchpad/types/sequence.d.ts | 4 +- packages/launchpad/types/tx.d.ts | 31 +++++++++++++ packages/launchpad/types/types.d.ts | 17 ------- 25 files changed, 137 insertions(+), 78 deletions(-) create mode 100644 packages/launchpad/src/tx.ts create mode 100644 packages/launchpad/types/tx.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b2f952aa..39c01ae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,9 @@ `StdSignDoc`. - @cosmjs/launchpad: Remove `makeSignBytes` in favour of `makeSignDoc` and `serializeSignDoc`. +- @cosmjs/launchpad: Create `WrappedTx`, `WrappedStdTx` and `isWrappedStdTx` to + better represent the Amino tx interface. Deprecate `CosmosSdkTx`, which is an + alias for `WrappedStdTx`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index 83a9f3c4..db6af67a 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -2,13 +2,13 @@ import { Coin, coins, - CosmosSdkTx, isBroadcastTxFailure, isMsgSend, LcdClient, makeSignDoc, MsgSend, Secp256k1Wallet, + WrappedStdTx, } from "@cosmjs/launchpad"; import { assert, sleep } from "@cosmjs/utils"; @@ -30,7 +30,7 @@ interface TestTxSend { readonly recipient: string; readonly hash: string; readonly height: number; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; } interface TestTxExecute { @@ -38,7 +38,7 @@ interface TestTxExecute { readonly contract: string; readonly hash: string; readonly height: number; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; } describe("CosmWasmClient.searchTx", () => { @@ -105,7 +105,7 @@ describe("CosmWasmClient.searchTx", () => { const chainId = await client.getChainId(); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(alice.address0, signDoc); - const tx: CosmosSdkTx = { + const tx: WrappedStdTx = { type: "cosmos-sdk/StdTx", value: { msg: [sendMsg], diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index c554a4ac..ec0f895b 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -3,6 +3,7 @@ import { Sha256 } from "@cosmjs/crypto"; import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding"; import { assertIsBroadcastTxSuccess, + isWrappedStdTx, makeSignDoc, MsgSend, Secp256k1Wallet, @@ -200,6 +201,7 @@ describe("CosmWasmClient", () => { it("works", async () => { pendingWithoutWasmd(); const client = new CosmWasmClient(wasmd.endpoint); + assert(isWrappedStdTx(cosmoshub.tx)); expect(await client.getIdentifier(cosmoshub.tx)).toEqual(cosmoshub.id); }); }); diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index 4541ed86..f2b26ab0 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -5,7 +5,6 @@ import { BroadcastMode, BroadcastTxResult, Coin, - CosmosSdkTx, IndexedTx, LcdClient, normalizePubkey, @@ -13,6 +12,7 @@ import { setupAuthExtension, StdTx, uint64ToNumber, + WrappedStdTx, } from "@cosmjs/launchpad"; import { Uint53 } from "@cosmjs/math"; @@ -199,7 +199,7 @@ export class CosmWasmClient { /** * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) */ - public async getIdentifier(tx: CosmosSdkTx): Promise { + public async getIdentifier(tx: WrappedStdTx): Promise { // We consult the REST API because we don't have a local amino encoder const response = await this.lcdClient.encodeTx(tx); const hash = new Sha256(fromBase64(response.tx)).digest(); diff --git a/packages/cosmwasm/types/cosmwasmclient.d.ts b/packages/cosmwasm/types/cosmwasmclient.d.ts index ca145907..bd4f4cb5 100644 --- a/packages/cosmwasm/types/cosmwasmclient.d.ts +++ b/packages/cosmwasm/types/cosmwasmclient.d.ts @@ -3,11 +3,11 @@ import { BroadcastMode, BroadcastTxResult, Coin, - CosmosSdkTx, IndexedTx, LcdClient, PubKey, StdTx, + WrappedStdTx, } from "@cosmjs/launchpad"; import { WasmExtension } from "./lcdapi/wasm"; import { JsonObject } from "./types"; @@ -132,7 +132,7 @@ export declare class CosmWasmClient { /** * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) */ - getIdentifier(tx: CosmosSdkTx): Promise; + getIdentifier(tx: WrappedStdTx): Promise; /** * Returns account number and sequence. * diff --git a/packages/launchpad/src/cosmosclient.searchtx.spec.ts b/packages/launchpad/src/cosmosclient.searchtx.spec.ts index 4a5f7a50..e6f06067 100644 --- a/packages/launchpad/src/cosmosclient.searchtx.spec.ts +++ b/packages/launchpad/src/cosmosclient.searchtx.spec.ts @@ -16,14 +16,14 @@ import { wasmd, wasmdEnabled, } from "./testutils.spec"; -import { CosmosSdkTx } from "./types"; +import { WrappedStdTx } from "./tx"; interface TestTxSend { readonly sender: string; readonly recipient: string; readonly hash: string; readonly height: number; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; } describe("CosmosClient.searchTx", () => { @@ -57,7 +57,7 @@ describe("CosmosClient.searchTx", () => { const chainId = await client.getChainId(); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); const { signature } = await wallet.sign(walletAddress, signDoc); - const tx: CosmosSdkTx = { + const tx: WrappedStdTx = { type: "cosmos-sdk/StdTx", value: { msg: [sendMsg], diff --git a/packages/launchpad/src/cosmosclient.spec.ts b/packages/launchpad/src/cosmosclient.spec.ts index cdfd95b2..4cf1deba 100644 --- a/packages/launchpad/src/cosmosclient.spec.ts +++ b/packages/launchpad/src/cosmosclient.spec.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { sleep } from "@cosmjs/utils"; +import { assert, sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; import { assertIsBroadcastTxSuccess, CosmosClient, PrivateCosmosClient } from "./cosmosclient"; @@ -16,7 +16,8 @@ import { unused, wasmd, } from "./testutils.spec"; -import { StdFee, StdTx } from "./types"; +import { isWrappedStdTx, StdTx } from "./tx"; +import { StdFee } from "./types"; const blockTime = 1_000; // ms @@ -190,6 +191,7 @@ describe("CosmosClient", () => { it("works", async () => { pendingWithoutWasmd(); const client = new CosmosClient(wasmd.endpoint); + assert(isWrappedStdTx(cosmoshub.tx)); expect(await client.getIdentifier(cosmoshub.tx)).toEqual(cosmoshub.id); }); }); diff --git a/packages/launchpad/src/cosmosclient.ts b/packages/launchpad/src/cosmosclient.ts index 9bb0d2ca..c59ec73f 100644 --- a/packages/launchpad/src/cosmosclient.ts +++ b/packages/launchpad/src/cosmosclient.ts @@ -12,7 +12,8 @@ import { uint64ToNumber, } from "./lcdapi"; import { Log, parseLogs } from "./logs"; -import { CosmosSdkTx, PubKey, StdTx } from "./types"; +import { StdTx, WrappedStdTx } from "./tx"; +import { PubKey } from "./types"; export interface GetSequenceResult { readonly accountNumber: number; @@ -121,7 +122,7 @@ export interface IndexedTx { readonly code: number; readonly rawLog: string; readonly logs: readonly Log[]; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; /** The gas limit as set by the user */ readonly gasWanted?: number; /** The gas used by the execution */ @@ -203,7 +204,7 @@ export class CosmosClient { /** * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) */ - public async getIdentifier(tx: CosmosSdkTx): Promise { + public async getIdentifier(tx: WrappedStdTx): Promise { // We consult the REST API because we don't have a local amino encoder const response = await this.lcdClient.encodeTx(tx); const hash = new Sha256(fromBase64(response.tx)).digest(); diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index 83087701..ed8aa4ad 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -100,6 +100,7 @@ export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; -export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; +export { isStdTx, isWrappedStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; +export { pubkeyType, PubKey, StdFee, StdSignature } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/src/lcdapi/base.ts b/packages/launchpad/src/lcdapi/base.ts index 85465454..442eda3f 100644 --- a/packages/launchpad/src/lcdapi/base.ts +++ b/packages/launchpad/src/lcdapi/base.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { CosmosSdkTx } from "../types"; +import { WrappedStdTx } from "../tx"; /** * The mode used to send transaction @@ -109,7 +109,7 @@ export interface TxsResponse { readonly code?: number; readonly raw_log: string; readonly logs?: unknown[]; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; /** The gas limit as set by the user */ readonly gas_wanted?: string; /** The gas used by the execution */ diff --git a/packages/launchpad/src/lcdapi/lcdclient.spec.ts b/packages/launchpad/src/lcdapi/lcdclient.spec.ts index 1a837842..b971823b 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.spec.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.spec.ts @@ -20,7 +20,8 @@ import { wasmd, wasmdEnabled, } from "../testutils.spec"; -import { StdFee, StdTx } from "../types"; +import { isWrappedStdTx, StdTx } from "../tx"; +import { StdFee } from "../types"; import { makeCosmoshubPath } from "../wallet"; import { setupAuthExtension } from "./auth"; import { TxsResponse } from "./base"; @@ -493,6 +494,7 @@ describe("LcdClient", () => { it("works for cosmoshub example", async () => { pendingWithoutWasmd(); const client = new LcdClient(wasmd.endpoint); + assert(isWrappedStdTx(cosmoshub.tx)); const response = await client.encodeTx(cosmoshub.tx); expect(response).toEqual( jasmine.objectContaining({ diff --git a/packages/launchpad/src/lcdapi/lcdclient.ts b/packages/launchpad/src/lcdapi/lcdclient.ts index 25bcb64a..02afc4cc 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.ts @@ -2,7 +2,7 @@ import { assert, isNonNullObject } from "@cosmjs/utils"; import axios, { AxiosError, AxiosInstance } from "axios"; -import { CosmosSdkTx, StdTx } from "../types"; +import { StdTx, WrappedStdTx } from "../tx"; import { BlockResponse, BroadcastMode, @@ -284,7 +284,7 @@ export class LcdClient { } /** returns the amino-encoding of the transaction performed by the server */ - public async encodeTx(tx: CosmosSdkTx): Promise { + public async encodeTx(tx: WrappedStdTx): Promise { const responseData = await this.post("/txs/encode", tx); if (!responseData.tx) { throw new Error("Unexpected response data format"); diff --git a/packages/launchpad/src/sequence.spec.ts b/packages/launchpad/src/sequence.spec.ts index e5d8f4cd..24c8006a 100644 --- a/packages/launchpad/src/sequence.spec.ts +++ b/packages/launchpad/src/sequence.spec.ts @@ -1,7 +1,10 @@ +import { assert } from "@cosmjs/utils"; + import { findSequenceForSignedTx } from "./sequence"; import response1 from "./testdata/txresponse1.json"; import response2 from "./testdata/txresponse2.json"; import response3 from "./testdata/txresponse3.json"; +import { isWrappedStdTx } from "./tx"; // Those values must match ./testdata/txresponse*.json const chainId = "testing"; @@ -10,6 +13,10 @@ const accountNumber = 4; describe("sequence", () => { describe("findSequenceForSignedTx", () => { it("works", async () => { + assert(isWrappedStdTx(response1.tx)); + assert(isWrappedStdTx(response2.tx)); + assert(isWrappedStdTx(response3.tx)); + const current = 100; // what we get from GET /auth/accounts/{address} expect(await findSequenceForSignedTx(response1.tx, chainId, accountNumber, current)).toEqual(10); // We know response3.height > response1.height, so the sequence must be at least 10+1 @@ -19,6 +26,10 @@ describe("sequence", () => { }); it("returns undefined when sequence is not in range", async () => { + assert(isWrappedStdTx(response1.tx)); + assert(isWrappedStdTx(response2.tx)); + assert(isWrappedStdTx(response3.tx)); + expect(await findSequenceForSignedTx(response1.tx, chainId, accountNumber, 5)).toBeUndefined(); expect(await findSequenceForSignedTx(response1.tx, chainId, accountNumber, 20, 11)).toBeUndefined(); expect(await findSequenceForSignedTx(response1.tx, chainId, accountNumber, 20, 50)).toBeUndefined(); diff --git a/packages/launchpad/src/sequence.ts b/packages/launchpad/src/sequence.ts index 74091372..a11c1eb2 100644 --- a/packages/launchpad/src/sequence.ts +++ b/packages/launchpad/src/sequence.ts @@ -2,7 +2,7 @@ import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto"; import { makeSignDoc, serializeSignDoc } from "./encoding"; import { decodeSignature } from "./signature"; -import { CosmosSdkTx } from "./types"; +import { WrappedStdTx } from "./tx"; /** * Serach for sequence s with `min` <= `s` < `upperBound` to find the sequence that was used to sign the transaction @@ -16,7 +16,7 @@ import { CosmosSdkTx } from "./types"; * @returns the sequence if a match was found and undefined otherwise */ export async function findSequenceForSignedTx( - tx: CosmosSdkTx, + tx: WrappedStdTx, chainId: string, accountNumber: number, upperBound: number, diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index d1e0a8b5..0c1edd5c 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -6,7 +6,8 @@ import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg, MsgSend } from "./msgs"; import { OfflineSigner } from "./signer"; -import { StdFee, StdTx } from "./types"; +import { StdTx } from "./tx"; +import { StdFee } from "./types"; /** * These fees are used by the higher level methods of SigningCosmosClient diff --git a/packages/launchpad/src/testutils.spec.ts b/packages/launchpad/src/testutils.spec.ts index 2093b56e..335880b1 100644 --- a/packages/launchpad/src/testutils.spec.ts +++ b/packages/launchpad/src/testutils.spec.ts @@ -2,7 +2,8 @@ import { Random } from "@cosmjs/crypto"; import { Bech32 } from "@cosmjs/encoding"; import { Msg } from "./msgs"; -import { StdFee, StdSignature, StdTx } from "./types"; +import { StdTx } from "./tx"; +import { StdFee, StdSignature } from "./types"; export function makeRandomAddress(): string { return Bech32.encode("cosmos", Random.getBytes(20)); diff --git a/packages/launchpad/src/tx.ts b/packages/launchpad/src/tx.ts new file mode 100644 index 00000000..53c0198c --- /dev/null +++ b/packages/launchpad/src/tx.ts @@ -0,0 +1,44 @@ +import { Msg } from "./msgs"; +import { StdFee, StdSignature } from "./types"; + +/** + * A Cosmos SDK StdTx + * + * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdtx + */ +export interface StdTx { + readonly msg: readonly Msg[]; + readonly fee: StdFee; + readonly signatures: readonly StdSignature[]; + readonly memo: string | undefined; +} + +export function isStdTx(txValue: unknown): txValue is StdTx { + const { memo, msg, fee, signatures } = txValue as StdTx; + return ( + typeof memo === "string" && Array.isArray(msg) && typeof fee === "object" && Array.isArray(signatures) + ); +} + +/** + * An Amino JSON wrapper around the Tx interface + */ +export interface WrappedTx { + readonly type: string; + readonly value: any; +} + +/** + * An Amino JSON wrapper around StdTx + */ +export interface WrappedStdTx extends WrappedTx { + readonly type: "cosmos-sdk/StdTx"; + readonly value: StdTx; +} + +export function isWrappedStdTx(wrapped: WrappedTx): wrapped is WrappedStdTx { + return (wrapped as WrappedStdTx).type === "cosmos-sdk/StdTx" && isStdTx(wrapped.value); +} + +/** @deprecated use WrappedStdTx */ +export type CosmosSdkTx = WrappedStdTx; diff --git a/packages/launchpad/src/types.ts b/packages/launchpad/src/types.ts index dc799014..01126078 100644 --- a/packages/launchpad/src/types.ts +++ b/packages/launchpad/src/types.ts @@ -1,30 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Coin } from "./coins"; -import { Msg } from "./msgs"; - -/** - * A Cosmos SDK StdTx - * - * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdtx - */ -export interface StdTx { - readonly msg: readonly Msg[]; - readonly fee: StdFee; - readonly signatures: readonly StdSignature[]; - readonly memo: string | undefined; -} - -export function isStdTx(txValue: unknown): txValue is StdTx { - const { memo, msg, fee, signatures } = txValue as StdTx; - return ( - typeof memo === "string" && Array.isArray(msg) && typeof fee === "object" && Array.isArray(signatures) - ); -} - -export interface CosmosSdkTx { - readonly type: string; - readonly value: StdTx; -} export interface StdFee { readonly amount: readonly Coin[]; diff --git a/packages/launchpad/types/cosmosclient.d.ts b/packages/launchpad/types/cosmosclient.d.ts index dcdda89d..12bb6f2d 100644 --- a/packages/launchpad/types/cosmosclient.d.ts +++ b/packages/launchpad/types/cosmosclient.d.ts @@ -1,7 +1,8 @@ import { Coin } from "./coins"; import { AuthExtension, BroadcastMode, LcdClient } from "./lcdapi"; import { Log } from "./logs"; -import { CosmosSdkTx, PubKey, StdTx } from "./types"; +import { StdTx, WrappedStdTx } from "./tx"; +import { PubKey } from "./types"; export interface GetSequenceResult { readonly accountNumber: number; readonly sequence: number; @@ -78,7 +79,7 @@ export interface IndexedTx { readonly code: number; readonly rawLog: string; readonly logs: readonly Log[]; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; /** The gas limit as set by the user */ readonly gasWanted?: number; /** The gas used by the execution */ @@ -127,7 +128,7 @@ export declare class CosmosClient { /** * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) */ - getIdentifier(tx: CosmosSdkTx): Promise; + getIdentifier(tx: WrappedStdTx): Promise; /** * Returns account number and sequence. * diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index c2205839..4a87457a 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -98,6 +98,7 @@ export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; -export { isStdTx, pubkeyType, CosmosSdkTx, PubKey, StdFee, StdSignature, StdTx } from "./types"; +export { isStdTx, isWrappedStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; +export { pubkeyType, PubKey, StdFee, StdSignature } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/types/lcdapi/base.d.ts b/packages/launchpad/types/lcdapi/base.d.ts index c8f58d7c..f35cfcd0 100644 --- a/packages/launchpad/types/lcdapi/base.d.ts +++ b/packages/launchpad/types/lcdapi/base.d.ts @@ -1,4 +1,4 @@ -import { CosmosSdkTx } from "../types"; +import { WrappedStdTx } from "../tx"; /** * The mode used to send transaction * @@ -93,7 +93,7 @@ export interface TxsResponse { readonly code?: number; readonly raw_log: string; readonly logs?: unknown[]; - readonly tx: CosmosSdkTx; + readonly tx: WrappedStdTx; /** The gas limit as set by the user */ readonly gas_wanted?: string; /** The gas used by the execution */ diff --git a/packages/launchpad/types/lcdapi/lcdclient.d.ts b/packages/launchpad/types/lcdapi/lcdclient.d.ts index b5cfd8ba..56682379 100644 --- a/packages/launchpad/types/lcdapi/lcdclient.d.ts +++ b/packages/launchpad/types/lcdapi/lcdclient.d.ts @@ -1,4 +1,4 @@ -import { CosmosSdkTx, StdTx } from "../types"; +import { StdTx, WrappedStdTx } from "../tx"; import { BlockResponse, BroadcastMode, @@ -151,7 +151,7 @@ export declare class LcdClient { txById(id: string): Promise; txsQuery(query: string): Promise; /** returns the amino-encoding of the transaction performed by the server */ - encodeTx(tx: CosmosSdkTx): Promise; + encodeTx(tx: WrappedStdTx): Promise; /** * Broadcasts a signed transaction to the transaction pool. * Depending on the client's broadcast mode, this might or might diff --git a/packages/launchpad/types/sequence.d.ts b/packages/launchpad/types/sequence.d.ts index 70d38469..3bd3430d 100644 --- a/packages/launchpad/types/sequence.d.ts +++ b/packages/launchpad/types/sequence.d.ts @@ -1,4 +1,4 @@ -import { CosmosSdkTx } from "./types"; +import { WrappedStdTx } from "./tx"; /** * Serach for sequence s with `min` <= `s` < `upperBound` to find the sequence that was used to sign the transaction * @@ -11,7 +11,7 @@ import { CosmosSdkTx } from "./types"; * @returns the sequence if a match was found and undefined otherwise */ export declare function findSequenceForSignedTx( - tx: CosmosSdkTx, + tx: WrappedStdTx, chainId: string, accountNumber: number, upperBound: number, diff --git a/packages/launchpad/types/tx.d.ts b/packages/launchpad/types/tx.d.ts new file mode 100644 index 00000000..8bf6134e --- /dev/null +++ b/packages/launchpad/types/tx.d.ts @@ -0,0 +1,31 @@ +import { Msg } from "./msgs"; +import { StdFee, StdSignature } from "./types"; +/** + * A Cosmos SDK StdTx + * + * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdtx + */ +export interface StdTx { + readonly msg: readonly Msg[]; + readonly fee: StdFee; + readonly signatures: readonly StdSignature[]; + readonly memo: string | undefined; +} +export declare function isStdTx(txValue: unknown): txValue is StdTx; +/** + * An Amino JSON wrapper around the Tx interface + */ +export interface WrappedTx { + readonly type: string; + readonly value: any; +} +/** + * An Amino JSON wrapper around StdTx + */ +export interface WrappedStdTx extends WrappedTx { + readonly type: "cosmos-sdk/StdTx"; + readonly value: StdTx; +} +export declare function isWrappedStdTx(wrapped: WrappedTx): wrapped is WrappedStdTx; +/** @deprecated use WrappedStdTx */ +export declare type CosmosSdkTx = WrappedStdTx; diff --git a/packages/launchpad/types/types.d.ts b/packages/launchpad/types/types.d.ts index 1a513b41..9c22056a 100644 --- a/packages/launchpad/types/types.d.ts +++ b/packages/launchpad/types/types.d.ts @@ -1,21 +1,4 @@ import { Coin } from "./coins"; -import { Msg } from "./msgs"; -/** - * A Cosmos SDK StdTx - * - * @see https://docs.cosmos.network/master/modules/auth/03_types.html#stdtx - */ -export interface StdTx { - readonly msg: readonly Msg[]; - readonly fee: StdFee; - readonly signatures: readonly StdSignature[]; - readonly memo: string | undefined; -} -export declare function isStdTx(txValue: unknown): txValue is StdTx; -export interface CosmosSdkTx { - readonly type: string; - readonly value: StdTx; -} export interface StdFee { readonly amount: readonly Coin[]; readonly gas: string; From bf6fed25fe3df81eff246a53a63aa38e1d13ee99 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 24 Sep 2020 11:37:24 +0200 Subject: [PATCH 11/12] Format code in README --- packages/launchpad/README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/launchpad/README.md b/packages/launchpad/README.md index 0ef2b847..9015b820 100644 --- a/packages/launchpad/README.md +++ b/packages/launchpad/README.md @@ -205,14 +205,7 @@ const memo = "Time for action"; const { account_number, sequence } = ( await client.auth.account(myAddress) ).result.value; -const signDoc = makeSignDoc( - [msg], - fee, - apiUrl, - memo, - account_number, - sequence, -); +const signDoc = makeSignDoc([msg], fee, apiUrl, memo, account_number, sequence); const { signature } = await signer.sign(myAddress, signDoc); const signedTx: StdTx = { msg: [msg], From 9d1508e1eeeff05f13f6256ba58717b565ff7134 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 24 Sep 2020 13:40:23 +0200 Subject: [PATCH 12/12] Add makeStdTx and used signed document from signers --- CHANGELOG.md | 1 + packages/cli/README.md | 9 +--- packages/cli/examples/delegate.ts | 9 +--- packages/cli/src/cli.ts | 1 + .../src/cosmwasmclient.searchtx.spec.ts | 10 ++-- packages/cosmwasm/src/cosmwasmclient.spec.ts | 11 ++-- packages/cosmwasm/src/lcdapi/wasm.spec.ts | 6 +-- .../cosmwasm/src/signingcosmwasmclient.ts | 11 ++-- packages/cosmwasm/src/testutils.spec.ts | 10 ---- packages/launchpad/README.md | 9 +--- .../src/cosmosclient.searchtx.spec.ts | 11 ++-- packages/launchpad/src/cosmosclient.spec.ts | 11 ++-- packages/launchpad/src/encoding.ts | 6 +-- packages/launchpad/src/index.ts | 2 +- .../launchpad/src/lcdapi/distribution.spec.ts | 12 ++--- .../launchpad/src/lcdapi/lcdclient.spec.ts | 25 +++------ packages/launchpad/src/lcdapi/staking.spec.ts | 23 +++----- .../launchpad/src/secp256k1wallet.spec.ts | 5 +- packages/launchpad/src/signingcosmosclient.ts | 11 ++-- packages/launchpad/src/testutils.spec.ts | 13 ----- packages/launchpad/src/tx.spec.ts | 54 +++++++++++++++++++ packages/launchpad/src/tx.ts | 13 +++++ packages/launchpad/types/index.d.ts | 2 +- packages/launchpad/types/tx.d.ts | 5 ++ 24 files changed, 127 insertions(+), 143 deletions(-) create mode 100644 packages/launchpad/src/tx.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c01ae8..e9b9f68e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ - @cosmjs/launchpad: Create `WrappedTx`, `WrappedStdTx` and `isWrappedStdTx` to better represent the Amino tx interface. Deprecate `CosmosSdkTx`, which is an alias for `WrappedStdTx`. +- @cosmjs/launchpad: Add `makeStdTx` to create an `StdTx`. - @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases) and `LaunchpadLedger` for more fine-grained access. diff --git a/packages/cli/README.md b/packages/cli/README.md index 8c5fbdfb..47818805 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -74,13 +74,8 @@ const signDoc = makeSignDoc( account_number, sequence, ); -const { signature } = await wallet.sign(faucetAddress, signDoc); -const signedTx: StdTx = { - msg: [sendTokensMsg], - fee: defaultFee, - memo: memo, - signatures: [signature], -}; +const { signed, signature } = await wallet.sign(faucetAddress, signDoc); +const signedTx = makeStdTx(signed, signature); const broadcastResult = await client.broadcastTx(signedTx); ``` diff --git a/packages/cli/examples/delegate.ts b/packages/cli/examples/delegate.ts index 199ed2b6..edcdfcfb 100644 --- a/packages/cli/examples/delegate.ts +++ b/packages/cli/examples/delegate.ts @@ -28,13 +28,8 @@ const { accountNumber, sequence } = await client.getSequence(senderAddress); console.log("Account/sequence:", accountNumber, sequence); const signDoc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence); -const { signature } = await wallet.sign(senderAddress, signDoc); -const signedTx: StdTx = { - msg: [msg], - fee: fee, - memo: memo, - signatures: [signature], -}; +const { signed, signature } = await wallet.sign(senderAddress, signDoc); +const signedTx = makeStdTx(signed, signature); const result = await client.broadcastTx(signedTx); console.log("Broadcast result:", result); diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 32b0ac14..cc3ad5e9 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -99,6 +99,7 @@ export async function main(originalArgs: readonly string[]): Promise { "logs", "makeCosmoshubPath", "makeSignDoc", + "makeStdTx", "IndexedTx", "BroadcastTxResult", "Coin", diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index db6af67a..9c386d77 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -6,6 +6,7 @@ import { isMsgSend, LcdClient, makeSignDoc, + makeStdTx, MsgSend, Secp256k1Wallet, WrappedStdTx, @@ -104,15 +105,10 @@ describe("CosmWasmClient.searchTx", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(alice.address0, signDoc); + const { signed, signature } = await wallet.sign(alice.address0, signDoc); const tx: WrappedStdTx = { type: "cosmos-sdk/StdTx", - value: { - msg: [sendMsg], - fee: fee, - memo: memo, - signatures: [signature], - }, + value: makeStdTx(signed, signature), }; const transactionId = await client.getIdentifier(tx); const result = await client.broadcastTx(tx.value); diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index ec0f895b..1e1143d1 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -5,10 +5,10 @@ import { assertIsBroadcastTxSuccess, isWrappedStdTx, makeSignDoc, + makeStdTx, MsgSend, Secp256k1Wallet, StdFee, - StdTx, } from "@cosmjs/launchpad"; import { assert, sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; @@ -240,13 +240,8 @@ describe("CosmWasmClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(alice.address0); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(alice.address0, signDoc); - const signedTx: StdTx = { - msg: [sendMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(alice.address0, signDoc); + const signedTx = makeStdTx(signed, signature); const result = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(result); const { logs, transactionHash } = result; diff --git a/packages/cosmwasm/src/lcdapi/wasm.spec.ts b/packages/cosmwasm/src/lcdapi/wasm.spec.ts index 199d915a..459ecdf7 100644 --- a/packages/cosmwasm/src/lcdapi/wasm.spec.ts +++ b/packages/cosmwasm/src/lcdapi/wasm.spec.ts @@ -11,6 +11,7 @@ import { coins, LcdClient, makeSignDoc, + makeStdTx, OfflineSigner, Secp256k1Wallet, setupAuthExtension, @@ -36,7 +37,6 @@ import { fromOneElementArray, getHackatom, makeRandomAddress, - makeSignedTx, pendingWithoutWasmd, wasmd, wasmdEnabled, @@ -126,8 +126,8 @@ async function executeContract( const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value; const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const { signature } = await signer.sign(alice.address0, signDoc); - const signedTx = makeSignedTx(theMsg, fee, memo, signature); + const { signed, signature } = await signer.sign(alice.address0, signDoc); + const signedTx = makeStdTx(signed, signature); return client.broadcastTx(signedTx); } diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index 07ff9fa8..1930deb7 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -12,11 +12,11 @@ import { GasPrice, isBroadcastTxFailure, makeSignDoc, + makeStdTx, Msg, MsgSend, OfflineSigner, StdFee, - StdTx, } from "@cosmjs/launchpad"; import { Uint53 } from "@cosmjs/math"; import pako from "pako"; @@ -361,13 +361,8 @@ export class SigningCosmWasmClient extends CosmWasmClient { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); - const { signature } = await this.signer.sign(this.senderAddress, signDoc); - const signedTx: StdTx = { - msg: msgs, - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await this.signer.sign(this.senderAddress, signDoc); + const signedTx = makeStdTx(signed, signature); return this.broadcastTx(signedTx); } } diff --git a/packages/cosmwasm/src/testutils.spec.ts b/packages/cosmwasm/src/testutils.spec.ts index 765d2e8a..fd780bf6 100644 --- a/packages/cosmwasm/src/testutils.spec.ts +++ b/packages/cosmwasm/src/testutils.spec.ts @@ -1,6 +1,5 @@ import { Random } from "@cosmjs/crypto"; import { Bech32, fromBase64 } from "@cosmjs/encoding"; -import { Msg, StdFee, StdSignature, StdTx } from "@cosmjs/launchpad"; import hackatom from "./testdata/contract.json"; @@ -89,12 +88,3 @@ export function fromOneElementArray(elements: ArrayLike): T { if (elements.length !== 1) throw new Error(`Expected exactly one element but got ${elements.length}`); return elements[0]; } - -export function makeSignedTx(firstMsg: Msg, fee: StdFee, memo: string, firstSignature: StdSignature): StdTx { - return { - msg: [firstMsg], - fee: fee, - memo: memo, - signatures: [firstSignature], - }; -} diff --git a/packages/launchpad/README.md b/packages/launchpad/README.md index 9015b820..3ecedbf0 100644 --- a/packages/launchpad/README.md +++ b/packages/launchpad/README.md @@ -206,13 +206,8 @@ const { account_number, sequence } = ( await client.auth.account(myAddress) ).result.value; const signDoc = makeSignDoc([msg], fee, apiUrl, memo, account_number, sequence); -const { signature } = await signer.sign(myAddress, signDoc); -const signedTx: StdTx = { - msg: [msg], - fee: fee, - memo: memo, - signatures: [signature], -}; +const { signed, signature } = await signer.sign(myAddress, signDoc); +const signedTx = makeStdTx(signed, signature); const result = await client.postTx(signedTx); assertIsPostTxSuccess(result); ``` diff --git a/packages/launchpad/src/cosmosclient.searchtx.spec.ts b/packages/launchpad/src/cosmosclient.searchtx.spec.ts index e6f06067..5ff15c3a 100644 --- a/packages/launchpad/src/cosmosclient.searchtx.spec.ts +++ b/packages/launchpad/src/cosmosclient.searchtx.spec.ts @@ -16,7 +16,7 @@ import { wasmd, wasmdEnabled, } from "./testutils.spec"; -import { WrappedStdTx } from "./tx"; +import { makeStdTx, WrappedStdTx } from "./tx"; interface TestTxSend { readonly sender: string; @@ -56,15 +56,10 @@ describe("CosmosClient.searchTx", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(walletAddress, signDoc); + const { signed, signature } = await wallet.sign(walletAddress, signDoc); const tx: WrappedStdTx = { type: "cosmos-sdk/StdTx", - value: { - msg: [sendMsg], - fee: fee, - memo: memo, - signatures: [signature], - }, + value: makeStdTx(signed, signature), }; const transactionId = await client.getIdentifier(tx); const result = await client.broadcastTx(tx.value); diff --git a/packages/launchpad/src/cosmosclient.spec.ts b/packages/launchpad/src/cosmosclient.spec.ts index 4cf1deba..95ee11b3 100644 --- a/packages/launchpad/src/cosmosclient.spec.ts +++ b/packages/launchpad/src/cosmosclient.spec.ts @@ -16,7 +16,7 @@ import { unused, wasmd, } from "./testutils.spec"; -import { isWrappedStdTx, StdTx } from "./tx"; +import { isWrappedStdTx, makeStdTx } from "./tx"; import { StdFee } from "./types"; const blockTime = 1_000; // ms @@ -232,13 +232,8 @@ describe("CosmosClient", () => { const chainId = await client.getChainId(); const { accountNumber, sequence } = await client.getSequence(faucet.address); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(walletAddress, signDoc); - const signedTx: StdTx = { - msg: [sendMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(walletAddress, signDoc); + const signedTx = makeStdTx(signed, signature); const txResult = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(txResult); const { logs, transactionHash } = txResult; diff --git a/packages/launchpad/src/encoding.ts b/packages/launchpad/src/encoding.ts index 970d69b1..81bafa2f 100644 --- a/packages/launchpad/src/encoding.ts +++ b/packages/launchpad/src/encoding.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { toUtf8 } from "@cosmjs/encoding"; +import { Uint53 } from "@cosmjs/math"; -import { uint64ToString } from "./lcdapi"; import { Msg } from "./msgs"; import { StdFee } from "./types"; @@ -47,8 +47,8 @@ export function makeSignDoc( ): StdSignDoc { return { chain_id: chainId, - account_number: uint64ToString(accountNumber), - sequence: uint64ToString(sequence), + account_number: Uint53.fromString(accountNumber.toString()).toString(), + sequence: Uint53.fromString(sequence.toString()).toString(), fee: fee, msgs: msgs, memo: memo, diff --git a/packages/launchpad/src/index.ts b/packages/launchpad/src/index.ts index ed8aa4ad..a703e61f 100644 --- a/packages/launchpad/src/index.ts +++ b/packages/launchpad/src/index.ts @@ -100,7 +100,7 @@ export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; -export { isStdTx, isWrappedStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; +export { isStdTx, isWrappedStdTx, makeStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; export { pubkeyType, PubKey, StdFee, StdSignature } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/src/lcdapi/distribution.spec.ts b/packages/launchpad/src/lcdapi/distribution.spec.ts index df624284..dc9f402e 100644 --- a/packages/launchpad/src/lcdapi/distribution.spec.ts +++ b/packages/launchpad/src/lcdapi/distribution.spec.ts @@ -16,6 +16,7 @@ import { wasmd, wasmdEnabled, } from "../testutils.spec"; +import { makeStdTx } from "../tx"; import { DistributionExtension, setupDistributionExtension } from "./distribution"; import { LcdClient } from "./lcdclient"; @@ -46,15 +47,10 @@ describe("DistributionExtension", () => { const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(faucet.address, signDoc); - const tx = { - msg: [msg], - fee: defaultFee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(faucet.address, signDoc); + const signedTx = makeStdTx(signed, signature); - const result = await client.broadcastTx(tx); + const result = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(result); await sleep(75); // wait until transactions are indexed diff --git a/packages/launchpad/src/lcdapi/lcdclient.spec.ts b/packages/launchpad/src/lcdapi/lcdclient.spec.ts index b971823b..051d8d86 100644 --- a/packages/launchpad/src/lcdapi/lcdclient.spec.ts +++ b/packages/launchpad/src/lcdapi/lcdclient.spec.ts @@ -12,7 +12,6 @@ import cosmoshub from "../testdata/cosmoshub.json"; import { faucet, makeRandomAddress, - makeSignedTx, nonNegativeIntegerMatcher, pendingWithoutWasmd, tendermintIdMatcher, @@ -20,7 +19,7 @@ import { wasmd, wasmdEnabled, } from "../testutils.spec"; -import { isWrappedStdTx, StdTx } from "../tx"; +import { isWrappedStdTx, makeStdTx, StdTx } from "../tx"; import { StdFee } from "../types"; import { makeCosmoshubPath } from "../wallet"; import { setupAuthExtension } from "./auth"; @@ -241,13 +240,8 @@ describe("LcdClient", () => { const { accountNumber, sequence } = await client.getSequence(); const chainId = await client.getChainId(); const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(walletAddress, signDoc); - const signedTx: StdTx = { - msg: [sendMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(walletAddress, signDoc); + const signedTx = makeStdTx(signed, signature); const transactionId = await client.getIdentifier({ type: "cosmos-sdk/StdTx", value: signedTx }); const result = await client.broadcastTx(signedTx); assert(isBroadcastTxFailure(result)); @@ -540,8 +534,8 @@ describe("LcdClient", () => { const { account_number, sequence } = (await client.auth.account(faucet.address)).result.value; const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence); - const { signature } = await wallet.sign(walletAddress, signDoc); - const signedTx = makeSignedTx(theMsg, fee, memo, signature); + const { signed, signature } = await wallet.sign(walletAddress, signDoc); + const signedTx = makeStdTx(signed, signature); const result = await client.broadcastTx(signedTx); expect(result.code).toBeUndefined(); expect(result).toEqual({ @@ -661,13 +655,8 @@ describe("LcdClient", () => { const { account_number, sequence } = (await client.auth.account(walletAddress)).result.value; const signDoc = makeSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence); - const { signature } = await wallet.sign(walletAddress, signDoc); - const signedTx: StdTx = { - msg: [msg1, msg2], - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(walletAddress, signDoc); + const signedTx = makeStdTx(signed, signature); const broadcastResult = await client.broadcastTx(signedTx); expect(broadcastResult.code).toBeUndefined(); }); diff --git a/packages/launchpad/src/lcdapi/staking.spec.ts b/packages/launchpad/src/lcdapi/staking.spec.ts index a188fa89..c7e1439a 100644 --- a/packages/launchpad/src/lcdapi/staking.spec.ts +++ b/packages/launchpad/src/lcdapi/staking.spec.ts @@ -16,6 +16,7 @@ import { wasmd, wasmdEnabled, } from "../testutils.spec"; +import { makeStdTx } from "../tx"; import { LcdClient } from "./lcdclient"; import { BondStatus, setupStakingExtension, StakingExtension } from "./staking"; @@ -47,15 +48,10 @@ describe("StakingExtension", () => { const memo = "Test delegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(faucet.address, signDoc); - const tx = { - msg: [msg], - fee: defaultFee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(faucet.address, signDoc); + const signedTx = makeStdTx(signed, signature); - const result = await client.broadcastTx(tx); + const result = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(result); } { @@ -70,15 +66,10 @@ describe("StakingExtension", () => { const memo = "Test undelegation for wasmd"; const { accountNumber, sequence } = await client.getSequence(); const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence); - const { signature } = await wallet.sign(faucet.address, signDoc); - const tx = { - msg: [msg], - fee: defaultFee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await wallet.sign(faucet.address, signDoc); + const signedTx = makeStdTx(signed, signature); - const result = await client.broadcastTx(tx); + const result = await client.broadcastTx(signedTx); assertIsBroadcastTxSuccess(result); } diff --git a/packages/launchpad/src/secp256k1wallet.spec.ts b/packages/launchpad/src/secp256k1wallet.spec.ts index 87d6c7a9..f7f6f867 100644 --- a/packages/launchpad/src/secp256k1wallet.spec.ts +++ b/packages/launchpad/src/secp256k1wallet.spec.ts @@ -120,10 +120,11 @@ describe("Secp256k1Wallet", () => { account_number: "7", sequence: "54", }; - const { signature } = await wallet.sign(defaultAddress, signDoc); + const { signed, signature } = await wallet.sign(defaultAddress, signDoc); + expect(signed).toEqual(signDoc); const valid = await Secp256k1.verifySignature( Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)), - new Sha256(serializeSignDoc(signDoc)).digest(), + new Sha256(serializeSignDoc(signed)).digest(), defaultPubkey, ); expect(valid).toEqual(true); diff --git a/packages/launchpad/src/signingcosmosclient.ts b/packages/launchpad/src/signingcosmosclient.ts index 0c1edd5c..77090274 100644 --- a/packages/launchpad/src/signingcosmosclient.ts +++ b/packages/launchpad/src/signingcosmosclient.ts @@ -6,7 +6,7 @@ import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas"; import { BroadcastMode } from "./lcdapi"; import { Msg, MsgSend } from "./msgs"; import { OfflineSigner } from "./signer"; -import { StdTx } from "./tx"; +import { makeStdTx } from "./tx"; import { StdFee } from "./types"; /** @@ -90,13 +90,8 @@ export class SigningCosmosClient extends CosmosClient { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence); - const { signature } = await this.signer.sign(this.senderAddress, signDoc); - const signedTx: StdTx = { - msg: msgs, - fee: fee, - memo: memo, - signatures: [signature], - }; + const { signed, signature } = await this.signer.sign(this.senderAddress, signDoc); + const signedTx = makeStdTx(signed, signature); return this.broadcastTx(signedTx); } } diff --git a/packages/launchpad/src/testutils.spec.ts b/packages/launchpad/src/testutils.spec.ts index 335880b1..66a0f592 100644 --- a/packages/launchpad/src/testutils.spec.ts +++ b/packages/launchpad/src/testutils.spec.ts @@ -1,10 +1,6 @@ import { Random } from "@cosmjs/crypto"; import { Bech32 } from "@cosmjs/encoding"; -import { Msg } from "./msgs"; -import { StdTx } from "./tx"; -import { StdFee, StdSignature } from "./types"; - export function makeRandomAddress(): string { return Bech32.encode("cosmos", Random.getBytes(20)); } @@ -75,12 +71,3 @@ export function fromOneElementArray(elements: ArrayLike): T { if (elements.length !== 1) throw new Error(`Expected exactly one element but got ${elements.length}`); return elements[0]; } - -export function makeSignedTx(firstMsg: Msg, fee: StdFee, memo: string, firstSignature: StdSignature): StdTx { - return { - msg: [firstMsg], - fee: fee, - memo: memo, - signatures: [firstSignature], - }; -} diff --git a/packages/launchpad/src/tx.spec.ts b/packages/launchpad/src/tx.spec.ts new file mode 100644 index 00000000..21bf834f --- /dev/null +++ b/packages/launchpad/src/tx.spec.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { coins } from "./coins"; +import { makeSignDoc } from "./encoding"; +import { makeStdTx } from "./tx"; +import { StdFee, StdSignature } from "./types"; + +describe("tx", () => { + describe("makeStdTx", () => { + it("can make an StdTx from a SignDoc and one signature", () => { + const fee: StdFee = { amount: coins(123, "ucosm"), gas: "22" }; + const signDoc = makeSignDoc([], fee, "chain-xy", "hello", 3, 4); + const signature: StdSignature = { + pub_key: { + type: "tendermint/PubKeySecp256k1", + value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", + }, + signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", + }; + const signedTx = makeStdTx(signDoc, signature); + expect(signedTx).toEqual({ + msg: [], + memo: "hello", + fee: fee, + signatures: [signature], + }); + }); + + it("can make an StdTx from a SignDoc and multiple signatures", () => { + const fee: StdFee = { amount: coins(123, "ucosm"), gas: "22" }; + const signDoc = makeSignDoc([], fee, "chain-xy", "hello", 3, 4); + const signature1: StdSignature = { + pub_key: { + type: "tendermint/PubKeySecp256k1", + value: "AtQaCqFnshaZQp6rIkvAPyzThvCvXSDO+9AzbxVErqJP", + }, + signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==", + }; + const signature2: StdSignature = { + pub_key: { + type: "tendermint/PubKeySecp256k1", + value: "A5qFcJBJvEK/fOmEAY0DHNWwSRZ9TEfNZyH8VoVvDtAq", + }, + signature: "NK1Oy4EUGAsoC03c1wi9GG03JC/39LEdautC5Jk643oIbEPqeXHMwaqbdvO/Jws0X/NAXaN8SAy2KNY5Qml+5Q==", + }; + const signedTx = makeStdTx(signDoc, [signature1, signature2]); + expect(signedTx).toEqual({ + msg: [], + memo: "hello", + fee: fee, + signatures: [signature1, signature2], + }); + }); + }); +}); diff --git a/packages/launchpad/src/tx.ts b/packages/launchpad/src/tx.ts index 53c0198c..a466c9f4 100644 --- a/packages/launchpad/src/tx.ts +++ b/packages/launchpad/src/tx.ts @@ -1,3 +1,4 @@ +import { StdSignDoc } from "./encoding"; import { Msg } from "./msgs"; import { StdFee, StdSignature } from "./types"; @@ -20,6 +21,18 @@ export function isStdTx(txValue: unknown): txValue is StdTx { ); } +export function makeStdTx( + content: Pick, + signatures: StdSignature | readonly StdSignature[], +): StdTx { + return { + msg: content.msgs, + fee: content.fee, + memo: content.memo, + signatures: Array.isArray(signatures) ? signatures : [signatures], + }; +} + /** * An Amino JSON wrapper around the Tx interface */ diff --git a/packages/launchpad/types/index.d.ts b/packages/launchpad/types/index.d.ts index 4a87457a..196653ce 100644 --- a/packages/launchpad/types/index.d.ts +++ b/packages/launchpad/types/index.d.ts @@ -98,7 +98,7 @@ export { findSequenceForSignedTx } from "./sequence"; export { encodeSecp256k1Signature, decodeSignature } from "./signature"; export { AccountData, Algo, OfflineSigner, SignResponse } from "./signer"; export { CosmosFeeTable, SigningCosmosClient } from "./signingcosmosclient"; -export { isStdTx, isWrappedStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; +export { isStdTx, isWrappedStdTx, makeStdTx, CosmosSdkTx, StdTx, WrappedStdTx, WrappedTx } from "./tx"; export { pubkeyType, PubKey, StdFee, StdSignature } from "./types"; export { makeCosmoshubPath, executeKdf, KdfConfiguration } from "./wallet"; export { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet"; diff --git a/packages/launchpad/types/tx.d.ts b/packages/launchpad/types/tx.d.ts index 8bf6134e..501dc880 100644 --- a/packages/launchpad/types/tx.d.ts +++ b/packages/launchpad/types/tx.d.ts @@ -1,3 +1,4 @@ +import { StdSignDoc } from "./encoding"; import { Msg } from "./msgs"; import { StdFee, StdSignature } from "./types"; /** @@ -12,6 +13,10 @@ export interface StdTx { readonly memo: string | undefined; } export declare function isStdTx(txValue: unknown): txValue is StdTx; +export declare function makeStdTx( + content: Pick, + signatures: StdSignature | readonly StdSignature[], +): StdTx; /** * An Amino JSON wrapper around the Tx interface */