Add "auto" option to fee

This commit is contained in:
Simon Warta 2021-11-19 00:11:10 +01:00
parent e3b18c3859
commit 86467822f9
5 changed files with 126 additions and 24 deletions

View File

@ -22,9 +22,19 @@ const rpcEndpoint = "ws://localhost:26658";
const gasPrice = GasPrice.fromString("0.025ucosm");
// Setup client
const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet);
const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet, { gasPrice: gasPrice });
// Send transaction (using sendTokens)
// Send transaction (using sendTokens with auto gas)
{
const recipient = "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5";
const amount = coins(1234567, "ucosm");
const memo = "With simulate";
const result = await client.sendTokens(account.address, recipient, amount, "auto", memo);
assertIsBroadcastTxSuccess(result);
console.log("Successfully broadcasted:", result);
}
// Send transaction (using sendTokens with manual gas)
{
const recipient = "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5";
const amount = coins(1234567, "ucosm");
@ -38,13 +48,31 @@ const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet
};
const memo = "With simulate";
const gasEstimation = await client.simulate(account.address, [sendMsg], memo);
const fee = calculateFee(Math.floor(gasEstimation * 1.3), gasPrice);
const fee = calculateFee(Math.round(gasEstimation * 1.3), gasPrice);
const result = await client.sendTokens(account.address, recipient, amount, fee, memo);
assertIsBroadcastTxSuccess(result);
console.log("Successfully broadcasted:", result);
}
// Send transaction (using signAndBroadcast)
// Send transaction (using signAndBroadcast with auto gas)
{
const recipient = "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5";
const amount = coins(1234567, "ucosm");
const sendMsg: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: {
fromAddress: account.address,
toAddress: recipient,
amount: amount,
},
};
const memo = "With simulate";
const result = await client.signAndBroadcast(account.address, [sendMsg], "auto", memo);
assertIsBroadcastTxSuccess(result);
console.log("Successfully broadcasted:", result);
}
// Send transaction (using signAndBroadcast with manual gas)
{
const recipient = "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5";
const amount = coins(1234567, "ucosm");
@ -58,7 +86,7 @@ const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet
};
const memo = "With simulate";
const gasEstimation = await client.simulate(account.address, [sendMsg], memo);
const fee = calculateFee(Math.floor(gasEstimation * 1.3), gasPrice);
const fee = calculateFee(Math.round(gasEstimation * 1.3), gasPrice);
const result = await client.signAndBroadcast(account.address, [sendMsg], fee, memo);
assertIsBroadcastTxSuccess(result);
console.log("Successfully broadcasted:", result);

View File

@ -28,6 +28,7 @@ import {
alice,
defaultClearAdminFee,
defaultExecuteFee,
defaultGasPrice,
defaultInstantiateFee,
defaultMigrateFee,
defaultSendFee,
@ -600,6 +601,32 @@ describe("SigningCosmWasmClient", () => {
client.disconnect();
});
it("works with auto gas", async () => {
pendingWithoutWasmd();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, {
...defaultSigningClientOptions,
prefix: wasmd.prefix,
gasPrice: defaultGasPrice,
});
const msgDelegateTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate";
const msg = MsgDelegate.fromPartial({
delegatorAddress: alice.address0,
validatorAddress: validator.validatorAddress,
amount: coin(1234, "ustake"),
});
const msgAny: MsgDelegateEncodeObject = {
typeUrl: msgDelegateTypeUrl,
value: msg,
};
const memo = "Use your power wisely";
const result = await client.signAndBroadcast(alice.address0, [msgAny], "auto", memo);
assertIsBroadcastTxSuccess(result);
client.disconnect();
});
it("works with a modifying signer", async () => {
pendingWithoutWasmd();
const wallet = await ModifyingDirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, {

View File

@ -17,8 +17,10 @@ import {
AminoTypes,
BroadcastTxFailure,
BroadcastTxResponse,
calculateFee,
Coin,
defaultRegistryTypes,
GasPrice,
isBroadcastTxFailure,
logs,
MsgDelegateEncodeObject,
@ -144,6 +146,7 @@ export interface SigningCosmWasmClientOptions {
readonly prefix?: string;
readonly broadcastTimeoutMs?: number;
readonly broadcastPollIntervalMs?: number;
readonly gasPrice?: GasPrice;
}
export class SigningCosmWasmClient extends CosmWasmClient {
@ -153,6 +156,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
private readonly signer: OfflineSigner;
private readonly aminoTypes: AminoTypes;
private readonly gasPrice: GasPrice | undefined;
public static async connectWithSigner(
endpoint: string,
@ -194,6 +198,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
this.signer = signer;
this.broadcastTimeoutMs = options.broadcastTimeoutMs;
this.broadcastPollIntervalMs = options.broadcastPollIntervalMs;
this.gasPrice = options.gasPrice;
}
public async simulate(
@ -219,7 +224,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
public async upload(
senderAddress: string,
wasmCode: Uint8Array,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<UploadResult> {
const compressed = pako.gzip(wasmCode, { level: 9 });
@ -253,7 +258,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
codeId: number,
msg: Record<string, unknown>,
label: string,
fee: StdFee,
fee: StdFee | "auto",
options: InstantiateOptions = {},
): Promise<InstantiateResult> {
const instantiateContractMsg: MsgInstantiateContractEncodeObject = {
@ -284,7 +289,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
senderAddress: string,
contractAddress: string,
newAdmin: string,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<ChangeAdminResult> {
const updateAdminMsg: MsgUpdateAdminEncodeObject = {
@ -308,7 +313,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
public async clearAdmin(
senderAddress: string,
contractAddress: string,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<ChangeAdminResult> {
const clearAdminMsg: MsgClearAdminEncodeObject = {
@ -333,7 +338,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
contractAddress: string,
codeId: number,
migrateMsg: Record<string, unknown>,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<MigrateResult> {
const migrateContractMsg: MsgMigrateContractEncodeObject = {
@ -359,7 +364,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
senderAddress: string,
contractAddress: string,
msg: Record<string, unknown>,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
funds?: readonly Coin[],
): Promise<ExecuteResult> {
@ -386,7 +391,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
senderAddress: string,
recipientAddress: string,
amount: readonly Coin[],
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const sendMsg: MsgSendEncodeObject = {
@ -404,7 +409,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
delegatorAddress: string,
validatorAddress: string,
amount: Coin,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const delegateMsg: MsgDelegateEncodeObject = {
@ -418,7 +423,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
delegatorAddress: string,
validatorAddress: string,
amount: Coin,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const undelegateMsg: MsgUndelegateEncodeObject = {
@ -431,7 +436,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
public async withdrawRewards(
delegatorAddress: string,
validatorAddress: string,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const withdrawDelegatorRewardMsg: MsgWithdrawDelegatorRewardEncodeObject = {
@ -452,10 +457,18 @@ export class SigningCosmWasmClient extends CosmWasmClient {
public async signAndBroadcast(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const txRaw = await this.sign(signerAddress, messages, fee, memo);
let usedFee: StdFee;
if (fee == "auto") {
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
const gasEstimation = await this.simulate(signerAddress, messages, memo);
usedFee = calculateFee(Math.round(gasEstimation * 1.3), this.gasPrice);
} else {
usedFee = fee;
}
const txRaw = await this.sign(signerAddress, messages, usedFee, memo);
const txBytes = TxRaw.encode(txRaw).finish();
return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs);
}

View File

@ -16,6 +16,7 @@ import { MsgDelegateEncodeObject, MsgSendEncodeObject } from "./encodeobjects";
import { PrivateSigningStargateClient, SigningStargateClient } from "./signingstargateclient";
import { assertIsBroadcastTxSuccess, isBroadcastTxFailure } from "./stargateclient";
import {
defaultGasPrice,
defaultSendFee,
defaultSigningClientOptions,
faucet,
@ -273,6 +274,27 @@ describe("SigningStargateClient", () => {
assertIsBroadcastTxSuccess(result);
});
it("works with auto gas", async () => {
pendingWithoutSimapp();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const client = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet, {
...defaultSigningClientOptions,
gasPrice: defaultGasPrice,
});
const msg = MsgDelegate.fromPartial({
delegatorAddress: faucet.address0,
validatorAddress: validator.validatorAddress,
amount: coin(1234, "ustake"),
});
const msgAny: MsgDelegateEncodeObject = {
typeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
value: msg,
};
const result = await client.signAndBroadcast(faucet.address0, [msgAny], "auto");
assertIsBroadcastTxSuccess(result);
});
it("works with a modifying signer", async () => {
pendingWithoutSimapp();
const wallet = await ModifyingDirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);

View File

@ -68,6 +68,7 @@ import {
MsgUndelegateEncodeObject,
MsgWithdrawDelegatorRewardEncodeObject,
} from "./encodeobjects";
import { calculateFee, GasPrice } from "./fee";
import { BroadcastTxResponse, StargateClient } from "./stargateclient";
export const defaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [
@ -131,6 +132,7 @@ export interface SigningStargateClientOptions {
readonly prefix?: string;
readonly broadcastTimeoutMs?: number;
readonly broadcastPollIntervalMs?: number;
readonly gasPrice?: GasPrice;
}
export class SigningStargateClient extends StargateClient {
@ -140,6 +142,7 @@ export class SigningStargateClient extends StargateClient {
private readonly signer: OfflineSigner;
private readonly aminoTypes: AminoTypes;
private readonly gasPrice: GasPrice | undefined;
public static async connectWithSigner(
endpoint: string,
@ -179,6 +182,7 @@ export class SigningStargateClient extends StargateClient {
this.signer = signer;
this.broadcastTimeoutMs = options.broadcastTimeoutMs;
this.broadcastPollIntervalMs = options.broadcastPollIntervalMs;
this.gasPrice = options.gasPrice;
}
public async simulate(
@ -204,7 +208,7 @@ export class SigningStargateClient extends StargateClient {
senderAddress: string,
recipientAddress: string,
amount: readonly Coin[],
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const sendMsg: MsgSendEncodeObject = {
@ -222,7 +226,7 @@ export class SigningStargateClient extends StargateClient {
delegatorAddress: string,
validatorAddress: string,
amount: Coin,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const delegateMsg: MsgDelegateEncodeObject = {
@ -240,7 +244,7 @@ export class SigningStargateClient extends StargateClient {
delegatorAddress: string,
validatorAddress: string,
amount: Coin,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const undelegateMsg: MsgUndelegateEncodeObject = {
@ -257,7 +261,7 @@ export class SigningStargateClient extends StargateClient {
public async withdrawRewards(
delegatorAddress: string,
validatorAddress: string,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const withdrawMsg: MsgWithdrawDelegatorRewardEncodeObject = {
@ -279,7 +283,7 @@ export class SigningStargateClient extends StargateClient {
timeoutHeight: Height | undefined,
/** timeout in seconds */
timeoutTimestamp: number | undefined,
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const timeoutTimestampNanoseconds = timeoutTimestamp
@ -303,10 +307,18 @@ export class SigningStargateClient extends StargateClient {
public async signAndBroadcast(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee,
fee: StdFee | "auto",
memo = "",
): Promise<BroadcastTxResponse> {
const txRaw = await this.sign(signerAddress, messages, fee, memo);
let usedFee: StdFee;
if (fee == "auto") {
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
const gasEstimation = await this.simulate(signerAddress, messages, memo);
usedFee = calculateFee(Math.round(gasEstimation * 1.3), this.gasPrice);
} else {
usedFee = fee;
}
const txRaw = await this.sign(signerAddress, messages, usedFee, memo);
const txBytes = TxRaw.encode(txRaw).finish();
return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs);
}