Skip to content

Commit

Permalink
feat: add aggregations
Browse files Browse the repository at this point in the history
  • Loading branch information
icfor committed Mar 1, 2024
1 parent 94ed48c commit 0b40c3a
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 74 deletions.
95 changes: 95 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"scripts": {
"build": "next build",
"dev": "PORT=4000 next dev",
"lint": "npm run lint:eslint && npm run lint:prettier",
"lint": "bash ./scripts/check_unused_exports.sh && npm run lint:eslint && npm run lint:prettier",
"lint:eslint": "eslint . --ext .ts,.tsx",
"lint:prettier": "prettier --check .",
"start": "next start",
Expand Down Expand Up @@ -45,6 +45,7 @@
"postcss": "^8.4.35",
"prettier": "^3.2.5",
"tailwindcss": "^3.4.1",
"ts-unused-exports": "^10.0.1",
"typescript": "^5.3.3"
}
}
9 changes: 9 additions & 0 deletions scripts/check_unused_exports.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

set -e

./node_modules/.bin/ts-unused-exports tsconfig.json \
--excludePathsFromReport='next.config' \
--excludePathsFromReport='tailwind.config' \
--excludePathsFromReport='.*pages.*' \
--excludePathsFromReport='.*\.next\.*'
29 changes: 9 additions & 20 deletions src/features/staking/components/main-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import { toast } from "react-toastify";

import {
claimRewardsAction,
setRedelegateAction,
stakeValidatorAction,
unstakeValidatorAction,
} from "../context/actions";
import { useStaking } from "../context/hooks";
import { getTotalDelegation } from "../context/selectors";
import type { StakingState } from "../context/state";
import type { StakeAddresses } from "../lib/core/base";
import { formatCoin } from "../lib/core/coins";
import { chainId } from "../lib/core/constants";
import { formatCoin } from "../lib/formatters";
import { keybaseClient } from "../lib/utils/keybase-client";
import DebugAccount from "./debug-account";

Expand Down Expand Up @@ -99,6 +99,8 @@ function StakingPage() {
[validators],
);

const totalDelegation = getTotalDelegation(staking.state);

return (
<>
<div className="flex flex-col gap-2">
Expand All @@ -120,6 +122,11 @@ function StakingPage() {
Tokens: <b>{formatCoin(tokens)}</b>
</div>
)}
{totalDelegation && (
<div>
Total delegation: <b>{formatCoin(totalDelegation)}</b>
</div>
)}
</div>
{isInfoLoading && <div>Loading ...</div>}
{!!delegations?.items.length && (
Expand Down Expand Up @@ -198,24 +205,6 @@ function StakingPage() {
Claim rewards
</Button>
)}
<Button
disabled={isLoading}
onClick={() => {
if (!client) return;

setIsLoading(true);

setRedelegateAction(
account.bech32Address,
client,
staking,
).finally(() => {
setIsLoading(false);
});
}}
>
Redelelegate
</Button>
</div>
</div>
);
Expand Down
48 changes: 19 additions & 29 deletions src/features/staking/components/validator-page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
"use client";

import BigNumber from "bignumber.js";
import { BondStatus } from "cosmjs-types/cosmos/staking/v1beta1/staking";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";

import { getValidatorDetailsAction } from "../context/actions";
import { useStaking } from "../context/hooks";
import { getVotingPowerPerc } from "../context/selectors";
import { formatCommission, formatVotingPowerPerc } from "../lib/formatters";
import { keybaseClient } from "../lib/utils/keybase-client";

export default function ValidatorPage() {
const searchParams = useSearchParams();
const address = searchParams.get("address");
const stakingRef = useStaking();

const { pool } = stakingRef.staking.state;

const [logo, setLogo] = useState<null | string>(null);

const [validatorDetails, setValidatorDetails] = useState<Awaited<
Expand Down Expand Up @@ -48,29 +47,12 @@ export default function ValidatorPage() {
return <div>Loading ...</div>;
}

const parseCommissionRate = (commissionRate: string) => {
const comission = new BigNumber(commissionRate)
.div(new BigNumber(10).pow(18))
.toNumber();

return `${(comission * 100).toFixed(0)}%`;
};

const votingPowerPercentage = (() => {
const validatorTokens = validatorDetails.tokens;

if (!validatorTokens || typeof pool?.bondedTokens !== "string") {
return null;
}

const perc = new BigNumber(validatorTokens)
.div(new BigNumber(pool.bondedTokens))
.toNumber();

const percNum = perc < 0.0001 ? "<0.1" : (perc * 100).toFixed(1);
const votingPowerPerc = getVotingPowerPerc(
validatorDetails.tokens,
stakingRef.staking.state,
);

return `${percNum}%`;
})();
const votingPowerPercStr = formatVotingPowerPerc(votingPowerPerc);

return (
<div>
Expand All @@ -87,7 +69,17 @@ export default function ValidatorPage() {
<div>{validatorDetails.description.website}</div>
<div>
Commission:{" "}
{parseCommissionRate(validatorDetails.commission.commissionRates.rate)}
{formatCommission(validatorDetails.commission.commissionRates.rate)}
</div>
<div>
Max commission:{" "}
{formatCommission(validatorDetails.commission.commissionRates.maxRate)}
</div>
<div>
Max commission change:{" "}
{formatCommission(
validatorDetails.commission.commissionRates.maxChangeRate,
)}
</div>
<div>Jailed: {validatorDetails.jailed.toString()}</div>
<div>
Expand All @@ -96,9 +88,7 @@ export default function ValidatorPage() {
? "Bonded"
: validatorDetails.status}
</div>
{votingPowerPercentage && (
<div>Voting Power: {votingPowerPercentage}</div>
)}
{votingPowerPercStr && <div>Voting Power: {votingPowerPercStr}</div>}
<Link href="/">Back</Link>
</div>
);
Expand Down
4 changes: 3 additions & 1 deletion src/features/staking/context/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ export const claimRewardsAction = async (
await fetchStakingDataAction(addresses.delegator, staking);
};

export const setRedelegateAction = async (
// @TODO
// eslint-disable-next-line
const setRedelegateAction = async (
delegatorAddress: string,
client: AbstraxionSigningClient,
staking: StakingContextType,
Expand Down
2 changes: 1 addition & 1 deletion src/features/staking/context/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useStakingSync } from "./hooks";
import { reducer } from "./reducer";
import { StakingContext, defaultState } from "./state";

export const Wrapper = ({ children }: PropsWithChildren) => {
const Wrapper = ({ children }: PropsWithChildren) => {
useStakingSync();

// eslint-disable-next-line react/jsx-no-useless-fragment
Expand Down
31 changes: 31 additions & 0 deletions src/features/staking/context/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import BigNumber from "bignumber.js";

import { sumAllCoins } from "../lib/core/coins";
import type { StakingState } from "./state";

export const getTotalDelegation = (state: StakingState) => {
const { delegations } = state;

if (!delegations?.items.length) {
return null;
}

const delegationCoins = delegations.items.map((d) => d.balance);

return sumAllCoins(delegationCoins);
};

export const getVotingPowerPerc = (
validatorTokens: string,
state: StakingState,
) => {
const { pool } = state;

if (!validatorTokens || typeof pool?.bondedTokens !== "string") {
return null;
}

return new BigNumber(validatorTokens)
.div(new BigNumber(pool.bondedTokens))
.toNumber();
};
12 changes: 3 additions & 9 deletions src/features/staking/lib/core/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export const getValidatorDetails = async (address: string) => {
return promise;
};

// @TODO: This returns the unbonding time
// const params = await queryClient.staking.params();

let poolRequest: null | Promise<Pool> = null;

export const getPool = async () => {
Expand Down Expand Up @@ -210,15 +213,6 @@ export const unstakeAmount = async (
.catch(handleTxError);
};

export const getUnbonding = async (
address: string,
validatorAddress: string,
) => {
const queryClient = await getStakingQueryClient();

return queryClient.staking.unbondingDelegation(address, validatorAddress);
};

export const claimRewards = async (
addresses: StakeAddresses,
client: NonNullable<AbstraxionSigningClient>,
Expand Down
18 changes: 5 additions & 13 deletions src/features/staking/lib/core/coins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,15 @@ export const normaliseCoin = (coin: Coin) => {
};
};

export const formatCoin = (coin: Coin) => {
const resolved = normaliseCoin(coin);
const amount = new BigNumber(resolved.amount);

return `${amount.toFormat()} ${resolved.denom}`;
};

export const getEmptyXionCoin = () =>
({ amount: "0", denom: "xion" }) satisfies Coin;
const getEmptyXionCoin = () => ({ amount: "0", denom: "xion" }) satisfies Coin;

export const sumAllCoins = (coins: Coin[]) =>
coins.reduce(
(acc, coin) => ({
amount: (
parseFloat(acc.amount) + parseFloat(normaliseCoin(coin).amount)
).toString(),
denom: coin.denom,
amount: new BigNumber(acc.amount)
.plus(normaliseCoin(coin).amount)
.toString(),
denom: acc.denom,
}),
getEmptyXionCoin(),
);
Loading

0 comments on commit 0b40c3a

Please sign in to comment.