Merge pull request #318 from CosmWasm/signAndPost
Add Signing{Cosmos,CosmWasm}Client.signAndPost
This commit is contained in:
commit
4a8bbf014f
@ -5,6 +5,11 @@
|
||||
- @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/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.
|
||||
@ -13,3 +18,7 @@
|
||||
`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`.
|
||||
- @cosmjs/sdk38: Export `PostTxFailure`/`PostTxSuccess` and type checkers
|
||||
`isPostTxFailure`/`isPostTxSuccess`; export `assertIsPostTxSuccess`.
|
||||
|
||||
@ -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";
|
||||
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ export {
|
||||
ContractDetails,
|
||||
CosmWasmClient,
|
||||
GetSequenceResult,
|
||||
PostTxResult,
|
||||
SearchByHeightQuery,
|
||||
SearchByIdQuery,
|
||||
SearchBySentFromOrToQuery,
|
||||
|
||||
@ -1,13 +1,29 @@
|
||||
/* 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 {
|
||||
assertIsPostTxSuccess,
|
||||
AuthExtension,
|
||||
coin,
|
||||
coins,
|
||||
LcdClient,
|
||||
MsgDelegate,
|
||||
Secp256k1Wallet,
|
||||
setupAuthExtension,
|
||||
} 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 { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd, unused } from "./testutils.spec";
|
||||
import {
|
||||
alice,
|
||||
getHackatom,
|
||||
makeRandomAddress,
|
||||
pendingWithoutWasmd,
|
||||
unused,
|
||||
validatorAddress,
|
||||
} from "./testutils.spec";
|
||||
|
||||
const httpUrl = "http://localhost:1317";
|
||||
|
||||
@ -317,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();
|
||||
|
||||
@ -327,4 +343,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: "180000", // 180k
|
||||
};
|
||||
const result = await client.signAndPost([msg], fee, "Use your power wisely");
|
||||
assertIsPostTxSuccess(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -6,9 +6,13 @@ import {
|
||||
BroadcastMode,
|
||||
Coin,
|
||||
coins,
|
||||
isPostTxFailure,
|
||||
makeSignBytes,
|
||||
Msg,
|
||||
MsgSend,
|
||||
OfflineSigner,
|
||||
PostTxFailure,
|
||||
PostTxResult,
|
||||
StdFee,
|
||||
StdSignature,
|
||||
StdTx,
|
||||
@ -16,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,
|
||||
@ -219,19 +216,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 +249,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 +270,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 +288,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 +313,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 +338,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 +361,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<PostTxResult> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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: {
|
||||
|
||||
18
packages/cosmwasm/types/cosmwasmclient.d.ts
vendored
18
packages/cosmwasm/types/cosmwasmclient.d.ts
vendored
@ -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;
|
||||
}
|
||||
|
||||
1
packages/cosmwasm/types/index.d.ts
vendored
1
packages/cosmwasm/types/index.d.ts
vendored
@ -11,7 +11,6 @@ export {
|
||||
ContractDetails,
|
||||
CosmWasmClient,
|
||||
GetSequenceResult,
|
||||
PostTxResult,
|
||||
SearchByHeightQuery,
|
||||
SearchByIdQuery,
|
||||
SearchBySentFromOrToQuery,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { BroadcastMode, Coin, 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<StdSignature>;
|
||||
@ -124,4 +124,9 @@ export declare class SigningCosmWasmClient extends CosmWasmClient {
|
||||
transferAmount?: readonly Coin[],
|
||||
): Promise<ExecuteResult>;
|
||||
sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise<PostTxResult>;
|
||||
/**
|
||||
* 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<PostTxResult>;
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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" },
|
||||
},
|
||||
],
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { assert } from "@cosmjs/utils";
|
||||
|
||||
import { Coin } from "./coins";
|
||||
import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmosclient";
|
||||
import { Coin, coin, coins } from "./coins";
|
||||
import { assertIsPostTxSuccess, 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";
|
||||
@ -66,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();
|
||||
|
||||
@ -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: "180000", // 180k
|
||||
};
|
||||
const result = await client.signAndPost([msg], fee, "Use your power wisely");
|
||||
assertIsPostTxSuccess(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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<PostTxResult> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
7
packages/sdk38/types/cosmosclient.d.ts
vendored
7
packages/sdk38/types/cosmosclient.d.ts
vendored
@ -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;
|
||||
}
|
||||
|
||||
5
packages/sdk38/types/index.d.ts
vendored
5
packages/sdk38/types/index.d.ts
vendored
@ -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,
|
||||
|
||||
@ -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<GetSequenceResult>;
|
||||
getAccount(address?: string): Promise<Account | undefined>;
|
||||
sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise<PostTxResult>;
|
||||
/**
|
||||
* 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<PostTxResult>;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user