mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-11 14:09:15 +00:00
Merge pull request #564 from cosmos/561-stargate-signed-data-signandbroadcast
Use signed data in stargate client signAndBroadcast
This commit is contained in:
commit
f9550b828f
@ -12,6 +12,7 @@
|
||||
- @cosmjs/launchpad-ledger: `LedgerSigner.sign` method renamed `signAmino`.
|
||||
- @cosmjs/proto-signing: Add new package for handling transaction signing with
|
||||
protobuf encoding.
|
||||
- @cosmjs/proto-signing: Expose `DirectSignResponse` interface.
|
||||
- @cosmjs/stargate: Add new package for Cosmos SDK Stargate support.
|
||||
- @cosmjs/tendermint-rpc: Make `Client.detectVersion` private and let it return
|
||||
a version instead of a client.
|
||||
|
@ -223,7 +223,7 @@ export class Secp256k1HdWallet implements OfflineSigner {
|
||||
private readonly pubkey: Uint8Array;
|
||||
private readonly privkey: Uint8Array;
|
||||
|
||||
private constructor(
|
||||
protected constructor(
|
||||
mnemonic: EnglishMnemonic,
|
||||
hdPath: HdPath,
|
||||
privkey: Uint8Array,
|
||||
|
10
packages/launchpad/types/secp256k1hdwallet.d.ts
vendored
10
packages/launchpad/types/secp256k1hdwallet.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { HdPath } from "@cosmjs/crypto";
|
||||
import { EnglishMnemonic, HdPath } from "@cosmjs/crypto";
|
||||
import { StdSignDoc } from "./encoding";
|
||||
import { AccountData, AminoSignResponse, OfflineSigner } from "./signer";
|
||||
import { EncryptionConfiguration, KdfConfiguration } from "./wallet";
|
||||
@ -66,7 +66,13 @@ export declare class Secp256k1HdWallet implements OfflineSigner {
|
||||
/** Derived data */
|
||||
private readonly pubkey;
|
||||
private readonly privkey;
|
||||
private constructor();
|
||||
protected constructor(
|
||||
mnemonic: EnglishMnemonic,
|
||||
hdPath: HdPath,
|
||||
privkey: Uint8Array,
|
||||
pubkey: Uint8Array,
|
||||
prefix: string,
|
||||
);
|
||||
get mnemonic(): string;
|
||||
private get address();
|
||||
getAccounts(): Promise<readonly AccountData[]>;
|
||||
|
@ -80,7 +80,7 @@ export class DirectSecp256k1HdWallet implements OfflineDirectSigner {
|
||||
private readonly pubkey: Uint8Array;
|
||||
private readonly privkey: Uint8Array;
|
||||
|
||||
private constructor(
|
||||
protected constructor(
|
||||
mnemonic: EnglishMnemonic,
|
||||
hdPath: HdPath,
|
||||
privkey: Uint8Array,
|
||||
|
@ -4,5 +4,5 @@ export { EncodeObject, Registry } from "./registry";
|
||||
export { DirectSecp256k1HdWallet } from "./directsecp256k1hdwallet";
|
||||
export { DirectSecp256k1Wallet } from "./directsecp256k1wallet";
|
||||
export { decodePubkey, encodePubkey } from "./pubkey";
|
||||
export { isOfflineDirectSigner, OfflineDirectSigner, OfflineSigner } from "./signer";
|
||||
export { DirectSignResponse, isOfflineDirectSigner, OfflineDirectSigner, OfflineSigner } from "./signer";
|
||||
export { makeAuthInfoBytes, makeSignBytes, makeSignDoc } from "./signing";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { HdPath } from "@cosmjs/crypto";
|
||||
import { EnglishMnemonic, HdPath } from "@cosmjs/crypto";
|
||||
import { AccountData } from "@cosmjs/launchpad";
|
||||
import { cosmos } from "./codec";
|
||||
import { DirectSignResponse, OfflineDirectSigner } from "./signer";
|
||||
@ -31,7 +31,13 @@ export declare class DirectSecp256k1HdWallet implements OfflineDirectSigner {
|
||||
/** Derived data */
|
||||
private readonly pubkey;
|
||||
private readonly privkey;
|
||||
private constructor();
|
||||
protected constructor(
|
||||
mnemonic: EnglishMnemonic,
|
||||
hdPath: HdPath,
|
||||
privkey: Uint8Array,
|
||||
pubkey: Uint8Array,
|
||||
prefix: string,
|
||||
);
|
||||
get mnemonic(): string;
|
||||
private get address();
|
||||
getAccounts(): Promise<readonly AccountData[]>;
|
||||
|
2
packages/proto-signing/types/index.d.ts
vendored
2
packages/proto-signing/types/index.d.ts
vendored
@ -4,5 +4,5 @@ export { EncodeObject, Registry } from "./registry";
|
||||
export { DirectSecp256k1HdWallet } from "./directsecp256k1hdwallet";
|
||||
export { DirectSecp256k1Wallet } from "./directsecp256k1wallet";
|
||||
export { decodePubkey, encodePubkey } from "./pubkey";
|
||||
export { isOfflineDirectSigner, OfflineDirectSigner, OfflineSigner } from "./signer";
|
||||
export { DirectSignResponse, isOfflineDirectSigner, OfflineDirectSigner, OfflineSigner } from "./signer";
|
||||
export { makeAuthInfoBytes, makeSignBytes, makeSignDoc } from "./signing";
|
||||
|
@ -1,27 +1,36 @@
|
||||
const typeRegister: Record<string, string> = {
|
||||
"/cosmos.bank.v1beta1.MsgSend": "cosmos-sdk/MsgSend",
|
||||
"/cosmos.bank.v1beta1.MsgMultiSend": "cosmos-sdk/MsgMultiSend",
|
||||
"/cosmos.crisis.v1beta1.MsgVerifyInvariant": "cosmos-sdk/MsgVerifyInvariant",
|
||||
"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress": "cosmos-sdk/MsgSetWithdrawAddress",
|
||||
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": "cosmos-sdk/MsgWithdrawDelegatorReward",
|
||||
"/cosmos.distribution.v1beta1.MsgWithdrawValidatorComission": "cosmos-sdk/MsgWithdrawValidatorComission",
|
||||
"/cosmos.distribution.v1beta1.MsgFundCommunityPool": "cosmos-sdk/MsgFundCommunityPool",
|
||||
"/cosmos.evidence.v1beta1.MsgSubmitEvidence": "cosmos-sdk/MsgSubmitEvidence",
|
||||
"/cosmos.gov.v1beta1.MsgSubmitProposal": "cosmos-sdk/MsgSubmitProposal",
|
||||
"/cosmos.gov.v1beta1.MsgVote": "cosmos-sdk/MsgVote",
|
||||
"/cosmos.gov.v1beta1.MsgDeposit": "cosmos-sdk/MsgDeposit",
|
||||
"/cosmos.slashing.v1beta1.MsgUnjail": "cosmos-sdk/MsgUnjail",
|
||||
"/cosmos.staking.v1beta1.MsgCreateValidator": "cosmos-sdk/MsgCreateValidator",
|
||||
"/cosmos.staking.v1beta1.MsgEditValidator": "cosmos-sdk/MsgEditValidator",
|
||||
"/cosmos.staking.v1beta1.MsgDelegate": "cosmos-sdk/MsgDelegate",
|
||||
"/cosmos.staking.v1beta1.MsgBeginRedelegate": "cosmos-sdk/MsgBeginRedelegate",
|
||||
"/cosmos.staking.v1beta1.MsgUndelegate": "cosmos-sdk/MsgUndelegate",
|
||||
"/cosmos.vesting.v1beta1.MsgCreateVestingAccount": "cosmos-sdk/MsgCreateVestingAccount",
|
||||
};
|
||||
|
||||
export function getMsgType(typeUrl: string): string {
|
||||
const typeRegister: Record<string, string> = {
|
||||
"/cosmos.bank.v1beta1.MsgSend": "cosmos-sdk/MsgSend",
|
||||
"/cosmos.bank.v1beta1.MsgMultiSend": "cosmos-sdk/MsgMultiSend",
|
||||
"/cosmos.crisis.v1beta1.MsgVerifyInvariant": "cosmos-sdk/MsgVerifyInvariant",
|
||||
"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress": "cosmos-sdk/MsgSetWithdrawAddress",
|
||||
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": "cosmos-sdk/MsgWithdrawDelegatorReward",
|
||||
"/cosmos.distribution.v1beta1.MsgWithdrawValidatorComission": "cosmos-sdk/MsgWithdrawValidatorComission",
|
||||
"/cosmos.distribution.v1beta1.MsgFundCommunityPool": "cosmos-sdk/MsgFundCommunityPool",
|
||||
"/cosmos.evidence.v1beta1.MsgSubmitEvidence": "cosmos-sdk/MsgSubmitEvidence",
|
||||
"/cosmos.gov.v1beta1.MsgSubmitProposal": "cosmos-sdk/MsgSubmitProposal",
|
||||
"/cosmos.gov.v1beta1.MsgVote": "cosmos-sdk/MsgVote",
|
||||
"/cosmos.gov.v1beta1.MsgDeposit": "cosmos-sdk/MsgDeposit",
|
||||
"/cosmos.slashing.v1beta1.MsgUnjail": "cosmos-sdk/MsgUnjail",
|
||||
"/cosmos.staking.v1beta1.MsgCreateValidator": "cosmos-sdk/MsgCreateValidator",
|
||||
"/cosmos.staking.v1beta1.MsgEditValidator": "cosmos-sdk/MsgEditValidator",
|
||||
"/cosmos.staking.v1beta1.MsgDelegate": "cosmos-sdk/MsgDelegate",
|
||||
"/cosmos.staking.v1beta1.MsgBeginRedelegate": "cosmos-sdk/MsgBeginRedelegate",
|
||||
"/cosmos.staking.v1beta1.MsgUndelegate": "cosmos-sdk/MsgUndelegate",
|
||||
"/cosmos.vesting.v1beta1.MsgCreateVestingAccount": "cosmos-sdk/MsgCreateVestingAccount",
|
||||
};
|
||||
const type = typeRegister[typeUrl];
|
||||
if (!type) {
|
||||
throw new Error("Type URL not known");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
export function getMsgTypeUrl(type: string): string {
|
||||
const [typeUrl] = Object.entries(typeRegister).find(([_typeUrl, value]) => value === type) ?? [];
|
||||
if (!typeUrl) {
|
||||
throw new Error("Type not known");
|
||||
}
|
||||
return typeUrl;
|
||||
}
|
||||
|
@ -1,13 +1,25 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { coin, coins, GasPrice, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
import { Coin, cosmosField, DirectSecp256k1HdWallet, registered, Registry } from "@cosmjs/proto-signing";
|
||||
import { assert } from "@cosmjs/utils";
|
||||
import { assert, sleep } from "@cosmjs/utils";
|
||||
import { Message } from "protobufjs";
|
||||
|
||||
import { cosmos } from "./codec";
|
||||
import { PrivateSigningStargateClient, SigningStargateClient } from "./signingstargateclient";
|
||||
import { assertIsBroadcastTxSuccess } from "./stargateclient";
|
||||
import { faucet, makeRandomAddress, pendingWithoutSimapp, simapp, validator } from "./testutils.spec";
|
||||
import {
|
||||
faucet,
|
||||
makeRandomAddress,
|
||||
ModifyingDirectSecp256k1HdWallet,
|
||||
ModifyingSecp256k1HdWallet,
|
||||
pendingWithoutSimapp,
|
||||
simapp,
|
||||
validator,
|
||||
} from "./testutils.spec";
|
||||
|
||||
const { MsgSend } = cosmos.bank.v1beta1;
|
||||
const { MsgDelegate } = cosmos.staking.v1beta1;
|
||||
const { Tx } = cosmos.tx.v1beta1;
|
||||
|
||||
describe("SigningStargateClient", () => {
|
||||
describe("constructor", () => {
|
||||
@ -33,11 +45,11 @@ describe("SigningStargateClient", () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const registry = new Registry();
|
||||
registry.register("/custom.MsgCustom", cosmos.bank.v1beta1.MsgSend);
|
||||
registry.register("/custom.MsgCustom", MsgSend);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
const openedClient = (client as unknown) as PrivateSigningStargateClient;
|
||||
expect(openedClient.registry.lookupType("/custom.MsgCustom")).toEqual(cosmos.bank.v1beta1.MsgSend);
|
||||
expect(openedClient.registry.lookupType("/custom.MsgCustom")).toEqual(MsgSend);
|
||||
});
|
||||
|
||||
it("can be constructed with custom gas price", async () => {
|
||||
@ -133,44 +145,81 @@ describe("SigningStargateClient", () => {
|
||||
});
|
||||
|
||||
describe("signAndBroadcast", () => {
|
||||
it("works with direct mode", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||
const registry = new Registry();
|
||||
registry.register(msgDelegateTypeUrl, cosmos.staking.v1beta1.MsgDelegate);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
describe("direct mode", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||
const registry = new Registry();
|
||||
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
|
||||
const msg = cosmos.staking.v1beta1.MsgDelegate.create({
|
||||
delegatorAddress: faucet.address0,
|
||||
validatorAddress: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
const msg = MsgDelegate.create({
|
||||
delegatorAddress: faucet.address0,
|
||||
validatorAddress: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
});
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "180000", // 180k
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
});
|
||||
|
||||
it("works with a modifying signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await ModifyingDirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||
const registry = new Registry();
|
||||
registry.register(msgDelegateTypeUrl, MsgDelegate);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
|
||||
const msg = MsgDelegate.create({
|
||||
delegatorAddress: faucet.address0,
|
||||
validatorAddress: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
});
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "180000", // 180k
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
|
||||
await sleep(1000);
|
||||
|
||||
const searchResult = await client.searchTx({ id: result.transactionHash });
|
||||
const tx = Tx.decode(searchResult[0].tx);
|
||||
// From ModifyingDirectSecp256k1HdWallet
|
||||
expect(tx.body!.memo).toEqual("This was modified");
|
||||
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));
|
||||
expect(tx.authInfo!.fee!.gasLimit!.toNumber()).toEqual(333333);
|
||||
});
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "180000", // 180k
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
});
|
||||
|
||||
it("works with legacy Amino mode", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const coinTypeUrl = "/cosmos.base.v1beta1.Coin";
|
||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||
describe("legacy Amino mode", () => {
|
||||
// NOTE: One registry shared between tests
|
||||
// See https://github.com/protobufjs/protobuf.js#using-decorators
|
||||
// > Decorated types reside in protobuf.roots["decorated"] using a flat structure, so no duplicate names.
|
||||
const registry = new Registry();
|
||||
registry.register(coinTypeUrl, Coin);
|
||||
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
|
||||
|
||||
@registered(registry, msgDelegateTypeUrl)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class MsgDelegate extends Message {
|
||||
class CustomMsgDelegate extends Message {
|
||||
@cosmosField.string(1)
|
||||
public readonly delegator_address?: string;
|
||||
@cosmosField.string(2)
|
||||
@ -179,25 +228,62 @@ describe("SigningStargateClient", () => {
|
||||
public readonly amount?: Coin;
|
||||
}
|
||||
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
it("works", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
|
||||
const msg = {
|
||||
delegator_address: faucet.address0,
|
||||
validator_address: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
};
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "200000",
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
const msg = {
|
||||
delegator_address: faucet.address0,
|
||||
validator_address: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
};
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "200000",
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
});
|
||||
|
||||
it("works with a modifying signer", async () => {
|
||||
pendingWithoutSimapp();
|
||||
const wallet = await ModifyingSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
|
||||
const options = { registry: registry };
|
||||
const client = await SigningStargateClient.connectWithWallet(simapp.tendermintUrl, wallet, options);
|
||||
|
||||
const msg = {
|
||||
delegator_address: faucet.address0,
|
||||
validator_address: validator.validatorAddress,
|
||||
amount: coin(1234, "ustake"),
|
||||
};
|
||||
const msgAny = {
|
||||
typeUrl: msgDelegateTypeUrl,
|
||||
value: msg,
|
||||
};
|
||||
const fee = {
|
||||
amount: coins(2000, "ucosm"),
|
||||
gas: "200000",
|
||||
};
|
||||
const memo = "Use your power wisely";
|
||||
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
|
||||
assertIsBroadcastTxSuccess(result);
|
||||
|
||||
await sleep(1000);
|
||||
|
||||
const searchResult = await client.searchTx({ id: result.transactionHash });
|
||||
const tx = Tx.decode(searchResult[0].tx);
|
||||
// From ModifyingSecp256k1HdWallet
|
||||
expect(tx.body!.memo).toEqual("This was modified");
|
||||
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));
|
||||
expect(tx.authInfo!.fee!.gasLimit!.toNumber()).toEqual(333333);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
import { adaptor34, Client as TendermintClient } from "@cosmjs/tendermint-rpc";
|
||||
|
||||
import { cosmos } from "./codec";
|
||||
import { getMsgType } from "./encoding";
|
||||
import { getMsgType, getMsgTypeUrl } from "./encoding";
|
||||
import { BroadcastTxResponse, StargateClient } from "./stargateclient";
|
||||
|
||||
const { TxRaw } = cosmos.tx.v1beta1;
|
||||
@ -123,10 +123,10 @@ export class SigningStargateClient extends StargateClient {
|
||||
if (isOfflineDirectSigner(this.signer)) {
|
||||
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence);
|
||||
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber);
|
||||
const { signature } = await this.signer.signDirect(address, signDoc);
|
||||
const { signature, signed } = await this.signer.signDirect(address, signDoc);
|
||||
const txRaw = TxRaw.create({
|
||||
bodyBytes: txBodyBytes,
|
||||
authInfoBytes: authInfoBytes,
|
||||
bodyBytes: signed.bodyBytes,
|
||||
authInfoBytes: signed.authInfoBytes,
|
||||
signatures: [fromBase64(signature.signature)],
|
||||
});
|
||||
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
||||
@ -135,17 +135,36 @@ export class SigningStargateClient extends StargateClient {
|
||||
|
||||
// Amino signer
|
||||
const signMode = cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
|
||||
const authInfoBytes = makeAuthInfoBytes([pubkeyAny], fee.amount, gasLimit, sequence, signMode);
|
||||
const msgs = messages.map((msg) => ({
|
||||
type: getMsgType(msg.typeUrl),
|
||||
value: msg.value,
|
||||
}));
|
||||
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
|
||||
const signResponse = await this.signer.signAmino(address, signDoc);
|
||||
const { signature, signed } = await this.signer.signAmino(address, signDoc);
|
||||
const signedTxBody = {
|
||||
messages: signed.msgs.map((msg) => ({
|
||||
typeUrl: getMsgTypeUrl(msg.type),
|
||||
value: msg.value,
|
||||
})),
|
||||
memo: signed.memo,
|
||||
};
|
||||
const signedTxBodyBytes = this.registry.encode({
|
||||
typeUrl: "/cosmos.tx.v1beta1.TxBody",
|
||||
value: signedTxBody,
|
||||
});
|
||||
const signedGasLimit = Int53.fromString(signed.fee.gas).toNumber();
|
||||
const signedSequence = Int53.fromString(signed.sequence).toNumber();
|
||||
const signedAuthInfoBytes = makeAuthInfoBytes(
|
||||
[pubkeyAny],
|
||||
signed.fee.amount,
|
||||
signedGasLimit,
|
||||
signedSequence,
|
||||
signMode,
|
||||
);
|
||||
const txRaw = TxRaw.create({
|
||||
bodyBytes: txBodyBytes,
|
||||
authInfoBytes: authInfoBytes,
|
||||
signatures: [fromBase64(signResponse.signature.signature)],
|
||||
bodyBytes: signedTxBodyBytes,
|
||||
authInfoBytes: signedAuthInfoBytes,
|
||||
signatures: [fromBase64(signature.signature)],
|
||||
});
|
||||
const signedTx = Uint8Array.from(TxRaw.encode(txRaw).finish());
|
||||
return this.broadcastTx(signedTx);
|
||||
|
@ -1,5 +1,18 @@
|
||||
import { Random } from "@cosmjs/crypto";
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Bip39, EnglishMnemonic, Random, Secp256k1, Slip10, Slip10Curve } from "@cosmjs/crypto";
|
||||
import { Bech32 } from "@cosmjs/encoding";
|
||||
import {
|
||||
AminoSignResponse,
|
||||
coins,
|
||||
makeCosmoshubPath,
|
||||
Secp256k1HdWallet,
|
||||
StdSignDoc,
|
||||
} from "@cosmjs/launchpad";
|
||||
import { DirectSecp256k1HdWallet, DirectSignResponse, makeAuthInfoBytes } from "@cosmjs/proto-signing";
|
||||
|
||||
import { cosmos } from "./codec";
|
||||
|
||||
const { AuthInfo, TxBody } = cosmos.tx.v1beta1;
|
||||
|
||||
export function simappEnabled(): boolean {
|
||||
return !!process.env.SIMAPP_ENABLED;
|
||||
@ -70,3 +83,86 @@ export const nonExistentAddress = "cosmos1p79apjaufyphcmsn4g07cynqf0wyjuezqu84hd
|
||||
|
||||
export const nonNegativeIntegerMatcher = /^[0-9]+$/;
|
||||
export const tendermintIdMatcher = /^[0-9A-F]{64}$/;
|
||||
|
||||
/**
|
||||
* A class for testing clients using an Amino signer which modifies the transaction it receives before signing
|
||||
*/
|
||||
export class ModifyingSecp256k1HdWallet extends Secp256k1HdWallet {
|
||||
public static async fromMnemonic(
|
||||
mnemonic: string,
|
||||
hdPath = makeCosmoshubPath(0),
|
||||
prefix = "cosmos",
|
||||
): Promise<ModifyingSecp256k1HdWallet> {
|
||||
const mnemonicChecked = new EnglishMnemonic(mnemonic);
|
||||
const seed = await Bip39.mnemonicToSeed(mnemonicChecked);
|
||||
const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, hdPath);
|
||||
const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey;
|
||||
return new ModifyingSecp256k1HdWallet(
|
||||
mnemonicChecked,
|
||||
hdPath,
|
||||
privkey,
|
||||
Secp256k1.compressPubkey(uncompressed),
|
||||
prefix,
|
||||
);
|
||||
}
|
||||
|
||||
public async signAmino(signerAddress: string, signDoc: StdSignDoc): Promise<AminoSignResponse> {
|
||||
const modifiedSignDoc = {
|
||||
...signDoc,
|
||||
fee: {
|
||||
amount: coins(3000, "ucosm"),
|
||||
gas: "333333",
|
||||
},
|
||||
memo: "This was modified",
|
||||
};
|
||||
return super.signAmino(signerAddress, modifiedSignDoc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for testing clients using a direct signer which modifies the transaction it receives before signing
|
||||
*/
|
||||
export class ModifyingDirectSecp256k1HdWallet extends DirectSecp256k1HdWallet {
|
||||
public static async fromMnemonic(
|
||||
mnemonic: string,
|
||||
hdPath = makeCosmoshubPath(0),
|
||||
prefix = "cosmos",
|
||||
): Promise<DirectSecp256k1HdWallet> {
|
||||
const mnemonicChecked = new EnglishMnemonic(mnemonic);
|
||||
const seed = await Bip39.mnemonicToSeed(mnemonicChecked);
|
||||
const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, hdPath);
|
||||
const uncompressed = (await Secp256k1.makeKeypair(privkey)).pubkey;
|
||||
return new ModifyingDirectSecp256k1HdWallet(
|
||||
mnemonicChecked,
|
||||
hdPath,
|
||||
privkey,
|
||||
Secp256k1.compressPubkey(uncompressed),
|
||||
prefix,
|
||||
);
|
||||
}
|
||||
|
||||
public async signDirect(address: string, signDoc: cosmos.tx.v1beta1.ISignDoc): Promise<DirectSignResponse> {
|
||||
const txBody = TxBody.decode(signDoc.bodyBytes!);
|
||||
const modifiedTxBody = TxBody.create({
|
||||
...txBody,
|
||||
memo: "This was modified",
|
||||
});
|
||||
const authInfo = AuthInfo.decode(signDoc.authInfoBytes!);
|
||||
const pubkeys = authInfo.signerInfos.map((signerInfo) => signerInfo.publicKey!);
|
||||
const sequence = authInfo.signerInfos[0].sequence!.toNumber();
|
||||
const modifiedFeeAmount = coins(3000, "ucosm");
|
||||
const modifiedGasLimit = 333333;
|
||||
const modifiedSignDoc = {
|
||||
...signDoc,
|
||||
bodyBytes: Uint8Array.from(TxBody.encode(modifiedTxBody).finish()),
|
||||
authInfoBytes: makeAuthInfoBytes(
|
||||
pubkeys,
|
||||
modifiedFeeAmount,
|
||||
modifiedGasLimit,
|
||||
sequence,
|
||||
cosmos.tx.signing.v1beta1.SignMode.SIGN_MODE_DIRECT,
|
||||
),
|
||||
};
|
||||
return super.signDirect(address, modifiedSignDoc);
|
||||
}
|
||||
}
|
||||
|
1
packages/stargate/types/encoding.d.ts
vendored
1
packages/stargate/types/encoding.d.ts
vendored
@ -1 +1,2 @@
|
||||
export declare function getMsgType(typeUrl: string): string;
|
||||
export declare function getMsgTypeUrl(type: string): string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user