From 3cfe3c0b94dc3cd083a7e365acffb11818291549 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 28 Jul 2020 11:48:15 +0200 Subject: [PATCH 1/6] Add SigningCosmosClient.signAndPost --- CHANGELOG.md | 2 ++ .../sdk38/src/signingcosmosclient.spec.ts | 29 +++++++++++++++++-- packages/sdk38/src/signingcosmosclient.ts | 16 ++++++---- packages/sdk38/types/signingcosmosclient.d.ts | 6 ++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 720d38c5..6231d1ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,3 +13,5 @@ `OfflineSigner` instead of a `SigningCallback`. - @cosmjs/math: Add missing integer check to `Uint64.fromNumber`. Before `Uint64.fromNumber(1.1)` produced some result. +- @cosmjs/sdk38: Add `SigningCosmosClient.signAndPost` as a mid-level + abstraction between `SigningCosmosClient.sendTokens` and `.postTx`. diff --git a/packages/sdk38/src/signingcosmosclient.spec.ts b/packages/sdk38/src/signingcosmosclient.spec.ts index ac5c6e5f..f1cb66c6 100644 --- a/packages/sdk38/src/signingcosmosclient.spec.ts +++ b/packages/sdk38/src/signingcosmosclient.spec.ts @@ -1,9 +1,11 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { assert } from "@cosmjs/utils"; -import { Coin } from "./coins"; +import { Coin, coin, coins } from "./coins"; import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmosclient"; +import { MsgDelegate } from "./msgs"; import { SigningCosmosClient } from "./signingcosmosclient"; -import { makeRandomAddress, pendingWithoutWasmd } from "./testutils.spec"; +import { makeRandomAddress, pendingWithoutWasmd, validatorAddress } from "./testutils.spec"; import { Secp256k1Wallet } from "./wallet"; const httpUrl = "http://localhost:1317"; @@ -76,4 +78,27 @@ describe("SigningCosmosClient", () => { expect(after.balance).toEqual(transferAmount); }); }); + + describe("signAndPost", () => { + it("works", async () => { + pendingWithoutWasmd(); + const wallet = await Secp256k1Wallet.fromMnemonic(faucet.mnemonic); + const client = new SigningCosmosClient(httpUrl, faucet.address, wallet); + + const msg: MsgDelegate = { + type: "cosmos-sdk/MsgDelegate", + value: { + delegator_address: faucet.address, + validator_address: validatorAddress, + amount: coin(1234, "ustake"), + }, + }; + const fee = { + amount: coins(2000, "ucosm"), + gas: "120000", // 120k + }; + const result = await client.signAndPost([msg], fee, "Use your power wisely"); + assert(!isPostTxFailure(result)); + }); + }); }); diff --git a/packages/sdk38/src/signingcosmosclient.ts b/packages/sdk38/src/signingcosmosclient.ts index 23f0013b..d901425a 100644 --- a/packages/sdk38/src/signingcosmosclient.ts +++ b/packages/sdk38/src/signingcosmosclient.ts @@ -3,7 +3,7 @@ import { Coin, coins } from "./coins"; import { Account, CosmosClient, GetSequenceResult, PostTxResult } from "./cosmosclient"; import { makeSignBytes } from "./encoding"; import { BroadcastMode } from "./lcdapi"; -import { MsgSend } from "./msgs"; +import { Msg, MsgSend } from "./msgs"; import { StdFee, StdTx } from "./types"; import { OfflineSigner } from "./wallet"; @@ -87,18 +87,24 @@ export class SigningCosmosClient extends CosmosClient { amount: transferAmount, }, }; - const fee = this.fees.send; + return this.signAndPost([sendMsg], this.fees.send, memo); + } + + /** + * Gets account number and sequence from the API, creates a sign doc, + * creates a single signature, assembles the signed transaction and broadcasts it. + */ + public async signAndPost(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signBytes = makeSignBytes(msgs, fee, chainId, memo, accountNumber, sequence); const signature = await this.signer.sign(this.senderAddress, signBytes); const signedTx: StdTx = { - msg: [sendMsg], + msg: msgs, fee: fee, memo: memo, signatures: [signature], }; - return this.postTx(signedTx); } } diff --git a/packages/sdk38/types/signingcosmosclient.d.ts b/packages/sdk38/types/signingcosmosclient.d.ts index 410e12db..d9947075 100644 --- a/packages/sdk38/types/signingcosmosclient.d.ts +++ b/packages/sdk38/types/signingcosmosclient.d.ts @@ -1,6 +1,7 @@ import { Coin } from "./coins"; import { Account, CosmosClient, GetSequenceResult, PostTxResult } from "./cosmosclient"; import { BroadcastMode } from "./lcdapi"; +import { Msg } from "./msgs"; import { StdFee } from "./types"; import { OfflineSigner } from "./wallet"; export interface FeeTable { @@ -35,4 +36,9 @@ export declare class SigningCosmosClient extends CosmosClient { getSequence(address?: string): Promise; getAccount(address?: string): Promise; sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise; + /** + * Gets account number and sequence from the API, creates a sign doc, + * creates a single signature, assembles the signed transaction and broadcasts it. + */ + signAndPost(msgs: readonly Msg[], fee: StdFee, memo?: string): Promise; } From 09ad90c9afd79cfaa27818590ad1c3c7a84db8c9 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Jul 2020 09:34:38 +0200 Subject: [PATCH 2/6] Add SigningCosmWasmClient.signAndPost --- CHANGELOG.md | 3 + .../src/signingcosmwasmclient.spec.ts | 42 +++++++- .../cosmwasm/src/signingcosmwasmclient.ts | 101 +++--------------- packages/cosmwasm/src/testutils.spec.ts | 2 + .../cosmwasm/types/signingcosmwasmclient.d.ts | 7 +- 5 files changed, 68 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6231d1ba..d922209f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - @cosmjs/cosmwasm: Rename `CosmWasmClient.getNonce` method to `.getSequence`. - @cosmjs/cosmwasm: Remove `RestClient` class in favour of new modular `LcdClient` class from @cosmjs/sdk38. +- @cosmjs/cosmwasm: Add `SigningCosmWasmClient.signAndPost` as a mid-level + abstraction between `SigningCosmWasmClient.upload`/`.instantiate`/`.execute` + and `.postTx`. - @cosmjs/sdk38: Rename `CosmosClient.getNonce` method to `.getSequence`. - @cosmjs/sdk38: Remove `RestClient` class in favour of new modular `LcdClient` class. diff --git a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts index 6c249071..7a7a2936 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts @@ -1,13 +1,28 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Sha256 } from "@cosmjs/crypto"; import { toHex } from "@cosmjs/encoding"; -import { AuthExtension, coin, coins, LcdClient, Secp256k1Wallet, setupAuthExtension } from "@cosmjs/sdk38"; +import { + AuthExtension, + coin, + coins, + LcdClient, + MsgDelegate, + Secp256k1Wallet, + setupAuthExtension, +} from "@cosmjs/sdk38"; import { assert } from "@cosmjs/utils"; import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient"; -import { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd, unused } from "./testutils.spec"; +import { + alice, + getHackatom, + makeRandomAddress, + pendingWithoutWasmd, + unused, + validatorAddress, +} from "./testutils.spec"; const httpUrl = "http://localhost:1317"; @@ -327,4 +342,27 @@ describe("SigningCosmWasmClient", () => { expect(after.balance).toEqual(transferAmount); }); }); + + describe("signAndPost", () => { + it("works", async () => { + pendingWithoutWasmd(); + const wallet = await Secp256k1Wallet.fromMnemonic(alice.mnemonic); + const client = new SigningCosmWasmClient(httpUrl, alice.address0, wallet); + + const msg: MsgDelegate = { + type: "cosmos-sdk/MsgDelegate", + value: { + delegator_address: alice.address0, + validator_address: validatorAddress, + amount: coin(1234, "ustake"), + }, + }; + const fee = { + amount: coins(2000, "ucosm"), + gas: "120000", // 120k + }; + const result = await client.signAndPost([msg], fee, "Use your power wisely"); + assert(!isPostTxFailure(result)); + }); + }); }); diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index 175176f6..c6fd17cc 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -7,6 +7,7 @@ import { Coin, coins, makeSignBytes, + Msg, MsgSend, OfflineSigner, StdFee, @@ -219,19 +220,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { builder: builder, }, }; - const fee = this.fees.upload; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [storeCodeMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([storeCodeMsg], this.fees.upload, memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -264,21 +253,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { admin: options.admin, }, }; - const memo = options.memo || ""; - const fee = this.fees.init; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, accountNumber, sequence); - - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [instantiateMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([instantiateMsg], this.fees.init, options.memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -299,19 +274,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { new_admin: newAdmin, }, }; - const fee = this.fees.changeAdmin; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([updateAdminMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [updateAdminMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([updateAdminMsg], this.fees.changeAdmin, memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -329,19 +292,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { contract: contractAddress, }, }; - const fee = this.fees.changeAdmin; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([clearAdminMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [clearAdminMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([clearAdminMsg], this.fees.changeAdmin, memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -366,19 +317,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { msg: migrateMsg, }, }; - const fee = this.fees.migrate; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([msg], fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [msg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([msg], this.fees.migrate, memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -403,19 +342,7 @@ export class SigningCosmWasmClient extends CosmWasmClient { sent_funds: transferAmount || [], }, }; - const fee = this.fees.exec; - const { accountNumber, sequence } = await this.getSequence(); - const chainId = await this.getChainId(); - const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, accountNumber, sequence); - const signature = await this.signer.sign(this.senderAddress, signBytes); - const signedTx: StdTx = { - msg: [executeMsg], - fee: fee, - memo: memo, - signatures: [signature], - }; - - const result = await this.postTx(signedTx); + const result = await this.signAndPost([executeMsg], this.fees.exec, memo); if (isPostTxFailure(result)) { throw new Error(createPostTxErrorMessage(result)); } @@ -438,18 +365,24 @@ export class SigningCosmWasmClient extends CosmWasmClient { amount: transferAmount, }, }; - const fee = this.fees.send; + return this.signAndPost([sendMsg], this.fees.send, memo); + } + + /** + * Gets account number and sequence from the API, creates a sign doc, + * creates a single signature, assembles the signed transaction and broadcasts it. + */ + public async signAndPost(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise { const { accountNumber, sequence } = await this.getSequence(); const chainId = await this.getChainId(); - const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); + const signBytes = makeSignBytes(msgs, fee, chainId, memo, accountNumber, sequence); const signature = await this.signer.sign(this.senderAddress, signBytes); const signedTx: StdTx = { - msg: [sendMsg], + msg: msgs, fee: fee, memo: memo, signatures: [signature], }; - return this.postTx(signedTx); } } diff --git a/packages/cosmwasm/src/testutils.spec.ts b/packages/cosmwasm/src/testutils.spec.ts index 5cfe24a4..c7ed6518 100644 --- a/packages/cosmwasm/src/testutils.spec.ts +++ b/packages/cosmwasm/src/testutils.spec.ts @@ -47,6 +47,8 @@ export const wasmd = { chainId: "testing", }; +export const validatorAddress = "cosmosvaloper1gjvanqxc774u6ed9thj4gpn9gj5zus5u32enqn"; + export const alice = { mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park", pubkey0: { diff --git a/packages/cosmwasm/types/signingcosmwasmclient.d.ts b/packages/cosmwasm/types/signingcosmwasmclient.d.ts index 6825aaa5..5c3e0fc4 100644 --- a/packages/cosmwasm/types/signingcosmwasmclient.d.ts +++ b/packages/cosmwasm/types/signingcosmwasmclient.d.ts @@ -1,4 +1,4 @@ -import { BroadcastMode, Coin, OfflineSigner, StdFee, StdSignature } from "@cosmjs/sdk38"; +import { BroadcastMode, Coin, Msg, OfflineSigner, StdFee, StdSignature } from "@cosmjs/sdk38"; import { Account, CosmWasmClient, GetSequenceResult, PostTxResult } from "./cosmwasmclient"; import { Log } from "./logs"; export interface SigningCallback { @@ -124,4 +124,9 @@ export declare class SigningCosmWasmClient extends CosmWasmClient { transferAmount?: readonly Coin[], ): Promise; sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise; + /** + * Gets account number and sequence from the API, creates a sign doc, + * creates a single signature, assembles the signed transaction and broadcasts it. + */ + signAndPost(msgs: readonly Msg[], fee: StdFee, memo?: string): Promise; } From 31ca949a8cb6a8a5ef5ae9f7eee32b40b30964d6 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Jul 2020 09:58:12 +0200 Subject: [PATCH 3/6] Add assertIsPostTxSuccess --- CHANGELOG.md | 2 ++ packages/sdk38/src/cosmosclient.spec.ts | 6 +++--- packages/sdk38/src/cosmosclient.ts | 19 +++++++++++++++++-- packages/sdk38/src/index.ts | 5 +++++ .../sdk38/src/lcdapi/distribution.spec.ts | 8 ++++---- packages/sdk38/src/lcdapi/gov.spec.ts | 10 +++++----- packages/sdk38/src/lcdapi/staking.spec.ts | 10 +++++----- .../sdk38/src/signingcosmosclient.spec.ts | 6 +++--- packages/sdk38/types/cosmosclient.d.ts | 7 ++++++- packages/sdk38/types/index.d.ts | 5 +++++ 10 files changed, 55 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d922209f..a8b33ef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,3 +18,5 @@ `Uint64.fromNumber(1.1)` produced some result. - @cosmjs/sdk38: Add `SigningCosmosClient.signAndPost` as a mid-level abstraction between `SigningCosmosClient.sendTokens` and `.postTx`. +- @cosmjs/sdk38: Export `PostTxFailure`/`PostTxSuccess` and type checkers + `isPostTxFailure`/`isPostTxSuccess`; export `assertIsPostTxSuccess`. diff --git a/packages/sdk38/src/cosmosclient.spec.ts b/packages/sdk38/src/cosmosclient.spec.ts index 30e5d14c..6087e967 100644 --- a/packages/sdk38/src/cosmosclient.spec.ts +++ b/packages/sdk38/src/cosmosclient.spec.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { assert, sleep } from "@cosmjs/utils"; +import { sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; -import { CosmosClient, isPostTxFailure, PrivateCosmWasmClient } from "./cosmosclient"; +import { assertIsPostTxSuccess, CosmosClient, PrivateCosmWasmClient } from "./cosmosclient"; import { makeSignBytes } from "./encoding"; import { findAttribute } from "./logs"; import { MsgSend } from "./msgs"; @@ -234,7 +234,7 @@ describe("CosmosClient", () => { signatures: [signature], }; const txResult = await client.postTx(signedTx); - assert(!isPostTxFailure(txResult)); + assertIsPostTxSuccess(txResult); const { logs, transactionHash } = txResult; const amountAttr = findAttribute(logs, "transfer", "amount"); expect(amountAttr.value).toEqual("1234567ucosm"); diff --git a/packages/sdk38/src/cosmosclient.ts b/packages/sdk38/src/cosmosclient.ts index a447f1b9..34ee4fe0 100644 --- a/packages/sdk38/src/cosmosclient.ts +++ b/packages/sdk38/src/cosmosclient.ts @@ -40,8 +40,23 @@ export interface PostTxSuccess { export type PostTxResult = PostTxSuccess | PostTxFailure; -export function isPostTxFailure(postTxResult: PostTxResult): postTxResult is PostTxFailure { - return !!(postTxResult as PostTxFailure).code; +export function isPostTxFailure(result: PostTxResult): result is PostTxFailure { + return !!(result as PostTxFailure).code; +} + +export function isPostTxSuccess(result: PostTxResult): result is PostTxSuccess { + return !isPostTxFailure(result); +} + +/** + * Ensures the given result is a success. Throws a detailed error message otherwise. + */ +export function assertIsPostTxSuccess(result: PostTxResult): asserts result is PostTxSuccess { + if (isPostTxFailure(result)) { + throw new Error( + `Error when posting tx ${result.transactionHash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`, + ); + } } export interface SearchByIdQuery { diff --git a/packages/sdk38/src/index.ts b/packages/sdk38/src/index.ts index 81ddccea..4afe6c26 100644 --- a/packages/sdk38/src/index.ts +++ b/packages/sdk38/src/index.ts @@ -6,12 +6,17 @@ export { Coin, coin, coins } from "./coins"; export { Account, + assertIsPostTxSuccess, Block, BlockHeader, CosmosClient, GetSequenceResult, IndexedTx, + isPostTxFailure, + isPostTxSuccess, + PostTxFailure, PostTxResult, + PostTxSuccess, SearchByHeightQuery, SearchByIdQuery, SearchBySentFromOrToQuery, diff --git a/packages/sdk38/src/lcdapi/distribution.spec.ts b/packages/sdk38/src/lcdapi/distribution.spec.ts index e57c386e..af63253f 100644 --- a/packages/sdk38/src/lcdapi/distribution.spec.ts +++ b/packages/sdk38/src/lcdapi/distribution.spec.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Bech32 } from "@cosmjs/encoding"; -import { assert, sleep } from "@cosmjs/utils"; +import { sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; -import { isPostTxFailure } from "../cosmosclient"; +import { assertIsPostTxSuccess } from "../cosmosclient"; import { makeSignBytes } from "../encoding"; import { MsgDelegate } from "../msgs"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -55,8 +55,8 @@ describe("DistributionExtension", () => { signatures: [signature], }; - const receipt = await client.postTx(tx); - assert(!isPostTxFailure(receipt)); + const result = await client.postTx(tx); + assertIsPostTxSuccess(result); await sleep(75); // wait until transactions are indexed } diff --git a/packages/sdk38/src/lcdapi/gov.spec.ts b/packages/sdk38/src/lcdapi/gov.spec.ts index ad379c45..3cb35162 100644 --- a/packages/sdk38/src/lcdapi/gov.spec.ts +++ b/packages/sdk38/src/lcdapi/gov.spec.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { assert, sleep } from "@cosmjs/utils"; +import { sleep } from "@cosmjs/utils"; import { coins } from "../coins"; -import { isPostTxFailure } from "../cosmosclient"; +import { assertIsPostTxSuccess } from "../cosmosclient"; import { makeSignBytes } from "../encoding"; import { SigningCosmosClient } from "../signingcosmosclient"; import { @@ -66,9 +66,9 @@ describe("GovExtension", () => { signatures: [proposalSignature], }; - const proposalReceipt = await client.postTx(proposalTx); - assert(!isPostTxFailure(proposalReceipt)); - proposalId = proposalReceipt.logs[0].events + const proposalResult = await client.postTx(proposalTx); + assertIsPostTxSuccess(proposalResult); + proposalId = proposalResult.logs[0].events .find(({ type }) => type === "submit_proposal")! .attributes.find(({ key }) => key === "proposal_id")!.value; diff --git a/packages/sdk38/src/lcdapi/staking.spec.ts b/packages/sdk38/src/lcdapi/staking.spec.ts index dfe91717..22996d25 100644 --- a/packages/sdk38/src/lcdapi/staking.spec.ts +++ b/packages/sdk38/src/lcdapi/staking.spec.ts @@ -2,7 +2,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { coin, coins } from "../coins"; -import { isPostTxFailure } from "../cosmosclient"; +import { assertIsPostTxSuccess } from "../cosmosclient"; import { makeSignBytes } from "../encoding"; import { MsgDelegate, MsgUndelegate } from "../msgs"; import { SigningCosmosClient } from "../signingcosmosclient"; @@ -56,8 +56,8 @@ describe("StakingExtension", () => { signatures: [signature], }; - const receipt = await client.postTx(tx); - assert(!isPostTxFailure(receipt)); + const result = await client.postTx(tx); + assertIsPostTxSuccess(result); } { const msg: MsgUndelegate = { @@ -79,8 +79,8 @@ describe("StakingExtension", () => { signatures: [signature], }; - const receipt = await client.postTx(tx); - assert(!isPostTxFailure(receipt)); + const result = await client.postTx(tx); + assertIsPostTxSuccess(result); } await sleep(75); // wait until transactions are indexed diff --git a/packages/sdk38/src/signingcosmosclient.spec.ts b/packages/sdk38/src/signingcosmosclient.spec.ts index f1cb66c6..a1d4c987 100644 --- a/packages/sdk38/src/signingcosmosclient.spec.ts +++ b/packages/sdk38/src/signingcosmosclient.spec.ts @@ -2,7 +2,7 @@ import { assert } from "@cosmjs/utils"; import { Coin, coin, coins } from "./coins"; -import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmosclient"; +import { assertIsPostTxSuccess, PrivateCosmWasmClient } from "./cosmosclient"; import { MsgDelegate } from "./msgs"; import { SigningCosmosClient } from "./signingcosmosclient"; import { makeRandomAddress, pendingWithoutWasmd, validatorAddress } from "./testutils.spec"; @@ -68,7 +68,7 @@ describe("SigningCosmosClient", () => { // send const result = await client.sendTokens(beneficiaryAddress, transferAmount, "for dinner"); - assert(!isPostTxFailure(result)); + assertIsPostTxSuccess(result); const [firstLog] = result.logs; expect(firstLog).toBeTruthy(); @@ -98,7 +98,7 @@ describe("SigningCosmosClient", () => { gas: "120000", // 120k }; const result = await client.signAndPost([msg], fee, "Use your power wisely"); - assert(!isPostTxFailure(result)); + assertIsPostTxSuccess(result); }); }); }); diff --git a/packages/sdk38/types/cosmosclient.d.ts b/packages/sdk38/types/cosmosclient.d.ts index 57879a30..f6a28054 100644 --- a/packages/sdk38/types/cosmosclient.d.ts +++ b/packages/sdk38/types/cosmosclient.d.ts @@ -29,7 +29,12 @@ export interface PostTxSuccess { readonly data?: Uint8Array; } export declare type PostTxResult = PostTxSuccess | PostTxFailure; -export declare function isPostTxFailure(postTxResult: PostTxResult): postTxResult is PostTxFailure; +export declare function isPostTxFailure(result: PostTxResult): result is PostTxFailure; +export declare function isPostTxSuccess(result: PostTxResult): result is PostTxSuccess; +/** + * Ensures the given result is a success. Throws a detailed error message otherwise. + */ +export declare function assertIsPostTxSuccess(result: PostTxResult): asserts result is PostTxSuccess; export interface SearchByIdQuery { readonly id: string; } diff --git a/packages/sdk38/types/index.d.ts b/packages/sdk38/types/index.d.ts index 7aaafa40..d84be9f2 100644 --- a/packages/sdk38/types/index.d.ts +++ b/packages/sdk38/types/index.d.ts @@ -4,12 +4,17 @@ export { pubkeyToAddress, rawSecp256k1PubkeyToAddress } from "./address"; export { Coin, coin, coins } from "./coins"; export { Account, + assertIsPostTxSuccess, Block, BlockHeader, CosmosClient, GetSequenceResult, IndexedTx, + isPostTxFailure, + isPostTxSuccess, + PostTxFailure, PostTxResult, + PostTxSuccess, SearchByHeightQuery, SearchByIdQuery, SearchBySentFromOrToQuery, From 939b2b9964c6aeb5493a75850b6260727c2fe5de Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Jul 2020 10:06:44 +0200 Subject: [PATCH 4/6] Use *PostTx* types and helpers from sdk38 in cosmwasm --- CHANGELOG.md | 2 ++ packages/cli/src/cli.ts | 2 +- .../src/cosmwasmclient.searchtx.spec.ts | 3 ++- packages/cosmwasm/src/cosmwasmclient.spec.ts | 6 ++--- packages/cosmwasm/src/cosmwasmclient.ts | 25 ++----------------- packages/cosmwasm/src/index.ts | 1 - .../src/signingcosmwasmclient.spec.ts | 7 +++--- .../cosmwasm/src/signingcosmwasmclient.ts | 12 +++------ packages/cosmwasm/types/cosmwasmclient.d.ts | 18 +------------ packages/cosmwasm/types/index.d.ts | 1 - .../cosmwasm/types/signingcosmwasmclient.d.ts | 4 +-- 11 files changed, 21 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b33ef0..1768da89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - @cosmjs/cosmwasm: Add `SigningCosmWasmClient.signAndPost` as a mid-level abstraction between `SigningCosmWasmClient.upload`/`.instantiate`/`.execute` and `.postTx`. +- @cosmjs/cosmwasm: Use `*PostTx*` types and helpers from @cosmjs/sdk38. Remove + exported `PostTxResult`. - @cosmjs/sdk38: Rename `CosmosClient.getNonce` method to `.getSequence`. - @cosmjs/sdk38: Remove `RestClient` class in favour of new modular `LcdClient` class. diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index cb53e7b9..fa7f892f 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -42,7 +42,6 @@ export function main(originalArgs: readonly string[]): void { "ContractDetails", "CosmWasmClient", "GetSequenceResult", - "PostTxResult", "SearchByHeightQuery", "SearchByIdQuery", "SearchBySentFromOrToQuery", @@ -98,6 +97,7 @@ export function main(originalArgs: readonly string[]): void { "MsgSend", "LcdClient", "OfflineSigner", + "PostTxResult", "PubKey", "pubkeyToAddress", "Secp256k1Wallet", diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index 8fc6fcf0..6d902e95 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -4,6 +4,7 @@ import { coins, CosmosSdkTx, isMsgSend, + isPostTxFailure, LcdClient, makeSignBytes, MsgSend, @@ -11,7 +12,7 @@ import { } from "@cosmjs/sdk38"; import { assert, sleep } from "@cosmjs/utils"; -import { CosmWasmClient, isPostTxFailure } from "./cosmwasmclient"; +import { CosmWasmClient } from "./cosmwasmclient"; import { isMsgExecuteContract, isMsgInstantiateContract } from "./msgs"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import { diff --git a/packages/cosmwasm/src/cosmwasmclient.spec.ts b/packages/cosmwasm/src/cosmwasmclient.spec.ts index 5f4121d6..8873281c 100644 --- a/packages/cosmwasm/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.spec.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Sha256 } from "@cosmjs/crypto"; import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding"; -import { makeSignBytes, MsgSend, Secp256k1Wallet, StdFee } from "@cosmjs/sdk38"; +import { assertIsPostTxSuccess, makeSignBytes, MsgSend, Secp256k1Wallet, StdFee } from "@cosmjs/sdk38"; import { assert, sleep } from "@cosmjs/utils"; import { ReadonlyDate } from "readonly-date"; -import { Code, CosmWasmClient, isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient"; +import { Code, CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient"; import { findAttribute } from "./logs"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import cosmoshub from "./testdata/cosmoshub.json"; @@ -243,7 +243,7 @@ describe("CosmWasmClient", () => { signatures: [signature], }; const result = await client.postTx(signedTx); - assert(!isPostTxFailure(result)); + assertIsPostTxSuccess(result); const { logs, transactionHash } = result; const amountAttr = findAttribute(logs, "transfer", "amount"); expect(amountAttr.value).toEqual("1234567ucosm"); diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index b22f6b94..f2543c97 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -9,13 +9,14 @@ import { decodeBech32Pubkey, IndexedTx, LcdClient, + PostTxResult, PubKey, setupAuthExtension, StdTx, } from "@cosmjs/sdk38"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; -import { Log, parseLogs } from "./logs"; +import { parseLogs } from "./logs"; import { JsonObject } from "./types"; export interface GetSequenceResult { @@ -32,28 +33,6 @@ export interface Account { readonly sequence: number; } -export interface PostTxFailure { - /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ - readonly transactionHash: string; - readonly height: number; - readonly code: number; - readonly rawLog: string; -} - -export interface PostTxSuccess { - readonly logs: readonly Log[]; - readonly rawLog: string; - /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ - readonly transactionHash: string; - readonly data?: Uint8Array; -} - -export type PostTxResult = PostTxSuccess | PostTxFailure; - -export function isPostTxFailure(postTxResult: PostTxResult): postTxResult is PostTxFailure { - return !!(postTxResult as PostTxFailure).code; -} - export interface SearchByIdQuery { readonly id: string; } diff --git a/packages/cosmwasm/src/index.ts b/packages/cosmwasm/src/index.ts index 40161f60..e77ef6e9 100644 --- a/packages/cosmwasm/src/index.ts +++ b/packages/cosmwasm/src/index.ts @@ -12,7 +12,6 @@ export { ContractDetails, CosmWasmClient, GetSequenceResult, - PostTxResult, SearchByHeightQuery, SearchByIdQuery, SearchBySentFromOrToQuery, diff --git a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts index 7a7a2936..35c53aa1 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts @@ -2,6 +2,7 @@ import { Sha256 } from "@cosmjs/crypto"; import { toHex } from "@cosmjs/encoding"; import { + assertIsPostTxSuccess, AuthExtension, coin, coins, @@ -12,7 +13,7 @@ import { } from "@cosmjs/sdk38"; import { assert } from "@cosmjs/utils"; -import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient"; +import { PrivateCosmWasmClient } from "./cosmwasmclient"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient"; import { @@ -332,7 +333,7 @@ describe("SigningCosmWasmClient", () => { // send const result = await client.sendTokens(beneficiaryAddress, transferAmount, "for dinner"); - assert(!isPostTxFailure(result)); + assertIsPostTxSuccess(result); const [firstLog] = result.logs; expect(firstLog).toBeTruthy(); @@ -362,7 +363,7 @@ describe("SigningCosmWasmClient", () => { gas: "120000", // 120k }; const result = await client.signAndPost([msg], fee, "Use your power wisely"); - assert(!isPostTxFailure(result)); + assertIsPostTxSuccess(result); }); }); }); diff --git a/packages/cosmwasm/src/signingcosmwasmclient.ts b/packages/cosmwasm/src/signingcosmwasmclient.ts index c6fd17cc..83715b26 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.ts @@ -6,10 +6,13 @@ import { BroadcastMode, Coin, coins, + isPostTxFailure, makeSignBytes, Msg, MsgSend, OfflineSigner, + PostTxFailure, + PostTxResult, StdFee, StdSignature, StdTx, @@ -17,14 +20,7 @@ import { import pako from "pako"; import { isValidBuilder } from "./builder"; -import { - Account, - CosmWasmClient, - GetSequenceResult, - isPostTxFailure, - PostTxFailure, - PostTxResult, -} from "./cosmwasmclient"; +import { Account, CosmWasmClient, GetSequenceResult } from "./cosmwasmclient"; import { findAttribute, Log } from "./logs"; import { MsgClearAdmin, diff --git a/packages/cosmwasm/types/cosmwasmclient.d.ts b/packages/cosmwasm/types/cosmwasmclient.d.ts index ac245804..ed3b6689 100644 --- a/packages/cosmwasm/types/cosmwasmclient.d.ts +++ b/packages/cosmwasm/types/cosmwasmclient.d.ts @@ -5,11 +5,11 @@ import { CosmosSdkTx, IndexedTx, LcdClient, + PostTxResult, PubKey, StdTx, } from "@cosmjs/sdk38"; import { WasmExtension } from "./lcdapi/wasm"; -import { Log } from "./logs"; import { JsonObject } from "./types"; export interface GetSequenceResult { readonly accountNumber: number; @@ -23,22 +23,6 @@ export interface Account { readonly accountNumber: number; readonly sequence: number; } -export interface PostTxFailure { - /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ - readonly transactionHash: string; - readonly height: number; - readonly code: number; - readonly rawLog: string; -} -export interface PostTxSuccess { - readonly logs: readonly Log[]; - readonly rawLog: string; - /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ - readonly transactionHash: string; - readonly data?: Uint8Array; -} -export declare type PostTxResult = PostTxSuccess | PostTxFailure; -export declare function isPostTxFailure(postTxResult: PostTxResult): postTxResult is PostTxFailure; export interface SearchByIdQuery { readonly id: string; } diff --git a/packages/cosmwasm/types/index.d.ts b/packages/cosmwasm/types/index.d.ts index a6406556..517e261b 100644 --- a/packages/cosmwasm/types/index.d.ts +++ b/packages/cosmwasm/types/index.d.ts @@ -11,7 +11,6 @@ export { ContractDetails, CosmWasmClient, GetSequenceResult, - PostTxResult, SearchByHeightQuery, SearchByIdQuery, SearchBySentFromOrToQuery, diff --git a/packages/cosmwasm/types/signingcosmwasmclient.d.ts b/packages/cosmwasm/types/signingcosmwasmclient.d.ts index 5c3e0fc4..71de1463 100644 --- a/packages/cosmwasm/types/signingcosmwasmclient.d.ts +++ b/packages/cosmwasm/types/signingcosmwasmclient.d.ts @@ -1,5 +1,5 @@ -import { BroadcastMode, Coin, Msg, OfflineSigner, StdFee, StdSignature } from "@cosmjs/sdk38"; -import { Account, CosmWasmClient, GetSequenceResult, PostTxResult } from "./cosmwasmclient"; +import { BroadcastMode, Coin, Msg, OfflineSigner, PostTxResult, StdFee, StdSignature } from "@cosmjs/sdk38"; +import { Account, CosmWasmClient, GetSequenceResult } from "./cosmwasmclient"; import { Log } from "./logs"; export interface SigningCallback { (signBytes: Uint8Array): Promise; From 42852c1cae6ed36b400d5dd48a15a15debb30478 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Jul 2020 10:12:24 +0200 Subject: [PATCH 5/6] Use 180k gas for MsgDelegate --- packages/cli/examples/delegate.ts | 2 +- packages/cosmwasm/src/signingcosmwasmclient.spec.ts | 2 +- packages/sdk38/src/signingcosmosclient.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/examples/delegate.ts b/packages/cli/examples/delegate.ts index f518989c..1a99e19e 100644 --- a/packages/cli/examples/delegate.ts +++ b/packages/cli/examples/delegate.ts @@ -17,7 +17,7 @@ const msg: MsgDelegate = { }; const fee = { amount: coins(2000, "ucosm"), - gas: "120000", // 120k + gas: "180000", // 180k }; const memo = "Use your power wisely"; diff --git a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts index 35c53aa1..46f70a83 100644 --- a/packages/cosmwasm/src/signingcosmwasmclient.spec.ts +++ b/packages/cosmwasm/src/signingcosmwasmclient.spec.ts @@ -360,7 +360,7 @@ describe("SigningCosmWasmClient", () => { }; const fee = { amount: coins(2000, "ucosm"), - gas: "120000", // 120k + gas: "180000", // 180k }; const result = await client.signAndPost([msg], fee, "Use your power wisely"); assertIsPostTxSuccess(result); diff --git a/packages/sdk38/src/signingcosmosclient.spec.ts b/packages/sdk38/src/signingcosmosclient.spec.ts index a1d4c987..63952110 100644 --- a/packages/sdk38/src/signingcosmosclient.spec.ts +++ b/packages/sdk38/src/signingcosmosclient.spec.ts @@ -95,7 +95,7 @@ describe("SigningCosmosClient", () => { }; const fee = { amount: coins(2000, "ucosm"), - gas: "120000", // 120k + gas: "180000", // 180k }; const result = await client.signAndPost([msg], fee, "Use your power wisely"); assertIsPostTxSuccess(result); From 06d8f66a9db6fcc2bbd1f10a0016168fc01859b7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 27 Jul 2020 10:12:45 +0200 Subject: [PATCH 6/6] Make validatorDelegations test more stable --- packages/sdk38/src/lcdapi/staking.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk38/src/lcdapi/staking.spec.ts b/packages/sdk38/src/lcdapi/staking.spec.ts index 22996d25..a3c28ace 100644 --- a/packages/sdk38/src/lcdapi/staking.spec.ts +++ b/packages/sdk38/src/lcdapi/staking.spec.ts @@ -402,7 +402,7 @@ describe("StakingExtension", () => { const response = await client.staking.validatorDelegations(validatorAddress); expect(response).toEqual({ height: jasmine.stringMatching(nonNegativeIntegerMatcher), - result: [ + result: jasmine.arrayContaining([ { delegator_address: faucet.address, validator_address: validatorAddress, @@ -415,7 +415,7 @@ describe("StakingExtension", () => { shares: "250000000.000000000000000000", balance: { denom: "ustake", amount: "250000000" }, }, - ], + ]), }); }); });