diff --git a/packages/stargate/src/fee.spec.ts b/packages/stargate/src/fee.spec.ts new file mode 100644 index 00000000..7a94238a --- /dev/null +++ b/packages/stargate/src/fee.spec.ts @@ -0,0 +1,23 @@ +import { Decimal } from "@cosmjs/math"; + +import { GasPrice } from "./fee"; + +describe("GasPrice", () => { + it("can be constructed", () => { + const inputs = ["3.14", "3", "0.14"]; + inputs.forEach((input) => { + const gasPrice = new GasPrice(Decimal.fromUserInput(input, 18), "utest"); + expect(gasPrice.amount.toString()).toEqual(input); + expect(gasPrice.denom).toEqual("utest"); + }); + }); + + it("can be constructed from a config string", () => { + const inputs = ["3.14", "3", "0.14"]; + inputs.forEach((input) => { + const gasPrice = GasPrice.fromString(`${input}utest`); + expect(gasPrice.amount.toString()).toEqual(input); + expect(gasPrice.denom).toEqual("utest"); + }); + }); +}); diff --git a/packages/stargate/src/fee.ts b/packages/stargate/src/fee.ts new file mode 100644 index 00000000..f82f0ddd --- /dev/null +++ b/packages/stargate/src/fee.ts @@ -0,0 +1,77 @@ +import { Decimal, Uint53 } from "@cosmjs/math"; +import { Coin, coins } from "@cosmjs/proto-signing"; + +/** + * This is the same as StdFee from @cosmjs/launchpad but those might diverge in the future. + */ +export interface StdFee { + readonly amount: readonly Coin[]; + readonly gas: string; +} + +/** + * This is the same as FeeTable from @cosmjs/launchpad but those might diverge in the future. + */ +export type FeeTable = Record; + +/** + * This is the same as GasPrice from @cosmjs/launchpad but those might diverge in the future. + */ +export class GasPrice { + public readonly amount: Decimal; + public readonly denom: string; + + public constructor(amount: Decimal, denom: string) { + this.amount = amount; + this.denom = denom; + } + + public static fromString(gasPrice: string): GasPrice { + const matchResult = gasPrice.match(/^(?.+?)(?[a-z]+)$/); + if (!matchResult) { + throw new Error("Invalid gas price string"); + } + const { amount, denom } = matchResult.groups as { readonly amount: string; readonly denom: string }; + if (denom.length < 3 || denom.length > 127) { + throw new Error("Gas price denomination must be between 3 and 127 characters"); + } + const fractionalDigits = 18; + const decimalAmount = Decimal.fromUserInput(amount, fractionalDigits); + return new GasPrice(decimalAmount, denom); + } +} + +/** + * This is the same as GasLimits from @cosmjs/launchpad but those might diverge in the future. + */ +export type GasLimits> = { + readonly [key in keyof T]: number; +}; + +/** + * This is the same as calculateFee from @cosmjs/launchpad but those might diverge in the future. + */ +function calculateFee(gasLimit: number, { denom, amount: gasPriceAmount }: GasPrice): StdFee { + const amount = Math.ceil(gasPriceAmount.multiply(new Uint53(gasLimit)).toFloatApproximation()); + return { + amount: coins(amount, denom), + gas: gasLimit.toString(), + }; +} + +/** + * This is the same as buildFeeTable from @cosmjs/launchpad but those might diverge in the future. + */ +export function buildFeeTable>( + gasPrice: GasPrice, + defaultGasLimits: GasLimits, + gasLimits: Partial>, +): T { + return Object.entries(defaultGasLimits).reduce( + (feeTable, [type, defaultGasLimit]) => ({ + ...feeTable, + [type]: calculateFee(gasLimits[type] || defaultGasLimit, gasPrice), + }), + {} as T, + ); +} diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index c05e786f..384f3d82 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -2,6 +2,7 @@ export { Coin, coin, coins, parseCoins } from "@cosmjs/proto-signing"; export { Account, accountFromAny } from "./accounts"; export { AminoConverter, AminoTypes } from "./aminotypes"; +export { buildFeeTable, FeeTable, GasLimits, GasPrice, StdFee } from "./fee"; export * as logs from "./logs"; export { AuthExtension, diff --git a/packages/stargate/src/signingstargateclient.spec.ts b/packages/stargate/src/signingstargateclient.spec.ts index bed17b38..869c4f12 100644 --- a/packages/stargate/src/signingstargateclient.spec.ts +++ b/packages/stargate/src/signingstargateclient.spec.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention,no-bitwise */ -import { GasPrice, MsgDelegate as LaunchpadMsgDelegate, Secp256k1HdWallet } from "@cosmjs/launchpad"; +import { MsgDelegate as LaunchpadMsgDelegate, Secp256k1HdWallet } from "@cosmjs/launchpad"; import { coin, coins, DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing"; import { assert, sleep } from "@cosmjs/utils"; import protobuf from "protobufjs/minimal"; @@ -9,6 +9,7 @@ import { MsgSend } from "./codec/cosmos/bank/v1beta1/tx"; import { Coin } from "./codec/cosmos/base/v1beta1/coin"; import { DeepPartial, MsgDelegate } from "./codec/cosmos/staking/v1beta1/tx"; import { Tx } from "./codec/cosmos/tx/v1beta1/tx"; +import { GasPrice } from "./fee"; import { PrivateSigningStargateClient, SigningStargateClient } from "./signingstargateclient"; import { assertIsBroadcastTxSuccess } from "./stargateclient"; import { diff --git a/packages/stargate/src/signingstargateclient.ts b/packages/stargate/src/signingstargateclient.ts index 5df8ba42..49b30cba 100644 --- a/packages/stargate/src/signingstargateclient.ts +++ b/packages/stargate/src/signingstargateclient.ts @@ -1,13 +1,6 @@ import { encodeSecp256k1Pubkey } from "@cosmjs/amino"; import { fromBase64 } from "@cosmjs/encoding"; -import { - buildFeeTable, - CosmosFeeTable, - GasLimits, - GasPrice, - makeSignDoc as makeSignDocAmino, - StdFee, -} from "@cosmjs/launchpad"; +import { CosmosFeeTable, makeSignDoc as makeSignDocAmino } from "@cosmjs/launchpad"; import { Int53 } from "@cosmjs/math"; import { EncodeObject, @@ -63,6 +56,7 @@ import { MsgConnectionOpenInit, MsgConnectionOpenTry, } from "./codec/ibc/core/connection/v1/tx"; +import { buildFeeTable, GasLimits, GasPrice, StdFee } from "./fee"; import { BroadcastTxResponse, StargateClient } from "./stargateclient"; const defaultGasPrice = GasPrice.fromString("0.025ucosm");