Add makeStdTx and used signed document from signers

This commit is contained in:
Simon Warta 2020-09-24 13:40:23 +02:00
parent bf6fed25fe
commit 9d1508e1ee
24 changed files with 127 additions and 143 deletions

View File

@ -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.

View File

@ -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);
```

View File

@ -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);

View File

@ -99,6 +99,7 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
"logs",
"makeCosmoshubPath",
"makeSignDoc",
"makeStdTx",
"IndexedTx",
"BroadcastTxResult",
"Coin",

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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<T>(elements: ArrayLike<T>): 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],
};
}

View File

@ -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);
```

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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";

View File

@ -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

View File

@ -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();
});

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<T>(elements: ArrayLike<T>): 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],
};
}

View File

@ -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],
});
});
});
});

View File

@ -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<StdSignDoc, "msgs" | "fee" | "memo">,
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
*/

View File

@ -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";

View File

@ -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<StdSignDoc, "msgs" | "fee" | "memo">,
signatures: StdSignature | readonly StdSignature[],
): StdTx;
/**
* An Amino JSON wrapper around the Tx interface
*/