}
- {!![stakedData, claimableRewards, unbondingTokens].filter(Boolean)
- .length && (
-
{(() => {
@@ -257,10 +182,8 @@ const PopOver = ({
return networkSummary?.bonded > 0
? [
- t("votingPower"),
- `${convertToMoney(
- networkSummary.bonded,
- )} ${network.denom?.toUpperCase()}`,
+ network.denom?.toUpperCase(),
+ convertToMoney(networkSummary.bonded),
]
: null;
})();
diff --git a/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.module.scss b/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.module.scss
new file mode 100644
index 00000000..def272e4
--- /dev/null
+++ b/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.module.scss
@@ -0,0 +1,78 @@
+@import "src/styles/sass.scss";
+
+.stakingData {
+ background: #ffffff8f;
+ border-radius: 8px;
+ box-shadow:
+ 0 10px 32px -4px #0226e11a,
+ 0 6px 14px -6px #0226e11f;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ line-break: anywhere;
+ margin-bottom: 8px;
+ max-width: 100%;
+ padding: 12px 16px;
+ width: 100%;
+
+ .unbonding,
+ .rewards,
+ .total {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ font-size: 16px;
+ justify-content: space-between;
+ width: 100%;
+
+ > div {
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 600;
+ letter-spacing: 0.032px;
+ line-height: 20px;
+ text-shadow: $box-shadow-variant-3;
+ }
+
+ > div:first-child {
+ color: #25282d;
+ text-align: left;
+ }
+
+ > div:last-child {
+ text-align: right;
+ }
+ }
+
+ .rewards {
+ > div:nth-child(2) {
+ color: #059c78;
+ }
+ }
+}
+
+.totalValue {
+ > div:nth-child(2) {
+ color: #616161;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ letter-spacing: 0.308px;
+ line-height: 20px;
+ text-align: right;
+ text-shadow: $box-shadow-variant-3;
+ }
+}
+
+.stakeAccount {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.external {
+ height: 20px;
+ width: 20px;
+}
diff --git a/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.tsx b/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.tsx
new file mode 100644
index 00000000..c474a53b
--- /dev/null
+++ b/src/screens/staking/components/networks/components/network_grid/components/network_card/staking_data_box.tsx
@@ -0,0 +1,150 @@
+import useTranslation from "next-translate/useTranslation";
+import { useEffect, useMemo } from "react";
+
+import { tooltipId } from "@src/components/tooltip";
+import { useStakingRef } from "@src/screens/staking/lib/staking_sdk/context";
+import { fetchCoinPriceForNetwork } from "@src/screens/staking/lib/staking_sdk/context/actions";
+import type { NetworkClaimableRewards } from "@src/screens/staking/lib/staking_sdk/context/selectors";
+import {
+ getClaimableRewardsForNetwork,
+ getCoinPriceForNetwork,
+ getStakedDataForNetwork,
+ getUnbondingTokensForNetwork,
+} from "@src/screens/staking/lib/staking_sdk/context/selectors";
+import { networkKeyToNetworkId } from "@src/screens/staking/lib/staking_sdk/core";
+import type { Coin } from "@src/screens/staking/lib/staking_sdk/core/base";
+import { WalletId } from "@src/screens/staking/lib/staking_sdk/core/base";
+import {
+ formatCoin,
+ formatStakedDataUSD,
+} from "@src/screens/staking/lib/staking_sdk/formatters";
+import type { Network, NetworkKey } from "@src/utils/network_info";
+
+import * as styles from "./staking_data_box.module.scss";
+
+type PopOverProps = {
+ network: Network;
+};
+
+const StakingDataBox = ({ network }: PopOverProps) => {
+ const stakingNetworkId = networkKeyToNetworkId[network.key as NetworkKey];
+
+ const stakingRef = useStakingRef();
+
+ const { t } = useTranslation("staking");
+
+ const { claimableRewards, stakedData, unbondingTokens } = useMemo(() => {
+ const wallet = WalletId.Keplr;
+
+ const result = {
+ claimableRewards: null as NetworkClaimableRewards | null,
+ stakedData: null as Coin | null,
+ unbondingTokens: null as { period: string; text: string } | null,
+ };
+
+ if (!!stakingNetworkId && !!wallet) {
+ result.stakedData = getStakedDataForNetwork(
+ stakingRef.current.state,
+ stakingNetworkId,
+ );
+
+ result.claimableRewards =
+ getClaimableRewardsForNetwork(
+ stakingRef.current.state,
+ stakingNetworkId,
+ ) || null;
+
+ const unbonding = getUnbondingTokensForNetwork(
+ stakingRef.current.state,
+ stakingNetworkId,
+ );
+
+ if (unbonding) {
+ result.unbondingTokens = {
+ period: unbonding.period
+ ? new Date(Number(unbonding.period) * 1000).toLocaleString()
+ : "",
+ text: formatCoin(unbonding.coin, { decimals: 4 }),
+ };
+ }
+ }
+
+ return result;
+ }, [stakingNetworkId, stakingRef]);
+
+ useEffect(() => {
+ fetchCoinPriceForNetwork(stakingRef.current, stakingNetworkId);
+ }, [stakingRef, stakingNetworkId]);
+
+ const displayedRewards = claimableRewards
+ ? `+${formatCoin(claimableRewards, { decimals: 4 })}`
+ : null;
+
+ const displayedStaked = (() => {
+ if (!stakedData || !stakingNetworkId) return null;
+
+ const coinPrice = getCoinPriceForNetwork(
+ stakingRef.current.state,
+ stakingNetworkId,
+ );
+
+ if (!coinPrice) return [formatCoin(stakedData)];
+
+ const stakedDataUSD = formatStakedDataUSD(stakedData, coinPrice);
+
+ return [formatCoin(stakedData), stakedDataUSD].filter(Boolean);
+ })();
+
+ if (![stakedData, claimableRewards, unbondingTokens].filter(Boolean).length) {
+ return null;
+ }
+
+ const content = (() => (
+ <>
+ {displayedStaked && (
+
+
{t("totalStaked")}
+
+ {displayedStaked.map((item, itemIdx) => (
+
{item}
+ ))}
+
+
+ )}
+ {!!claimableRewards && (
+
+
{t("claimableRewards")}
+
+ {displayedRewards}
+
+
+ )}
+ {!!unbondingTokens && (
+
+
{t("unbondingTokens")}
+
+ {unbondingTokens.text}
+
+
+ )}
+ >
+ ))();
+
+ return
{content}
;
+};
+
+export default StakingDataBox;
diff --git a/src/screens/staking/components/staking_widget/index.module.scss b/src/screens/staking/components/staking_widget/index.module.scss
index 0e321144..f6a18409 100644
--- a/src/screens/staking/components/staking_widget/index.module.scss
+++ b/src/screens/staking/components/staking_widget/index.module.scss
@@ -31,6 +31,11 @@ $wallet-icon-size: 28px;
display: flex;
margin-left: -8px;
}
+
+ &:nth-child(3) {
+ display: flex;
+ margin-left: -8px;
+ }
}
&:hover {
diff --git a/src/screens/staking/lib/staking_sdk/context/actions.ts b/src/screens/staking/lib/staking_sdk/context/actions.ts
index 6fc164c4..424a75c6 100644
--- a/src/screens/staking/lib/staking_sdk/context/actions.ts
+++ b/src/screens/staking/lib/staking_sdk/context/actions.ts
@@ -154,8 +154,8 @@ export const setSelectedAccount = (
};
type FetchAccountResult = {
- info: Awaited
>;
- rewards: Awaited>;
+ info: Awaited> | undefined;
+ rewards: Awaited> | undefined;
};
const accountsRequests: Record<
@@ -198,8 +198,8 @@ export const fetchAccountData = async (
}
const newRequest = Promise.all([
- stakingClient.getAddressInfo(networkId, address),
- stakingClient.getRewardsInfo(networkId, address),
+ stakingClient.getAddressInfo(networkId, address).catch(() => undefined),
+ stakingClient.getRewardsInfo(networkId, address).catch(() => undefined),
]).then(([info, rewards]) => {
accountsRequests[id] = undefined;
diff --git a/src/screens/staking/lib/staking_sdk/context/index.tsx b/src/screens/staking/lib/staking_sdk/context/index.tsx
index b3abe542..6cb3cb59 100644
--- a/src/screens/staking/lib/staking_sdk/context/index.tsx
+++ b/src/screens/staking/lib/staking_sdk/context/index.tsx
@@ -34,7 +34,7 @@ const baseContext: TStakingContext = {
state: defaultState,
};
-export const StakingContext = createContext(baseContext);
+const StakingContext = createContext(baseContext);
export const StakingProvider = ({ children }: PropsWithChildren) => {
const [state, setState] = useState(
diff --git a/src/screens/staking/lib/staking_sdk/core/cosmos.ts b/src/screens/staking/lib/staking_sdk/core/cosmos.ts
index 6d7074be..4c42264a 100644
--- a/src/screens/staking/lib/staking_sdk/core/cosmos.ts
+++ b/src/screens/staking/lib/staking_sdk/core/cosmos.ts
@@ -5,7 +5,7 @@ import {
testnetNetworks,
} from "./base";
-export const keplrNetworks = new Set(
+export const keplrNetworks = new Set(
[
StakingNetworkId.Akash,
StakingNetworkId.Celestia,
diff --git a/src/screens/staking/lib/staking_sdk/core/index.ts b/src/screens/staking/lib/staking_sdk/core/index.ts
index 8ea1c43b..520d3a53 100644
--- a/src/screens/staking/lib/staking_sdk/core/index.ts
+++ b/src/screens/staking/lib/staking_sdk/core/index.ts
@@ -12,7 +12,7 @@ export const networksWithStaking = new Set([
...Array.from(cosmosStakingNetworks),
]);
-export const walletsSupported = new Set(Array.from(cosmosWallets)); // TODO add WalletId.Leap back when staking with Leap Wallet is reliable
+export const walletsSupported = new Set([...Array.from(cosmosWallets)]);
export const networkIdToNetworkKey: Record = {
[StakingNetworkId.Akash]: "akash",
diff --git a/src/screens/staking/lib/staking_sdk/staking_client.ts b/src/screens/staking/lib/staking_sdk/staking_client.ts
index d32c856e..6e3d8937 100644
--- a/src/screens/staking/lib/staking_sdk/staking_client.ts
+++ b/src/screens/staking/lib/staking_sdk/staking_client.ts
@@ -6,7 +6,6 @@ import type {
ClaimableRewardsResponse,
StakingInfoResponse,
} from "./staking_client_types";
-import { normaliseCoin } from "./utils/coins";
const baseUrl =
process.env.NEXT_PUBLIC_STAKING_API || "https://staking-api.forbole.com";
@@ -32,16 +31,15 @@ const rewardsDivisor = new BigNumber(10).pow(18);
const parseStakingRewards = async (res: ClaimableRewardsResponse) =>
Array.isArray(res)
- ? res
- .map((coin) => {
- const num = new BigNumber(coin.amount);
+ ? res.map((coin) => {
+ const num = new BigNumber(coin.amount);
- return {
- amount: num.dividedBy(rewardsDivisor).toString(),
- denom: coin.denom,
- };
- })
- .map(normaliseCoin)
+ return {
+ ...coin,
+ amount: num.dividedBy(rewardsDivisor).toString(),
+ denom: coin.denom,
+ };
+ })
: res;
type StakeResponse = {
diff --git a/src/screens/staking/lib/staking_sdk/wallet_operations.ts b/src/screens/staking/lib/staking_sdk/wallet_operations.ts
index db1fe6ec..c2266d93 100644
--- a/src/screens/staking/lib/staking_sdk/wallet_operations.ts
+++ b/src/screens/staking/lib/staking_sdk/wallet_operations.ts
@@ -29,7 +29,18 @@ export const MAX_MEMO = 256;
export const stakeAmount = (
opts: StakeOpts,
-): Promise> => stakeAmountCosmos(opts);
+): Promise> => {
+ const { account } = opts;
+
+ if (
+ keplrNetworks.has(account.networkId) ||
+ leapNetworks.has(account.networkId)
+ ) {
+ return stakeAmountCosmos(opts);
+ }
+
+ throw new Error("Unsupported network");
+};
export const claimRewards = async (
opts: ClaimOpts,
@@ -42,7 +53,18 @@ export const getClaimRewardsFee = async (
export const unstake = async (
opts: UnstakeAmount,
-): Promise> => unstakeCosmos(opts);
+): Promise> => {
+ const { account } = opts;
+
+ if (
+ keplrNetworks.has(account.networkId) ||
+ leapNetworks.has(account.networkId)
+ ) {
+ return unstakeCosmos(opts);
+ }
+
+ throw new Error("Unsupported network");
+};
export const tryToConnectWallets = async (
context: TStakingContext,
diff --git a/src/screens/staking/lib/staking_sdk/wallet_operations/base.ts b/src/screens/staking/lib/staking_sdk/wallet_operations/base.ts
index c354bc95..690b794e 100644
--- a/src/screens/staking/lib/staking_sdk/wallet_operations/base.ts
+++ b/src/screens/staking/lib/staking_sdk/wallet_operations/base.ts
@@ -1,7 +1,9 @@
import type { Account } from "../core";
+import type { Coin } from "../core/base";
export type WalletOperationResult =
| {
+ coin?: Coin;
error: ErrorType;
success: false;
}
diff --git a/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts b/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts
index 3cd4e9bc..40c6d144 100644
--- a/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts
+++ b/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts
@@ -387,6 +387,10 @@ export const tryToConnectKeplr = async (
const nonNativeChains = Array.from(keplrNonNativeChains);
+ if (!chainsToConnect.length || !nonNativeChains.length) {
+ return;
+ }
+
try {
await keplr.enable(chainsToConnect);