Add SigningCosmWasmClient.signAndPost

This commit is contained in:
Simon Warta 2020-07-27 09:34:38 +02:00
parent 3cfe3c0b94
commit 09ad90c9af
5 changed files with 68 additions and 87 deletions

View File

@ -5,6 +5,9 @@
- @cosmjs/cosmwasm: Rename `CosmWasmClient.getNonce` method to `.getSequence`. - @cosmjs/cosmwasm: Rename `CosmWasmClient.getNonce` method to `.getSequence`.
- @cosmjs/cosmwasm: Remove `RestClient` class in favour of new modular - @cosmjs/cosmwasm: Remove `RestClient` class in favour of new modular
`LcdClient` class from @cosmjs/sdk38. `LcdClient` class from @cosmjs/sdk38.
- @cosmjs/cosmwasm: Add `SigningCosmWasmClient.signAndPost` as a mid-level
abstraction between `SigningCosmWasmClient.upload`/`.instantiate`/`.execute`
and `.postTx`.
- @cosmjs/sdk38: Rename `CosmosClient.getNonce` method to `.getSequence`. - @cosmjs/sdk38: Rename `CosmosClient.getNonce` method to `.getSequence`.
- @cosmjs/sdk38: Remove `RestClient` class in favour of new modular `LcdClient` - @cosmjs/sdk38: Remove `RestClient` class in favour of new modular `LcdClient`
class. class.

View File

@ -1,13 +1,28 @@
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
import { Sha256 } from "@cosmjs/crypto"; import { Sha256 } from "@cosmjs/crypto";
import { toHex } from "@cosmjs/encoding"; import { toHex } from "@cosmjs/encoding";
import { AuthExtension, coin, coins, LcdClient, Secp256k1Wallet, setupAuthExtension } from "@cosmjs/sdk38"; import {
AuthExtension,
coin,
coins,
LcdClient,
MsgDelegate,
Secp256k1Wallet,
setupAuthExtension,
} from "@cosmjs/sdk38";
import { assert } from "@cosmjs/utils"; import { assert } from "@cosmjs/utils";
import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient"; import { isPostTxFailure, PrivateCosmWasmClient } from "./cosmwasmclient";
import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm"; import { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient"; import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient";
import { alice, getHackatom, makeRandomAddress, pendingWithoutWasmd, unused } from "./testutils.spec"; import {
alice,
getHackatom,
makeRandomAddress,
pendingWithoutWasmd,
unused,
validatorAddress,
} from "./testutils.spec";
const httpUrl = "http://localhost:1317"; const httpUrl = "http://localhost:1317";
@ -327,4 +342,27 @@ describe("SigningCosmWasmClient", () => {
expect(after.balance).toEqual(transferAmount); expect(after.balance).toEqual(transferAmount);
}); });
}); });
describe("signAndPost", () => {
it("works", async () => {
pendingWithoutWasmd();
const wallet = await Secp256k1Wallet.fromMnemonic(alice.mnemonic);
const client = new SigningCosmWasmClient(httpUrl, alice.address0, wallet);
const msg: MsgDelegate = {
type: "cosmos-sdk/MsgDelegate",
value: {
delegator_address: alice.address0,
validator_address: validatorAddress,
amount: coin(1234, "ustake"),
},
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "120000", // 120k
};
const result = await client.signAndPost([msg], fee, "Use your power wisely");
assert(!isPostTxFailure(result));
});
});
}); });

View File

@ -7,6 +7,7 @@ import {
Coin, Coin,
coins, coins,
makeSignBytes, makeSignBytes,
Msg,
MsgSend, MsgSend,
OfflineSigner, OfflineSigner,
StdFee, StdFee,
@ -219,19 +220,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
builder: builder, builder: builder,
}, },
}; };
const fee = this.fees.upload; const result = await this.signAndPost([storeCodeMsg], this.fees.upload, memo);
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [storeCodeMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -264,21 +253,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
admin: options.admin, admin: options.admin,
}, },
}; };
const memo = options.memo || ""; const result = await this.signAndPost([instantiateMsg], this.fees.init, options.memo);
const fee = this.fees.init;
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [instantiateMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -299,19 +274,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
new_admin: newAdmin, new_admin: newAdmin,
}, },
}; };
const fee = this.fees.changeAdmin; const result = await this.signAndPost([updateAdminMsg], this.fees.changeAdmin, memo);
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([updateAdminMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [updateAdminMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -329,19 +292,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
contract: contractAddress, contract: contractAddress,
}, },
}; };
const fee = this.fees.changeAdmin; const result = await this.signAndPost([clearAdminMsg], this.fees.changeAdmin, memo);
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([clearAdminMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [clearAdminMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -366,19 +317,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
msg: migrateMsg, msg: migrateMsg,
}, },
}; };
const fee = this.fees.migrate; const result = await this.signAndPost([msg], this.fees.migrate, memo);
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([msg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [msg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -403,19 +342,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
sent_funds: transferAmount || [], sent_funds: transferAmount || [],
}, },
}; };
const fee = this.fees.exec; const result = await this.signAndPost([executeMsg], this.fees.exec, memo);
const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId();
const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = {
msg: [executeMsg],
fee: fee,
memo: memo,
signatures: [signature],
};
const result = await this.postTx(signedTx);
if (isPostTxFailure(result)) { if (isPostTxFailure(result)) {
throw new Error(createPostTxErrorMessage(result)); throw new Error(createPostTxErrorMessage(result));
} }
@ -438,18 +365,24 @@ export class SigningCosmWasmClient extends CosmWasmClient {
amount: transferAmount, amount: transferAmount,
}, },
}; };
const fee = this.fees.send; return this.signAndPost([sendMsg], this.fees.send, memo);
}
/**
* Gets account number and sequence from the API, creates a sign doc,
* creates a single signature, assembles the signed transaction and broadcasts it.
*/
public async signAndPost(msgs: readonly Msg[], fee: StdFee, memo = ""): Promise<PostTxResult> {
const { accountNumber, sequence } = await this.getSequence(); const { accountNumber, sequence } = await this.getSequence();
const chainId = await this.getChainId(); const chainId = await this.getChainId();
const signBytes = makeSignBytes([sendMsg], fee, chainId, memo, accountNumber, sequence); const signBytes = makeSignBytes(msgs, fee, chainId, memo, accountNumber, sequence);
const signature = await this.signer.sign(this.senderAddress, signBytes); const signature = await this.signer.sign(this.senderAddress, signBytes);
const signedTx: StdTx = { const signedTx: StdTx = {
msg: [sendMsg], msg: msgs,
fee: fee, fee: fee,
memo: memo, memo: memo,
signatures: [signature], signatures: [signature],
}; };
return this.postTx(signedTx); return this.postTx(signedTx);
} }
} }

View File

@ -47,6 +47,8 @@ export const wasmd = {
chainId: "testing", chainId: "testing",
}; };
export const validatorAddress = "cosmosvaloper1gjvanqxc774u6ed9thj4gpn9gj5zus5u32enqn";
export const alice = { export const alice = {
mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park", mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park",
pubkey0: { pubkey0: {

View File

@ -1,4 +1,4 @@
import { BroadcastMode, Coin, OfflineSigner, StdFee, StdSignature } from "@cosmjs/sdk38"; import { BroadcastMode, Coin, Msg, OfflineSigner, StdFee, StdSignature } from "@cosmjs/sdk38";
import { Account, CosmWasmClient, GetSequenceResult, PostTxResult } from "./cosmwasmclient"; import { Account, CosmWasmClient, GetSequenceResult, PostTxResult } from "./cosmwasmclient";
import { Log } from "./logs"; import { Log } from "./logs";
export interface SigningCallback { export interface SigningCallback {
@ -124,4 +124,9 @@ export declare class SigningCosmWasmClient extends CosmWasmClient {
transferAmount?: readonly Coin[], transferAmount?: readonly Coin[],
): Promise<ExecuteResult>; ): Promise<ExecuteResult>;
sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise<PostTxResult>; sendTokens(recipientAddress: string, transferAmount: readonly Coin[], memo?: string): Promise<PostTxResult>;
/**
* Gets account number and sequence from the API, creates a sign doc,
* creates a single signature, assembles the signed transaction and broadcasts it.
*/
signAndPost(msgs: readonly Msg[], fee: StdFee, memo?: string): Promise<PostTxResult>;
} }