Let OfflineSigner.sign take a StdSignDoc instead of an encoded message
This commit is contained in:
parent
6c116f3d5a
commit
bc890bee73
@ -47,6 +47,8 @@
|
||||
`BroadcastTxsResponse.logs` to `unknown[]`.
|
||||
- @cosmjs/launchpad: Export `StdSignDoc` and create helpers to make and
|
||||
serialize a `StdSignDoc`: `makeStdSignDoc` and `serializeSignDoc`.
|
||||
- @cosmjs/launchpad: Let `OfflineSigner.sign` take an `StdSignDoc` instead of an
|
||||
encoded message.
|
||||
- @cosmjs/launchpad-ledger: Add package supporting Ledger device integration for
|
||||
Launchpad. Two new classes are provided: `LedgerSigner` (for most use cases)
|
||||
and `LaunchpadLedger` for more fine-grained access.
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
isBroadcastTxFailure,
|
||||
isMsgSend,
|
||||
LcdClient,
|
||||
makeSignBytes,
|
||||
makeStdSignDoc,
|
||||
MsgSend,
|
||||
Secp256k1Wallet,
|
||||
} from "@cosmjs/launchpad";
|
||||
@ -103,8 +103,8 @@ describe("CosmWasmClient.searchTx", () => {
|
||||
};
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const chainId = await client.getChainId();
|
||||
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(alice.address0, signBytes);
|
||||
const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(alice.address0, signDoc);
|
||||
const tx: CosmosSdkTx = {
|
||||
type: "cosmos-sdk/StdTx",
|
||||
value: {
|
||||
|
||||
@ -3,7 +3,7 @@ import { Sha256 } from "@cosmjs/crypto";
|
||||
import { Bech32, fromHex, fromUtf8, toAscii, toBase64 } from "@cosmjs/encoding";
|
||||
import {
|
||||
assertIsBroadcastTxSuccess,
|
||||
makeSignBytes,
|
||||
makeStdSignDoc,
|
||||
MsgSend,
|
||||
Secp256k1Wallet,
|
||||
StdFee,
|
||||
@ -236,8 +236,8 @@ describe("CosmWasmClient", () => {
|
||||
|
||||
const chainId = await client.getChainId();
|
||||
const { accountNumber, sequence } = await client.getSequence(alice.address0);
|
||||
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(alice.address0, signBytes);
|
||||
const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(alice.address0, signDoc);
|
||||
const signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
coin,
|
||||
coins,
|
||||
LcdClient,
|
||||
makeSignBytes,
|
||||
makeStdSignDoc,
|
||||
OfflineSigner,
|
||||
Secp256k1Wallet,
|
||||
setupAuthExtension,
|
||||
@ -125,8 +125,8 @@ async function executeContract(
|
||||
};
|
||||
|
||||
const { account_number, sequence } = (await client.auth.account(alice.address0)).result.value;
|
||||
const signBytes = makeSignBytes([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature = await signer.sign(alice.address0, signBytes);
|
||||
const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature = await signer.sign(alice.address0, signDoc);
|
||||
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
||||
return client.broadcastTx(signedTx);
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
GasLimits,
|
||||
GasPrice,
|
||||
isBroadcastTxFailure,
|
||||
makeSignBytes,
|
||||
makeStdSignDoc,
|
||||
Msg,
|
||||
MsgSend,
|
||||
OfflineSigner,
|
||||
@ -360,8 +360,8 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<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 signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await this.signer.sign(this.senderAddress, signDoc);
|
||||
const signedTx: StdTx = {
|
||||
msg: msgs,
|
||||
fee: fee,
|
||||
|
||||
@ -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, makeStdSignDoc, StdFee, StdSignature } from "@cosmjs/launchpad";
|
||||
|
||||
import { LedgerSigner } from "../ledgersigner";
|
||||
|
||||
@ -48,7 +48,7 @@ export async function sign(
|
||||
},
|
||||
},
|
||||
];
|
||||
const signBytes = makeSignBytes(
|
||||
const signDoc = makeStdSignDoc(
|
||||
msgs,
|
||||
defaultFee,
|
||||
defaultChainId,
|
||||
@ -56,5 +56,5 @@ export async function sign(
|
||||
accountNumber,
|
||||
defaultSequence,
|
||||
);
|
||||
return signer.sign(fromAddress, signBytes);
|
||||
return signer.sign(fromAddress, signDoc);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -5,7 +5,9 @@ import {
|
||||
makeCosmoshubPath,
|
||||
OfflineSigner,
|
||||
StdSignature,
|
||||
StdSignDoc,
|
||||
} from "@cosmjs/launchpad";
|
||||
import { serializeSignDoc } from "@cosmjs/launchpad";
|
||||
|
||||
import { LaunchpadLedger, LaunchpadLedgerOptions } from "./launchpadledger";
|
||||
|
||||
@ -34,14 +36,15 @@ export class LedgerSigner implements OfflineSigner {
|
||||
return this.accounts;
|
||||
}
|
||||
|
||||
public async sign(address: string, message: Uint8Array): Promise<StdSignature> {
|
||||
public async sign(signerAddress: string, signDoc: StdSignDoc): Promise<StdSignature> {
|
||||
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);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AccountData, OfflineSigner, StdSignature } from "@cosmjs/launchpad";
|
||||
import { AccountData, OfflineSigner, StdSignature, StdSignDoc } from "@cosmjs/launchpad";
|
||||
import { LaunchpadLedgerOptions } from "./launchpadledger";
|
||||
export declare class LedgerSigner implements OfflineSigner {
|
||||
private readonly ledger;
|
||||
@ -6,5 +6,5 @@ export declare class LedgerSigner implements OfflineSigner {
|
||||
private accounts?;
|
||||
constructor(options?: LaunchpadLedgerOptions);
|
||||
getAccounts(): Promise<readonly AccountData[]>;
|
||||
sign(address: string, message: Uint8Array): Promise<StdSignature>;
|
||||
sign(signerAddress: string, signDoc: StdSignDoc): Promise<StdSignature>;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coins } from "./coins";
|
||||
import { CosmosClient, isBroadcastTxFailure } from "./cosmosclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeStdSignDoc } from "./encoding";
|
||||
import { LcdClient } from "./lcdapi";
|
||||
import { isMsgSend, MsgSend } from "./msgs";
|
||||
import { Secp256k1Wallet } from "./secp256k1wallet";
|
||||
@ -55,8 +55,8 @@ describe("CosmosClient.searchTx", () => {
|
||||
};
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const chainId = await client.getChainId();
|
||||
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signBytes);
|
||||
const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signDoc);
|
||||
const tx: CosmosSdkTx = {
|
||||
type: "cosmos-sdk/StdTx",
|
||||
value: {
|
||||
|
||||
@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { assertIsBroadcastTxSuccess, CosmosClient, PrivateCosmosClient } from "./cosmosclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeStdSignDoc } from "./encoding";
|
||||
import { findAttribute } from "./logs";
|
||||
import { MsgSend } from "./msgs";
|
||||
import { Secp256k1Wallet } from "./secp256k1wallet";
|
||||
@ -229,8 +229,8 @@ describe("CosmosClient", () => {
|
||||
|
||||
const chainId = await client.getChainId();
|
||||
const { accountNumber, sequence } = await client.getSequence(faucet.address);
|
||||
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signBytes);
|
||||
const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signDoc);
|
||||
const signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
|
||||
@ -4,7 +4,7 @@ import { sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coin, coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeStdSignDoc } from "../encoding";
|
||||
import { MsgDelegate } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
import { SigningCosmosClient } from "../signingcosmosclient";
|
||||
@ -45,8 +45,8 @@ describe("DistributionExtension", () => {
|
||||
};
|
||||
const memo = "Test delegation for wasmd";
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signBytes);
|
||||
const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signDoc);
|
||||
const tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
|
||||
@ -3,7 +3,7 @@ import { sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeStdSignDoc } from "../encoding";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
import { SigningCosmosClient } from "../signingcosmosclient";
|
||||
import {
|
||||
@ -50,7 +50,7 @@ describe("GovExtension", () => {
|
||||
};
|
||||
const proposalMemo = "Test proposal for wasmd";
|
||||
const { accountNumber: proposalAccountNumber, sequence: proposalSequence } = await client.getSequence();
|
||||
const proposalSignBytes = makeSignBytes(
|
||||
const proposalSignDoc = makeStdSignDoc(
|
||||
[proposalMsg],
|
||||
defaultFee,
|
||||
chainId,
|
||||
@ -58,7 +58,7 @@ describe("GovExtension", () => {
|
||||
proposalAccountNumber,
|
||||
proposalSequence,
|
||||
);
|
||||
const proposalSignature = await wallet.sign(faucet.address, proposalSignBytes);
|
||||
const proposalSignature = await wallet.sign(faucet.address, proposalSignDoc);
|
||||
const proposalTx = {
|
||||
msg: [proposalMsg],
|
||||
fee: defaultFee,
|
||||
@ -82,7 +82,7 @@ describe("GovExtension", () => {
|
||||
};
|
||||
const voteMemo = "Test vote for wasmd";
|
||||
const { accountNumber: voteAccountNumber, sequence: voteSequence } = await client.getSequence();
|
||||
const voteSignBytes = makeSignBytes(
|
||||
const voteSignDoc = makeStdSignDoc(
|
||||
[voteMsg],
|
||||
defaultFee,
|
||||
chainId,
|
||||
@ -90,7 +90,7 @@ describe("GovExtension", () => {
|
||||
voteAccountNumber,
|
||||
voteSequence,
|
||||
);
|
||||
const voteSignature = await wallet.sign(faucet.address, voteSignBytes);
|
||||
const voteSignature = await wallet.sign(faucet.address, voteSignDoc);
|
||||
const voteTx = {
|
||||
msg: [voteMsg],
|
||||
fee: defaultFee,
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { Coin } from "../coins";
|
||||
import { isBroadcastTxFailure } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeStdSignDoc } from "../encoding";
|
||||
import { parseLogs } from "../logs";
|
||||
import { MsgSend } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
@ -239,8 +239,8 @@ describe("LcdClient", () => {
|
||||
};
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const chainId = await client.getChainId();
|
||||
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signBytes);
|
||||
const signDoc = makeStdSignDoc([sendMsg], fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signDoc);
|
||||
const signedTx = {
|
||||
msg: [sendMsg],
|
||||
fee: fee,
|
||||
@ -537,8 +537,8 @@ describe("LcdClient", () => {
|
||||
const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension);
|
||||
const { account_number, sequence } = (await client.auth.account(faucet.address)).result.value;
|
||||
|
||||
const signBytes = makeSignBytes([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signBytes);
|
||||
const signDoc = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signDoc);
|
||||
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
|
||||
const result = await client.broadcastTx(signedTx);
|
||||
expect(result.code).toBeUndefined();
|
||||
@ -594,12 +594,12 @@ describe("LcdClient", () => {
|
||||
const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value;
|
||||
const { account_number: an3, sequence: sequence3 } = (await client.auth.account(address3)).result.value;
|
||||
|
||||
const signBytes1 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signBytes2 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signBytes3 = makeSignBytes([theMsg], fee, wasmd.chainId, memo, an3, sequence3);
|
||||
const signature1 = await account1.sign(address1, signBytes1);
|
||||
const signature2 = await account2.sign(address2, signBytes2);
|
||||
const signature3 = await account3.sign(address3, signBytes3);
|
||||
const signDoc1 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signDoc2 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signDoc3 = makeStdSignDoc([theMsg], fee, wasmd.chainId, memo, an3, sequence3);
|
||||
const signature1 = await account1.sign(address1, signDoc1);
|
||||
const signature2 = await account2.sign(address2, signDoc2);
|
||||
const signature3 = await account3.sign(address3, signDoc3);
|
||||
const signedTx = {
|
||||
msg: [theMsg],
|
||||
fee: fee,
|
||||
@ -658,13 +658,13 @@ describe("LcdClient", () => {
|
||||
const client = LcdClient.withExtensions({ apiUrl: wasmd.endpoint }, setupAuthExtension);
|
||||
const { account_number, sequence } = (await client.auth.account(walletAddress)).result.value;
|
||||
|
||||
const signBytes = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature1 = await wallet.sign(walletAddress, signBytes);
|
||||
const signDoc = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, account_number, sequence);
|
||||
const signature = await wallet.sign(walletAddress, signDoc);
|
||||
const signedTx = {
|
||||
msg: [msg1, msg2],
|
||||
fee: fee,
|
||||
memo: memo,
|
||||
signatures: [signature1],
|
||||
signatures: [signature],
|
||||
};
|
||||
const broadcastResult = await client.broadcastTx(signedTx);
|
||||
expect(broadcastResult.code).toBeUndefined();
|
||||
@ -722,10 +722,10 @@ describe("LcdClient", () => {
|
||||
const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value;
|
||||
const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value;
|
||||
|
||||
const signBytes1 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signBytes2 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signBytes1);
|
||||
const signature2 = await account2.sign(address2, signBytes2);
|
||||
const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signDoc1);
|
||||
const signature2 = await account2.sign(address2, signDoc2);
|
||||
const signedTx = {
|
||||
msg: [msg2, msg1],
|
||||
fee: fee,
|
||||
@ -793,10 +793,10 @@ describe("LcdClient", () => {
|
||||
const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value;
|
||||
const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value;
|
||||
|
||||
const signBytes1 = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signBytes2 = makeSignBytes([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signBytes1);
|
||||
const signature2 = await account2.sign(address2, signBytes2);
|
||||
const signDoc1 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signDoc2 = makeStdSignDoc([msg1, msg2], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signDoc1);
|
||||
const signature2 = await account2.sign(address2, signDoc2);
|
||||
const signedTx = {
|
||||
msg: [msg1, msg2],
|
||||
fee: fee,
|
||||
@ -859,10 +859,10 @@ describe("LcdClient", () => {
|
||||
const { account_number: an1, sequence: sequence1 } = (await client.auth.account(address1)).result.value;
|
||||
const { account_number: an2, sequence: sequence2 } = (await client.auth.account(address2)).result.value;
|
||||
|
||||
const signBytes1 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signBytes2 = makeSignBytes([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signBytes1);
|
||||
const signature2 = await account2.sign(address2, signBytes2);
|
||||
const signDoc1 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an1, sequence1);
|
||||
const signDoc2 = makeStdSignDoc([msg2, msg1], fee, wasmd.chainId, memo, an2, sequence2);
|
||||
const signature1 = await account1.sign(address1, signDoc1);
|
||||
const signature2 = await account2.sign(address2, signDoc2);
|
||||
const signedTx = {
|
||||
msg: [msg2, msg1],
|
||||
fee: fee,
|
||||
|
||||
@ -3,7 +3,7 @@ import { assert, sleep } from "@cosmjs/utils";
|
||||
|
||||
import { coin, coins } from "../coins";
|
||||
import { assertIsBroadcastTxSuccess } from "../cosmosclient";
|
||||
import { makeSignBytes } from "../encoding";
|
||||
import { makeStdSignDoc } from "../encoding";
|
||||
import { MsgDelegate, MsgUndelegate } from "../msgs";
|
||||
import { Secp256k1Wallet } from "../secp256k1wallet";
|
||||
import { SigningCosmosClient } from "../signingcosmosclient";
|
||||
@ -46,8 +46,8 @@ describe("StakingExtension", () => {
|
||||
};
|
||||
const memo = "Test delegation for wasmd";
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signBytes);
|
||||
const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signDoc);
|
||||
const tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
@ -69,8 +69,8 @@ describe("StakingExtension", () => {
|
||||
};
|
||||
const memo = "Test undelegation for wasmd";
|
||||
const { accountNumber, sequence } = await client.getSequence();
|
||||
const signBytes = makeSignBytes([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signBytes);
|
||||
const signDoc = makeStdSignDoc([msg], defaultFee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await wallet.sign(faucet.address, signDoc);
|
||||
const tx = {
|
||||
msg: [msg],
|
||||
fee: defaultFee,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto";
|
||||
import { fromBase64, fromHex, toAscii } from "@cosmjs/encoding";
|
||||
import { fromBase64, fromHex } from "@cosmjs/encoding";
|
||||
|
||||
import { serializeSignDoc, StdSignDoc } from "./encoding";
|
||||
import { extractKdfConfiguration, Secp256k1Wallet } from "./secp256k1wallet";
|
||||
import { base64Matcher } from "./testutils.spec";
|
||||
import { executeKdf, KdfConfiguration } from "./wallet";
|
||||
@ -110,11 +112,18 @@ describe("Secp256k1Wallet", () => {
|
||||
describe("sign", () => {
|
||||
it("resolves to valid signature if enabled", async () => {
|
||||
const wallet = await Secp256k1Wallet.fromMnemonic(defaultMnemonic);
|
||||
const message = toAscii("foo bar");
|
||||
const signature = await wallet.sign(defaultAddress, message);
|
||||
const signDoc: StdSignDoc = {
|
||||
msgs: [],
|
||||
fee: { amount: [], gas: "23" },
|
||||
chain_id: "foochain",
|
||||
memo: "hello, world",
|
||||
account_number: "7",
|
||||
sequence: "54",
|
||||
};
|
||||
const signature = await wallet.sign(defaultAddress, signDoc);
|
||||
const valid = await Secp256k1.verifySignature(
|
||||
Secp256k1Signature.fromFixedLength(fromBase64(signature.signature)),
|
||||
new Sha256(message).digest(),
|
||||
new Sha256(serializeSignDoc(signDoc)).digest(),
|
||||
defaultPubkey,
|
||||
);
|
||||
expect(valid).toEqual(true);
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
pathToString,
|
||||
Random,
|
||||
Secp256k1,
|
||||
Sha256,
|
||||
Slip10,
|
||||
Slip10Curve,
|
||||
stringToPath,
|
||||
@ -13,8 +14,9 @@ import { fromBase64, fromUtf8, toBase64, toUtf8 } from "@cosmjs/encoding";
|
||||
import { assert, isNonNullObject } from "@cosmjs/utils";
|
||||
|
||||
import { rawSecp256k1PubkeyToAddress } from "./address";
|
||||
import { serializeSignDoc, StdSignDoc } from "./encoding";
|
||||
import { encodeSecp256k1Signature } from "./signature";
|
||||
import { AccountData, OfflineSigner, PrehashType } from "./signer";
|
||||
import { AccountData, OfflineSigner } from "./signer";
|
||||
import { StdSignature } from "./types";
|
||||
import {
|
||||
decrypt,
|
||||
@ -23,7 +25,6 @@ import {
|
||||
executeKdf,
|
||||
KdfConfiguration,
|
||||
makeCosmoshubPath,
|
||||
prehash,
|
||||
supportedAlgorithms,
|
||||
} from "./wallet";
|
||||
|
||||
@ -255,16 +256,12 @@ export class Secp256k1Wallet implements OfflineSigner {
|
||||
];
|
||||
}
|
||||
|
||||
public async sign(
|
||||
address: string,
|
||||
message: Uint8Array,
|
||||
prehashType: PrehashType = "sha256",
|
||||
): Promise<StdSignature> {
|
||||
if (address !== this.address) {
|
||||
throw new Error(`Address ${address} not found in wallet`);
|
||||
public async sign(signerAddress: string, signDoc: StdSignDoc): Promise<StdSignature> {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { StdSignature } from "./types";
|
||||
|
||||
export type PrehashType = "sha256" | "sha512" | null;
|
||||
@ -19,6 +20,13 @@ export interface OfflineSigner {
|
||||
|
||||
/**
|
||||
* Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled.
|
||||
*
|
||||
* @param signerAddress The address of the account that should sign the transaction
|
||||
* @param signDoc The content that should be signed
|
||||
*/
|
||||
readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
|
||||
readonly sign: (
|
||||
signerAddress: string,
|
||||
signDoc: StdSignDoc,
|
||||
prehashType?: PrehashType,
|
||||
) => Promise<StdSignature>;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Coin } from "./coins";
|
||||
import { Account, BroadcastTxResult, CosmosClient, GetSequenceResult } from "./cosmosclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { makeStdSignDoc } from "./encoding";
|
||||
import { buildFeeTable, FeeTable, GasLimits, GasPrice } from "./gas";
|
||||
import { BroadcastMode } from "./lcdapi";
|
||||
import { Msg, MsgSend } from "./msgs";
|
||||
@ -88,8 +88,8 @@ export class SigningCosmosClient extends CosmosClient {
|
||||
public async signAndBroadcast(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<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 signDoc = makeStdSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||
const signature = await this.signer.sign(this.senderAddress, signDoc);
|
||||
const signedTx: StdTx = {
|
||||
msg: msgs,
|
||||
fee: fee,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { HdPath } from "@cosmjs/crypto";
|
||||
import { AccountData, OfflineSigner, PrehashType } from "./signer";
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { AccountData, OfflineSigner } from "./signer";
|
||||
import { StdSignature } from "./types";
|
||||
import { EncryptionConfiguration, KdfConfiguration } from "./wallet";
|
||||
/**
|
||||
@ -86,7 +87,7 @@ export declare class Secp256k1Wallet implements OfflineSigner {
|
||||
get mnemonic(): string;
|
||||
private get address();
|
||||
getAccounts(): Promise<readonly AccountData[]>;
|
||||
sign(address: string, message: Uint8Array, prehashType?: PrehashType): Promise<StdSignature>;
|
||||
sign(signerAddress: string, signDoc: StdSignDoc): Promise<StdSignature>;
|
||||
/**
|
||||
* Generates an encrypted serialization of this wallet.
|
||||
*
|
||||
|
||||
10
packages/launchpad/types/signer.d.ts
vendored
10
packages/launchpad/types/signer.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { StdSignature } from "./types";
|
||||
export declare type PrehashType = "sha256" | "sha512" | null;
|
||||
export declare type Algo = "secp256k1" | "ed25519" | "sr25519";
|
||||
@ -14,6 +15,13 @@ export interface OfflineSigner {
|
||||
readonly getAccounts: () => Promise<readonly AccountData[]>;
|
||||
/**
|
||||
* Request signature from whichever key corresponds to provided bech32-encoded address. Rejects if not enabled.
|
||||
*
|
||||
* @param signerAddress The address of the account that should sign the transaction
|
||||
* @param signDoc The content that should be signed
|
||||
*/
|
||||
readonly sign: (address: string, message: Uint8Array, prehashType?: PrehashType) => Promise<StdSignature>;
|
||||
readonly sign: (
|
||||
signerAddress: string,
|
||||
signDoc: StdSignDoc,
|
||||
prehashType?: PrehashType,
|
||||
) => Promise<StdSignature>;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user