From 6d9398475f415f59774c6353cd83f6da1bd45187 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 3 Jan 2022 23:43:45 +0100 Subject: [PATCH 1/2] Add decodeCosmosSdkDecFromProto --- CHANGELOG.md | 2 ++ packages/stargate/src/index.ts | 1 + packages/stargate/src/queries/index.ts | 7 ++++++- packages/stargate/src/queries/utils.spec.ts | 21 +++++++++++++++++++++ packages/stargate/src/queries/utils.ts | 15 +++++++++++++-- 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 packages/stargate/src/queries/utils.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b39c42848..5e3a9cc10d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to ([#932]). - @cosmjs/stargate: Merge `DeliverTxFailure` and `DeliverTxSuccess` into a single `DeliverTxResponse` ([#878], [#949]). Add `assertIsDeliverTxFailure`. +- @cosmjs/stargate: Created `types.Dec` decoder function + `decodeCosmosSdkDecFromProto`. - @cosmjs/amino: Added `StdTx`, `isStdTx` and `makeStdTx` and removed them from @cosmjs/launchpad. They are re-exported in @cosmjs/launchpad for backwards compatibility. diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index 7b7eedc8c0..3e41e69bc4 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -62,6 +62,7 @@ export { BankExtension, createPagination, createProtobufRpcClient, + decodeCosmosSdkDecFromProto, DistributionExtension, GovExtension, GovParamsType, diff --git a/packages/stargate/src/queries/index.ts b/packages/stargate/src/queries/index.ts index 5616050117..913b2f8ce4 100644 --- a/packages/stargate/src/queries/index.ts +++ b/packages/stargate/src/queries/index.ts @@ -11,4 +11,9 @@ export { GovExtension, GovParamsType, GovProposalId, setupGovExtension } from ". export { IbcExtension, setupIbcExtension } from "./ibc"; export { setupStakingExtension, StakingExtension } from "./staking"; export { setupTxExtension, TxExtension } from "./tx"; -export { createPagination, createProtobufRpcClient, ProtobufRpcClient } from "./utils"; +export { + createPagination, + createProtobufRpcClient, + decodeCosmosSdkDecFromProto, + ProtobufRpcClient, +} from "./utils"; diff --git a/packages/stargate/src/queries/utils.spec.ts b/packages/stargate/src/queries/utils.spec.ts new file mode 100644 index 0000000000..703efca4c7 --- /dev/null +++ b/packages/stargate/src/queries/utils.spec.ts @@ -0,0 +1,21 @@ +import { fromHex } from "@cosmjs/encoding"; + +import { decodeCosmosSdkDecFromProto } from "./utils"; + +describe("utils", () => { + describe("decodeCosmosSdkDecFromProto", () => { + it("works for string inputs", () => { + expect(decodeCosmosSdkDecFromProto("0").toString()).toEqual("0"); + expect(decodeCosmosSdkDecFromProto("1").toString()).toEqual("0.000000000000000001"); + expect(decodeCosmosSdkDecFromProto("3000000").toString()).toEqual("0.000000000003"); + expect(decodeCosmosSdkDecFromProto("123456789123456789").toString()).toEqual("0.123456789123456789"); + expect(decodeCosmosSdkDecFromProto("1234567891234567890").toString()).toEqual("1.23456789123456789"); + }); + + it("works for byte inputs", () => { + expect(decodeCosmosSdkDecFromProto(fromHex("313330303033343138373830313631333938")).toString()).toEqual( + "0.130003418780161398", + ); + }); + }); +}); diff --git a/packages/stargate/src/queries/utils.ts b/packages/stargate/src/queries/utils.ts index 9b565d0309..c931727dc1 100644 --- a/packages/stargate/src/queries/utils.ts +++ b/packages/stargate/src/queries/utils.ts @@ -1,5 +1,5 @@ -import { Bech32 } from "@cosmjs/encoding"; -import { Uint64 } from "@cosmjs/math"; +import { Bech32, fromAscii } from "@cosmjs/encoding"; +import { Decimal, Uint64 } from "@cosmjs/math"; import { PageRequest } from "cosmjs-types/cosmos/base/query/v1beta1/pagination"; import Long from "long"; @@ -53,3 +53,14 @@ export function longify(value: string | number | Long | Uint64): Long { const checkedValue = Uint64.fromString(value.toString()); return Long.fromBytesBE([...checkedValue.toBytesBigEndian()], true); } + +/** + * Takes a string or binary encoded `github.com/cosmos/cosmos-sdk/types.Dec` from the + * protobuf API and converts it into a `Decimal` with 18 fractional digits. + * + * See https://github.com/cosmos/cosmos-sdk/issues/10863 for more context why this is needed. + */ +export function decodeCosmosSdkDecFromProto(input: string | Uint8Array): Decimal { + const asString = typeof input === "string" ? input : fromAscii(input); + return Decimal.fromAtomics(asString, 18); +} From 576bf2a5a235052bb2b60ff70a53d3405a73fef0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 4 Jan 2022 22:49:13 +0100 Subject: [PATCH 2/2] Add MintExtension for queries --- CHANGELOG.md | 1 + packages/stargate/src/index.ts | 3 ++ packages/stargate/src/queries/index.ts | 1 + packages/stargate/src/queries/mint.spec.ts | 58 +++++++++++++++++++++ packages/stargate/src/queries/mint.ts | 60 ++++++++++++++++++++++ 5 files changed, 123 insertions(+) create mode 100644 packages/stargate/src/queries/mint.spec.ts create mode 100644 packages/stargate/src/queries/mint.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e3a9cc10d..e5b07f23ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to ([#932]). - @cosmjs/stargate: Merge `DeliverTxFailure` and `DeliverTxSuccess` into a single `DeliverTxResponse` ([#878], [#949]). Add `assertIsDeliverTxFailure`. +- @cosmjs/stargate: Created initial `MintExtension`. - @cosmjs/stargate: Created `types.Dec` decoder function `decodeCosmosSdkDecFromProto`. - @cosmjs/amino: Added `StdTx`, `isStdTx` and `makeStdTx` and removed them from diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index 3e41e69bc4..c9a633a060 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -68,6 +68,8 @@ export { GovParamsType, GovProposalId, IbcExtension, + MintExtension, + MintParams, ProtobufRpcClient, QueryClient, setupAuthExtension, @@ -75,6 +77,7 @@ export { setupDistributionExtension, setupGovExtension, setupIbcExtension, + setupMintExtension, setupStakingExtension, setupTxExtension, StakingExtension, diff --git a/packages/stargate/src/queries/index.ts b/packages/stargate/src/queries/index.ts index 913b2f8ce4..f0cb2e7779 100644 --- a/packages/stargate/src/queries/index.ts +++ b/packages/stargate/src/queries/index.ts @@ -9,6 +9,7 @@ export { BankExtension, setupBankExtension } from "./bank"; export { DistributionExtension, setupDistributionExtension } from "./distribution"; export { GovExtension, GovParamsType, GovProposalId, setupGovExtension } from "./gov"; export { IbcExtension, setupIbcExtension } from "./ibc"; +export { MintExtension, MintParams, setupMintExtension } from "./mint"; export { setupStakingExtension, StakingExtension } from "./staking"; export { setupTxExtension, TxExtension } from "./tx"; export { diff --git a/packages/stargate/src/queries/mint.spec.ts b/packages/stargate/src/queries/mint.spec.ts new file mode 100644 index 0000000000..ba9abfedff --- /dev/null +++ b/packages/stargate/src/queries/mint.spec.ts @@ -0,0 +1,58 @@ +import { Tendermint34Client } from "@cosmjs/tendermint-rpc"; + +import { QueryClient } from "../"; +import { pendingWithoutSimapp, simapp } from "../testutils.spec"; +import { MintExtension, setupMintExtension } from "./mint"; + +async function makeClientWithMint( + rpcUrl: string, +): Promise<[QueryClient & MintExtension, Tendermint34Client]> { + const tmClient = await Tendermint34Client.connect(rpcUrl); + return [QueryClient.withExtensions(tmClient, setupMintExtension), tmClient]; +} + +describe("MintExtension", () => { + describe("params", () => { + it("works", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithMint(simapp.tendermintUrl); + + const params = await client.mint.params(); + expect(params.blocksPerYear.toNumber()).toBeGreaterThan(100_000); + expect(params.blocksPerYear.toNumber()).toBeLessThan(100_000_000); + expect(params.goalBonded.toString()).toEqual("0.67"); + expect(params.inflationMin.toString()).toEqual("0.07"); + expect(params.inflationMax.toString()).toEqual("0.2"); + expect(params.inflationRateChange.toString()).toEqual("0.13"); + expect(params.mintDenom).toEqual(simapp.denomStaking); + + tmClient.disconnect(); + }); + }); + + describe("inflation", () => { + it("works", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithMint(simapp.tendermintUrl); + + const inflation = await client.mint.inflation(); + expect(inflation.toFloatApproximation()).toBeGreaterThan(0.13); + expect(inflation.toFloatApproximation()).toBeLessThan(0.1301); + + tmClient.disconnect(); + }); + }); + + describe("annualProvisions", () => { + it("works", async () => { + pendingWithoutSimapp(); + const [client, tmClient] = await makeClientWithMint(simapp.tendermintUrl); + + const annualProvisions = await client.mint.annualProvisions(); + expect(annualProvisions.toFloatApproximation()).toBeGreaterThan(5_400_000_000); + expect(annualProvisions.toFloatApproximation()).toBeLessThan(5_500_000_000); + + tmClient.disconnect(); + }); + }); +}); diff --git a/packages/stargate/src/queries/mint.ts b/packages/stargate/src/queries/mint.ts new file mode 100644 index 0000000000..6928f06004 --- /dev/null +++ b/packages/stargate/src/queries/mint.ts @@ -0,0 +1,60 @@ +import { Decimal } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; +import { Params } from "cosmjs-types/cosmos/mint/v1beta1/mint"; +import { QueryClientImpl } from "cosmjs-types/cosmos/mint/v1beta1/query"; + +import { createProtobufRpcClient } from "../"; +import { QueryClient } from "./queryclient"; +import { decodeCosmosSdkDecFromProto } from "./utils"; + +/** + * Like Params from "cosmjs-types/cosmos/mint/v1beta1/mint" + * but using decimal types. + */ +export interface MintParams extends Pick { + readonly goalBonded: Decimal; + readonly inflationMin: Decimal; + readonly inflationMax: Decimal; + readonly inflationRateChange: Decimal; +} + +export interface MintExtension { + readonly mint: { + readonly params: () => Promise; + readonly inflation: () => Promise; + readonly annualProvisions: () => Promise; + }; +} + +export function setupMintExtension(base: QueryClient): MintExtension { + const rpc = createProtobufRpcClient(base); + // Use this service to get easy typed access to query methods + // This cannot be used for proof verification + const queryService = new QueryClientImpl(rpc); + + return { + mint: { + params: async (): Promise => { + const { params } = await queryService.Params({}); + assert(params); + + return { + blocksPerYear: params.blocksPerYear, + goalBonded: decodeCosmosSdkDecFromProto(params.goalBonded), + inflationMin: decodeCosmosSdkDecFromProto(params.inflationMin), + inflationMax: decodeCosmosSdkDecFromProto(params.inflationMax), + inflationRateChange: decodeCosmosSdkDecFromProto(params.inflationRateChange), + mintDenom: params.mintDenom, + }; + }, + inflation: async () => { + const { inflation } = await queryService.Inflation({}); + return decodeCosmosSdkDecFromProto(inflation); + }, + annualProvisions: async () => { + const { annualProvisions } = await queryService.AnnualProvisions({}); + return decodeCosmosSdkDecFromProto(annualProvisions); + }, + }, + }; +}