Merge pull request #432 from CosmWasm/flexible-offline-signer
Allow OfflineSigner implementation to override fields
This commit is contained in:
commit
75b7a7d2bf
14
CHANGELOG.md
14
CHANGELOG.md
@ -45,6 +45,20 @@
|
||||
`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`: `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 `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: 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.
|
||||
|
||||
@ -66,7 +66,7 @@ const sendTokensMsg: MsgSend = {
|
||||
},
|
||||
};
|
||||
|
||||
const signBytes = makeSignBytes(
|
||||
const signDoc = makeSignDoc(
|
||||
[sendTokensMsg],
|
||||
defaultFee,
|
||||
defaultNetworkId,
|
||||
@ -74,13 +74,8 @@ const signBytes = makeSignBytes(
|
||||
account_number,
|
||||
sequence,
|
||||
);
|
||||
const signature = await pen.sign(signBytes);
|
||||
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);
|
||||
```
|
||||
|
||||
|
||||
@ -27,14 +27,9 @@ 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 signedTx: StdTx = {
|
||||
msg: [msg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence);
|
||||
const { signed, signature } = await wallet.sign(senderAddress, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
|
||||
const result = await client.broadcastTx(signedTx);
|
||||
console.log("Broadcast result:", result);
|
||||
|
||||
@ -98,7 +98,8 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
|
||||
"encodeSecp256k1Signature",
|
||||
"logs",
|
||||
"makeCosmoshubPath",
|
||||
"makeSignBytes",
|
||||
"makeSignDoc",
|
||||
"makeStdTx",
|
||||
"IndexedTx",
|
||||
"BroadcastTxResult",
|
||||
"Coin",
|
||||
@ -115,6 +116,7 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
|
||||
"Secp256k1Wallet",
|
||||
"SigningCosmosClient",
|
||||
"StdFee",
|
||||
"StdSignDoc",
|
||||
"StdTx",
|
||||
],
|
||||
],
|
||||
@ -161,7 +163,13 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
|
||||
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 = makeSignDoc([], 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);
|
||||
|
||||
@ -2,13 +2,14 @@
|
||||
import {
|
||||
Coin,
|
||||
coins,
|
||||
CosmosSdkTx,
|
||||
isBroadcastTxFailure,
|
||||
isMsgSend,
|
||||
LcdClient,
|
||||
makeSignBytes,
|
||||
makeSignDoc,
|
||||
makeStdTx,
|
||||
MsgSend,
|
||||
Secp256k1Wallet,
|
||||
WrappedStdTx,
|
||||
} from "@cosmjs/launchpad";
|
||||
import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
@ -30,7 +31,7 @@ interface TestTxSend {
|
||||
readonly recipient: string;
|
||||
readonly hash: string;
|
||||
readonly height: number;
|
||||
readonly tx: CosmosSdkTx;
|
||||
readonly tx: WrappedStdTx;
|
||||
}
|
||||
|
||||
interface TestTxExecute {
|
||||
@ -38,7 +39,7 @@ interface TestTxExecute {
|
||||
readonly contract: string;
|
||||
readonly hash: string;
|
||||
readonly height: number;
|
||||
readonly tx: CosmosSdkTx;
|
||||
readonly tx: WrappedStdTx;
|
||||
}
|
||||
|
||||
describe("CosmWasmClient.searchTx", () => {
|
||||
@ -103,16 +104,11 @@ 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 tx: CosmosSdkTx = {
|
||||
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
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);
|
||||
|
||||
@ -3,7 +3,9 @@ import { Sha256 } from "@cosmjs/crypto";
|
||||
import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding";
|
||||
import {
|
||||
assertIsBroadcastTxSuccess,
|
||||
makeSignBytes,
|
||||
isWrappedStdTx,
|
||||
makeSignDoc,
|
||||
makeStdTx,
|
||||
MsgSend,
|
||||
Secp256k1Wallet,
|
||||
StdFee,
|
||||
@ -199,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);
|
||||
});
|
||||
});
|
||||
@ -236,14 +239,9 @@ 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 signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
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;
|
||||
|
||||
@ -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<string> {
|
||||
public async getIdentifier(tx: WrappedStdTx): Promise<string> {
|
||||
// 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();
|
||||
|
||||
@ -10,7 +10,8 @@ import {
|
||||
coin,
|
||||
coins,
|
||||
LcdClient,
|
||||
makeSignBytes,
|
||||
makeSignDoc,
|
||||
makeStdTx,
|
||||
OfflineSigner,
|
||||
Secp256k1Wallet,
|
||||
setupAuthExtension,
|
||||
@ -36,7 +37,6 @@ import {
|
||||
fromOneElementArray,
|
||||
getHackatom,
|
||||
makeRandomAddress,
|
||||
makeSignedTx,
|
||||
pendingWithoutWasmd,
|
||||
wasmd,
|
||||
wasmdEnabled,
|
||||
@ -125,9 +125,9 @@ 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 signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
||||
const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const { signed, signature } = await signer.sign(alice.address0, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
return client.broadcastTx(signedTx);
|
||||
}
|
||||
|
||||
|
||||
@ -11,12 +11,12 @@ import {
|
||||
GasLimits,
|
||||
GasPrice,
|
||||
isBroadcastTxFailure,
|
||||
makeSignBytes,
|
||||
makeSignDoc,
|
||||
makeStdTx,
|
||||
Msg,
|
||||
MsgSend,
|
||||
OfflineSigner,
|
||||
StdFee,
|
||||
StdTx,
|
||||
} from "@cosmjs/launchpad";
|
||||
import { Uint53 } from "@cosmjs/math";
|
||||
import pako from "pako";
|
||||
@ -360,14 +360,9 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<BroadcastTxResult> {
|
||||
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 signedTx: StdTx = {
|
||||
msg: msgs,
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||
const { signed, signature } = await this.signer.sign(this.senderAddress, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
return this.broadcastTx(signedTx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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],
|
||||
};
|
||||
}
|
||||
|
||||
4
packages/cosmwasm/types/cosmwasmclient.d.ts
vendored
4
packages/cosmwasm/types/cosmwasmclient.d.ts
vendored
@ -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<string>;
|
||||
getIdentifier(tx: WrappedStdTx): Promise<string>;
|
||||
/**
|
||||
* Returns account number and sequence.
|
||||
*
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<label>Message</label>
|
||||
<textarea id="message">
|
||||
<textarea id="sign-doc">
|
||||
</textarea>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@ -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, makeSignDoc, StdFee, StdSignature } from "@cosmjs/launchpad";
|
||||
|
||||
import { LedgerSigner } from "../ledgersigner";
|
||||
|
||||
@ -48,13 +48,7 @@ export async function sign(
|
||||
},
|
||||
},
|
||||
];
|
||||
const signBytes = makeSignBytes(
|
||||
msgs,
|
||||
defaultFee,
|
||||
defaultChainId,
|
||||
defaultMemo,
|
||||
accountNumber,
|
||||
defaultSequence,
|
||||
);
|
||||
return signer.sign(fromAddress, signBytes);
|
||||
const signDoc = makeSignDoc(msgs, defaultFee, defaultChainId, defaultMemo, accountNumber, defaultSequence);
|
||||
const { signature } = await signer.sign(fromAddress, signDoc);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@ -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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
|
||||
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;
|
||||
|
||||
@ -4,8 +4,9 @@ import {
|
||||
encodeSecp256k1Signature,
|
||||
makeCosmoshubPath,
|
||||
OfflineSigner,
|
||||
StdSignature,
|
||||
StdSignDoc,
|
||||
} from "@cosmjs/launchpad";
|
||||
import { serializeSignDoc, SignResponse } from "@cosmjs/launchpad";
|
||||
|
||||
import { LaunchpadLedger, LaunchpadLedgerOptions } from "./launchpadledger";
|
||||
|
||||
@ -34,17 +35,21 @@ export class LedgerSigner implements OfflineSigner {
|
||||
return this.accounts;
|
||||
}
|
||||
|
||||
public async sign(address: string, message: Uint8Array): Promise<StdSignature> {
|
||||
public async sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse> {
|
||||
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);
|
||||
return encodeSecp256k1Signature(accountForAddress.pubkey, signature);
|
||||
return {
|
||||
signed: signDoc,
|
||||
signature: encodeSecp256k1Signature(accountForAddress.pubkey, signature),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { AccountData, OfflineSigner, StdSignature } 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<readonly AccountData[]>;
|
||||
sign(address: string, message: Uint8Array): Promise<StdSignature>;
|
||||
sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse>;
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ import { MsgExecuteContract, setupWasmExtension } from "@cosmjs/cosmwasm";
|
||||
import {
|
||||
assertIsPostTxSuccess,
|
||||
LcdClient,
|
||||
makeSignBytes,
|
||||
makeSignDoc,
|
||||
setupAuthExtension,
|
||||
StdFee,
|
||||
StdTx,
|
||||
@ -205,21 +205,9 @@ const memo = "Time for action";
|
||||
const { account_number, sequence } = (
|
||||
await client.auth.account(myAddress)
|
||||
).result.value;
|
||||
const signBytes = makeSignBytes(
|
||||
[msg],
|
||||
fee,
|
||||
apiUrl,
|
||||
memo,
|
||||
account_number,
|
||||
sequence,
|
||||
);
|
||||
const signature = await signer.sign(myAddress, signBytes);
|
||||
const signedTx: StdTx = {
|
||||
msg: [msg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg], fee, apiUrl, memo, account_number, sequence);
|
||||
const { signed, signature } = await signer.sign(myAddress, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
const result = await client.postTx(signedTx);
|
||||
assertIsPostTxSuccess(result);
|
||||
```
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coins } from "./coins";
|
||||
import { CosmosClient, isBroadcastTxFailure } from "./cosmosclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeSignDoc } from "./encoding";
|
||||
import { LcdClient } from "./lcdapi";
|
||||
import { isMsgSend, MsgSend } from "./msgs";
|
||||
import { Secp256k1Wallet } from "./secp256k1wallet";
|
||||
@ -16,14 +16,14 @@ import {
|
||||
wasmd,
|
||||
wasmdEnabled,
|
||||
} from "./testutils.spec";
|
||||
import { CosmosSdkTx } from "./types";
|
||||
import { makeStdTx, 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", () => {
|
||||
@ -55,16 +55,11 @@ 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 tx: CosmosSdkTx = {
|
||||
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
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);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
/* 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";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeSignDoc } from "./encoding";
|
||||
import { findAttribute } from "./logs";
|
||||
import { MsgSend } from "./msgs";
|
||||
import { Secp256k1Wallet } from "./secp256k1wallet";
|
||||
@ -16,6 +16,7 @@ import {
|
||||
unused,
|
||||
wasmd,
|
||||
} from "./testutils.spec";
|
||||
import { isWrappedStdTx, makeStdTx } 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);
|
||||
});
|
||||
});
|
||||
@ -229,14 +231,9 @@ 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 signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
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;
|
||||
|
||||
@ -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<string> {
|
||||
public async getIdentifier(tx: WrappedStdTx): Promise<string> {
|
||||
// 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();
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -29,30 +29,33 @@ 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 makeSignBytes(
|
||||
export function makeSignDoc(
|
||||
msgs: readonly Msg[],
|
||||
fee: StdFee,
|
||||
chainId: string,
|
||||
memo: string,
|
||||
accountNumber: number | string,
|
||||
sequence: number | string,
|
||||
): Uint8Array {
|
||||
const signDoc: StdSignDoc = {
|
||||
account_number: uint64ToString(accountNumber),
|
||||
): StdSignDoc {
|
||||
return {
|
||||
chain_id: chainId,
|
||||
account_number: Uint53.fromString(accountNumber.toString()).toString(),
|
||||
sequence: Uint53.fromString(sequence.toString()).toString(),
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
msgs: msgs,
|
||||
sequence: uint64ToString(sequence),
|
||||
memo: memo,
|
||||
};
|
||||
}
|
||||
|
||||
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array {
|
||||
const sortedSignDoc = sortJson(signDoc);
|
||||
return toUtf8(JSON.stringify(sortedSignDoc));
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ export {
|
||||
isSearchBySentFromOrToQuery,
|
||||
isSearchByTagsQuery,
|
||||
} from "./cosmosclient";
|
||||
export { makeSignBytes, StdSignDoc } from "./encoding";
|
||||
export { makeSignDoc, serializeSignDoc, StdSignDoc } from "./encoding";
|
||||
export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas";
|
||||
export {
|
||||
AuthAccountsResponse,
|
||||
@ -98,15 +98,9 @@ export {
|
||||
} from "./pubkey";
|
||||
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 {
|
||||
AccountData,
|
||||
Algo,
|
||||
PrehashType,
|
||||
OfflineSigner,
|
||||
makeCosmoshubPath,
|
||||
executeKdf,
|
||||
KdfConfiguration,
|
||||
} from "./wallet";
|
||||
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";
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -4,7 +4,7 @@ import { sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coin, coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeSignDoc } from "../encoding";
|
||||
import { MsgDelegate } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
import { SigningCosmosClient } from "../signingcosmosclient";
|
||||
@ -16,6 +16,7 @@ import {
|
||||
wasmd,
|
||||
wasmdEnabled,
|
||||
} from "../testutils.spec";
|
||||
import { makeStdTx } from "../tx";
|
||||
import { DistributionExtension, setupDistributionExtension } from "./distribution";
|
||||
import { LcdClient } from "./lcdclient";
|
||||
|
||||
@ -45,16 +46,11 @@ 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 tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
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
|
||||
|
||||
@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } 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 proposalSignBytes = makeSignBytes(
|
||||
const proposalSignDoc = makeSignDoc(
|
||||
[proposalMsg],
|
||||
defaultFee,
|
||||
chainId,
|
||||
@ -58,7 +58,7 @@ describe("GovExtension", () => {
|
||||
proposalAccountNumber,
|
||||
proposalSequence,
|
||||
);
|
||||
const proposalSignature = await wallet.sign(faucet.address, proposalSignBytes);
|
||||
const { signature: 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 = makeSignDoc(
|
||||
[voteMsg],
|
||||
defaultFee,
|
||||
chainId,
|
||||
@ -90,7 +90,7 @@ describe("GovExtension", () => {
|
||||
voteAccountNumber,
|
||||
voteSequence,
|
||||
);
|
||||
const voteSignature = await wallet.sign(faucet.address, voteSignBytes);
|
||||
const { signature: voteSignature } = await wallet.sign(faucet.address, voteSignDoc);
|
||||
const voteTx = {
|
||||
msg: [voteMsg],
|
||||
fee: defaultFee,
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { Coin } from "../coins";
|
||||
import { isBroadcastTxFailure } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeSignDoc } from "../encoding";
|
||||
import { parseLogs } from "../logs";
|
||||
import { MsgSend } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
@ -12,7 +12,6 @@ import cosmoshub from "../testdata/cosmoshub.json";
|
||||
import {
|
||||
faucet,
|
||||
makeRandomAddress,
|
||||
makeSignedTx,
|
||||
nonNegativeIntegerMatcher,
|
||||
pendingWithoutWasmd,
|
||||
tendermintIdMatcher,
|
||||
@ -20,6 +19,7 @@ import {
|
||||
wasmd,
|
||||
wasmdEnabled,
|
||||
} from "../testutils.spec";
|
||||
import { isWrappedStdTx, makeStdTx, StdTx } from "../tx";
|
||||
import { StdFee } from "../types";
|
||||
import { makeCosmoshubPath } from "../wallet";
|
||||
import { setupAuthExtension } from "./auth";
|
||||
@ -239,14 +239,9 @@ 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 signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
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));
|
||||
@ -493,6 +488,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({
|
||||
@ -537,9 +533,9 @@ 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 signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
||||
const signDoc = makeSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
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({
|
||||
@ -594,13 +590,13 @@ 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 signedTx = {
|
||||
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);
|
||||
const signedTx: StdTx = {
|
||||
msg: [theMsg],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
@ -658,14 +654,9 @@ 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 signedTx = {
|
||||
msg: [msg1, msg2],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature1],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const { signed, signature } = await wallet.sign(walletAddress, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
const broadcastResult = await client.broadcastTx(signedTx);
|
||||
expect(broadcastResult.code).toBeUndefined();
|
||||
});
|
||||
@ -722,11 +713,11 @@ 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 signedTx = {
|
||||
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 = {
|
||||
msg: [msg2, msg1],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
@ -793,11 +784,11 @@ 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 signedTx = {
|
||||
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 = {
|
||||
msg: [msg1, msg2],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
@ -859,11 +850,11 @@ 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 signedTx = {
|
||||
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 = {
|
||||
msg: [msg2, msg1],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
|
||||
@ -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<EncodeTxResponse> {
|
||||
public async encodeTx(tx: WrappedStdTx): Promise<EncodeTxResponse> {
|
||||
const responseData = await this.post("/txs/encode", tx);
|
||||
if (!responseData.tx) {
|
||||
throw new Error("Unexpected response data format");
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coin, coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeSignDoc } from "../encoding";
|
||||
import { MsgDelegate, MsgUndelegate } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
import { SigningCosmosClient } from "../signingcosmosclient";
|
||||
@ -16,6 +16,7 @@ import {
|
||||
wasmd,
|
||||
wasmdEnabled,
|
||||
} from "../testutils.spec";
|
||||
import { makeStdTx } from "../tx";
|
||||
import { LcdClient } from "./lcdclient";
|
||||
import { BondStatus, setupStakingExtension, StakingExtension } from "./staking";
|
||||
|
||||
@ -46,16 +47,11 @@ 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 tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
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);
|
||||
}
|
||||
{
|
||||
@ -69,16 +65,11 @@ 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 tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -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,19 @@ 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 { signed, signature } = await wallet.sign(defaultAddress, signDoc);
|
||||
expect(signed).toEqual(signDoc);
|
||||
const valid = await Secp256k1.verifySignature(
|
||||
Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)),
|
||||
new Sha256(message).digest(),
|
||||
new Sha256(serializeSignDoc(signed)).digest(),
|
||||
defaultPubkey,
|
||||
);
|
||||
expect(valid).toEqual(true);
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
pathToString,
|
||||
Random,
|
||||
Secp256k1,
|
||||
Sha256,
|
||||
Slip10,
|
||||
Slip10Curve,
|
||||
stringToPath,
|
||||
@ -13,19 +14,16 @@ 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 { StdSignature } from "./types";
|
||||
import { AccountData, OfflineSigner, SignResponse } from "./signer";
|
||||
import {
|
||||
AccountData,
|
||||
decrypt,
|
||||
encrypt,
|
||||
EncryptionConfiguration,
|
||||
executeKdf,
|
||||
KdfConfiguration,
|
||||
makeCosmoshubPath,
|
||||
OfflineSigner,
|
||||
prehash,
|
||||
PrehashType,
|
||||
supportedAlgorithms,
|
||||
} from "./wallet";
|
||||
|
||||
@ -257,18 +255,17 @@ export class Secp256k1Wallet implements OfflineSigner {
|
||||
];
|
||||
}
|
||||
|
||||
public async sign(
|
||||
address: string,
|
||||
message: Uint8Array,
|
||||
prehashType: PrehashType = "sha256",
|
||||
): Promise<StdSignature> {
|
||||
if (address !== this.address) {
|
||||
throw new Error(`Address ${address} not found in wallet`);
|
||||
public async sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse> {
|
||||
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);
|
||||
return {
|
||||
signed: signDoc,
|
||||
signature: encodeSecp256k1Signature(this.pubkey, signatureBytes),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto";
|
||||
|
||||
import { makeSignBytes } from "./encoding";
|
||||
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,
|
||||
@ -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(
|
||||
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);
|
||||
|
||||
38
packages/launchpad/src/signer.ts
Normal file
38
packages/launchpad/src/signer.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { StdSignature } from "./types";
|
||||
|
||||
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 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 signed: StdSignDoc;
|
||||
readonly signature: StdSignature;
|
||||
}
|
||||
|
||||
export interface OfflineSigner {
|
||||
/**
|
||||
* Get AccountData array from wallet. Rejects if not enabled.
|
||||
*/
|
||||
readonly getAccounts: () => Promise<readonly AccountData[]>;
|
||||
|
||||
/**
|
||||
* 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<SignResponse>;
|
||||
}
|
||||
@ -1,12 +1,13 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Coin } from "./coins";
|
||||
import { Account, BroadcastTxResult, CosmosClient, GetSequenceResult } from "./cosmosclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeSignDoc } from "./encoding";
|
||||
import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas";
|
||||
import { BroadcastMode } from "./lcdapi";
|
||||
import { Msg, MsgSend } from "./msgs";
|
||||
import { StdFee, StdTx } from "./types";
|
||||
import { OfflineSigner } from "./wallet";
|
||||
import { OfflineSigner } from "./signer";
|
||||
import { makeStdTx } from "./tx";
|
||||
import { StdFee } from "./types";
|
||||
|
||||
/**
|
||||
* These fees are used by the higher level methods of SigningCosmosClient
|
||||
@ -88,14 +89,9 @@ export class SigningCosmosClient extends CosmosClient {
|
||||
public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<BroadcastTxResult> {
|
||||
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 signedTx: StdTx = {
|
||||
msg: msgs,
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature],
|
||||
};
|
||||
const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||
const { signed, signature } = await this.signer.sign(this.senderAddress, signDoc);
|
||||
const signedTx = makeStdTx(signed, signature);
|
||||
return this.broadcastTx(signedTx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
import { Random } from "@cosmjs/crypto";
|
||||
import { Bech32 } from "@cosmjs/encoding";
|
||||
|
||||
import { Msg } from "./msgs";
|
||||
import { StdFee, StdSignature, StdTx } from "./types";
|
||||
|
||||
export function makeRandomAddress(): string {
|
||||
return Bech32.encode("cosmos", Random.getBytes(20));
|
||||
}
|
||||
@ -74,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],
|
||||
};
|
||||
}
|
||||
|
||||
54
packages/launchpad/src/tx.spec.ts
Normal file
54
packages/launchpad/src/tx.spec.ts
Normal 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],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
57
packages/launchpad/src/tx.ts
Normal file
57
packages/launchpad/src/tx.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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;
|
||||
@ -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[];
|
||||
|
||||
@ -3,52 +3,12 @@ import {
|
||||
HdPath,
|
||||
isArgon2idOptions,
|
||||
Random,
|
||||
Sha256,
|
||||
Sha512,
|
||||
Slip10RawIndex,
|
||||
xchacha20NonceLength,
|
||||
Xchacha20poly1305Ietf,
|
||||
} 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<readonly AccountData[]>;
|
||||
|
||||
/**
|
||||
* Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled.
|
||||
*/
|
||||
readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
|
||||
}
|
||||
|
||||
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`.
|
||||
|
||||
7
packages/launchpad/types/cosmosclient.d.ts
vendored
7
packages/launchpad/types/cosmosclient.d.ts
vendored
@ -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<string>;
|
||||
getIdentifier(tx: WrappedStdTx): Promise<string>;
|
||||
/**
|
||||
* Returns account number and sequence.
|
||||
*
|
||||
|
||||
13
packages/launchpad/types/encoding.d.ts
vendored
13
packages/launchpad/types/encoding.d.ts
vendored
@ -6,18 +6,19 @@ 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 makeSignBytes(
|
||||
export declare function makeSignDoc(
|
||||
msgs: readonly Msg[],
|
||||
fee: StdFee,
|
||||
chainId: string,
|
||||
memo: string,
|
||||
accountNumber: number | string,
|
||||
sequence: number | string,
|
||||
): Uint8Array;
|
||||
): StdSignDoc;
|
||||
export declare function serializeSignDoc(signDoc: StdSignDoc): Uint8Array;
|
||||
|
||||
16
packages/launchpad/types/index.d.ts
vendored
16
packages/launchpad/types/index.d.ts
vendored
@ -26,7 +26,7 @@ export {
|
||||
isSearchBySentFromOrToQuery,
|
||||
isSearchByTagsQuery,
|
||||
} from "./cosmosclient";
|
||||
export { makeSignBytes, StdSignDoc } from "./encoding";
|
||||
export { makeSignDoc, serializeSignDoc, StdSignDoc } from "./encoding";
|
||||
export { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas";
|
||||
export {
|
||||
AuthAccountsResponse,
|
||||
@ -96,15 +96,9 @@ export {
|
||||
} from "./pubkey";
|
||||
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 {
|
||||
AccountData,
|
||||
Algo,
|
||||
PrehashType,
|
||||
OfflineSigner,
|
||||
makeCosmoshubPath,
|
||||
executeKdf,
|
||||
KdfConfiguration,
|
||||
} from "./wallet";
|
||||
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";
|
||||
|
||||
4
packages/launchpad/types/lcdapi/base.d.ts
vendored
4
packages/launchpad/types/lcdapi/base.d.ts
vendored
@ -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 */
|
||||
|
||||
@ -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<TxsResponse>;
|
||||
txsQuery(query: string): Promise<SearchTxsResponse>;
|
||||
/** returns the amino-encoding of the transaction performed by the server */
|
||||
encodeTx(tx: CosmosSdkTx): Promise<EncodeTxResponse>;
|
||||
encodeTx(tx: WrappedStdTx): Promise<EncodeTxResponse>;
|
||||
/**
|
||||
* Broadcasts a signed transaction to the transaction pool.
|
||||
* Depending on the client's broadcast mode, this might or might
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { HdPath } from "@cosmjs/crypto";
|
||||
import { StdSignature } from "./types";
|
||||
import { AccountData, EncryptionConfiguration, KdfConfiguration, OfflineSigner, PrehashType } from "./wallet";
|
||||
import { StdSignDoc } from "./encoding";
|
||||
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.
|
||||
* All fields in here must be JSON types.
|
||||
@ -85,7 +86,7 @@ export declare class Secp256k1Wallet implements OfflineSigner {
|
||||
get mnemonic(): string;
|
||||
private get address();
|
||||
getAccounts(): Promise<readonly AccountData[]>;
|
||||
sign(address: string, message: Uint8Array, prehashType?: PrehashType): Promise<StdSignature>;
|
||||
sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse>;
|
||||
/**
|
||||
* Generates an encrypted serialization of this wallet.
|
||||
*
|
||||
|
||||
4
packages/launchpad/types/sequence.d.ts
vendored
4
packages/launchpad/types/sequence.d.ts
vendored
@ -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,
|
||||
|
||||
33
packages/launchpad/types/signer.d.ts
vendored
Normal file
33
packages/launchpad/types/signer.d.ts
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { StdSignature } from "./types";
|
||||
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 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 signed: StdSignDoc;
|
||||
readonly signature: StdSignature;
|
||||
}
|
||||
export interface OfflineSigner {
|
||||
/**
|
||||
* Get AccountData array from wallet. Rejects if not enabled.
|
||||
*/
|
||||
readonly getAccounts: () => Promise<readonly AccountData[]>;
|
||||
/**
|
||||
* 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<SignResponse>;
|
||||
}
|
||||
@ -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
|
||||
*/
|
||||
|
||||
36
packages/launchpad/types/tx.d.ts
vendored
Normal file
36
packages/launchpad/types/tx.d.ts
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
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;
|
||||
export declare function makeStdTx(
|
||||
content: Pick<StdSignDoc, "msgs" | "fee" | "memo">,
|
||||
signatures: StdSignature | readonly StdSignature[],
|
||||
): 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;
|
||||
17
packages/launchpad/types/types.d.ts
vendored
17
packages/launchpad/types/types.d.ts
vendored
@ -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;
|
||||
|
||||
19
packages/launchpad/types/wallet.d.ts
vendored
19
packages/launchpad/types/wallet.d.ts
vendored
@ -1,23 +1,4 @@
|
||||
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<readonly AccountData[]>;
|
||||
/**
|
||||
* Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled.
|
||||
*/
|
||||
readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
|
||||
}
|
||||
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`.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user