Merge pull request #1124 from cosmos/add-getBalanceStaked

Add getter to get staked balance
This commit is contained in:
Milan Steiner 2022-04-13 16:11:16 +02:00 committed by GitHub
commit d59dcbc095
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 5 deletions

View File

@ -9,6 +9,8 @@ and this project adheres to
### Added
- @cosmjs/math: Add `Decimal.zero` and `Decimal.one` ([#1110]).
- @cosmjs/amino: Add `addCoins` ([#1116])
- @cosmjs/stargate: Add `StargateClient.getBalanceStaked()` to query the sum of all staked balance. ([#1116])
### Changed
@ -27,6 +29,7 @@ and this project adheres to
[#1110]: https://github.com/cosmos/cosmjs/issues/1110
[#1120]: https://github.com/cosmos/cosmjs/pull/1120
[#1121]: https://github.com/cosmos/cosmjs/pull/1121
[#1116]: https://github.com/cosmos/cosmjs/issues/1116
## [0.28.3] - 2022-04-11

View File

@ -1,4 +1,4 @@
import { coin, coins, parseCoins } from "./coins";
import { addCoins, coin, coins, parseCoins } from "./coins";
describe("coins", () => {
describe("coin", () => {
@ -138,4 +138,39 @@ describe("coins", () => {
expect(() => parseCoins("ucosm")).toThrowError(/invalid coin string/i);
});
});
describe("addCoins", () => {
it("works with same denom", () => {
const balance1 = {
amount: "10000",
denom: "utest",
};
const balance2 = {
amount: "20000",
denom: "utest",
};
const expectedBalance = {
amount: "30000",
denom: "utest",
};
expect(addCoins(balance1, balance2)).toEqual(expectedBalance);
});
it("works with different denoms", () => {
const balance1 = {
amount: "10000",
denom: "utest",
};
const balance2 = {
amount: "20000",
denom: "ucosm",
};
expect(() => addCoins(balance1, balance2)).toThrowError(
/Trying to add two coins with different denoms/i,
);
});
});
});

View File

@ -1,5 +1,4 @@
import { Uint53, Uint64 } from "@cosmjs/math";
import { Decimal, Uint53, Uint64 } from "@cosmjs/math";
export interface Coin {
readonly denom: string;
readonly amount: string;
@ -68,3 +67,14 @@ export function parseCoins(input: string): Coin[] {
};
});
}
/**
* Function to sum up coins with type Coin
*/
export function addCoins(lhs: Coin, rhs: Coin): Coin {
if (lhs.denom !== rhs.denom) throw new Error("Trying to add two coins with different denoms");
return {
amount: Decimal.fromAtomics(lhs.amount, 0).plus(Decimal.fromAtomics(rhs.amount, 0)).atomics,
denom: lhs.denom,
};
}

View File

@ -4,7 +4,7 @@ export {
rawEd25519PubkeyToRawAddress,
rawSecp256k1PubkeyToRawAddress,
} from "./addresses";
export { Coin, coin, coins, parseCoins } from "./coins";
export { addCoins, Coin, coin, coins, parseCoins } from "./coins";
export {
decodeAminoPubkey,
decodeBech32Pubkey,

View File

@ -257,6 +257,16 @@ describe("StargateClient", () => {
client.disconnect();
});
describe("getBalanceStaked", () => {
it("works", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
const response = await client.getBalanceStaked(faucet.address0);
expect(response).toEqual({ denom: "ustake", amount: "63474" });
});
});
it("returns 0 for non-existent balance", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);

View File

@ -1,10 +1,13 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { addCoins } from "@cosmjs/amino";
import { toHex } from "@cosmjs/encoding";
import { Uint53 } from "@cosmjs/math";
import { HttpEndpoint, Tendermint34Client, toRfc3339WithNanoseconds } from "@cosmjs/tendermint-rpc";
import { sleep } from "@cosmjs/utils";
import { assert, sleep } from "@cosmjs/utils";
import { MsgData } from "cosmjs-types/cosmos/base/abci/v1beta1/abci";
import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin";
import { QueryDelegatorDelegationsResponse } from "cosmjs-types/cosmos/staking/v1beta1/query";
import { DelegationResponse } from "cosmjs-types/cosmos/staking/v1beta1/staking";
import { Account, accountFromAny, AccountParser } from "./accounts";
import {
@ -273,6 +276,30 @@ export class StargateClient {
return this.forceGetQueryClient().bank.allBalances(address);
}
public async getBalanceStaked(address: string): Promise<Coin | null> {
const allDelegations = [];
let startAtKey: Uint8Array | undefined = undefined;
do {
const { delegationResponses, pagination }: QueryDelegatorDelegationsResponse =
await this.forceGetQueryClient().staking.delegatorDelegations(address, startAtKey);
const loadedDelegations = delegationResponses || [];
allDelegations.push(...loadedDelegations);
startAtKey = pagination?.nextKey;
} while (startAtKey !== undefined && startAtKey.length !== 0);
const sumValues = allDelegations.reduce(
(previousValue: Coin | null, currentValue: DelegationResponse): Coin => {
// Safe because field is set to non-nullable (https://github.com/cosmos/cosmos-sdk/blob/v0.45.3/proto/cosmos/staking/v1beta1/staking.proto#L295)
assert(currentValue.balance);
return previousValue !== null ? addCoins(previousValue, currentValue.balance) : currentValue.balance;
},
null,
);
return sumValues;
}
public async getDelegation(delegatorAddress: string, validatorAddress: string): Promise<Coin | null> {
let delegatedAmount: Coin | undefined;
try {