From 2c26c900cae29b3385b887a3863f690a4c85afa0 Mon Sep 17 00:00:00 2001 From: Ignacio <142767109+icfor@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:13:47 +0800 Subject: [PATCH] feat: refactor chains imports and add networks (#196) --- e2e/poms/staking_page.ts | 8 +- e2e/staking.spec.ts | 2 +- public/images/network/dymension.svg | 9 + public/images/network/evmos.svg | 11 + src/components/stats/hooks.tsx | 2 +- .../components/network_card/index.module.scss | 1 + .../components/network_card/popover.tsx | 8 +- .../staking_section/claim_rewards_modal.tsx | 2 +- .../staking_section/networks_select.tsx | 12 +- .../staking_section/staking_modal.tsx | 9 +- .../staking_section/unstaking_modal.tsx | 11 +- .../components/staking_widget/index.tsx | 6 +- .../lib/staking_sdk/context/actions.ts | 29 ++- .../staking/lib/staking_sdk/context/index.tsx | 12 +- .../lib/staking_sdk/context/selectors.ts | 52 ++--- src/screens/staking/lib/staking_sdk/core.ts | 185 --------------- .../staking/lib/staking_sdk/core/base.ts | 66 ++++++ .../staking/lib/staking_sdk/core/cosmos.ts | 58 +++++ .../staking/lib/staking_sdk/core/index.ts | 81 +++++++ .../staking/lib/staking_sdk/formatters.ts | 2 +- .../staking/lib/staking_sdk/gecko_client.ts | 2 +- .../staking/lib/staking_sdk/staking_client.ts | 7 +- .../staking/lib/staking_sdk/utils/accounts.ts | 3 +- .../staking/lib/staking_sdk/utils/coins.ts | 4 +- .../staking/lib/staking_sdk/utils/networks.ts | 4 +- .../staking/lib/staking_sdk/utils/storage.ts | 2 +- .../staking/lib/staking_sdk/utils/wallets.ts | 2 +- .../lib/staking_sdk/wallet_operations.ts | 5 +- .../staking_sdk/wallet_operations/cosmos.ts | 219 +++++++++--------- src/screens/staking/lib/wallet_info.ts | 2 +- src/utils/network_info.ts | 11 +- 31 files changed, 446 insertions(+), 381 deletions(-) create mode 100644 public/images/network/dymension.svg create mode 100644 public/images/network/evmos.svg delete mode 100644 src/screens/staking/lib/staking_sdk/core.ts create mode 100644 src/screens/staking/lib/staking_sdk/core/base.ts create mode 100644 src/screens/staking/lib/staking_sdk/core/cosmos.ts create mode 100644 src/screens/staking/lib/staking_sdk/core/index.ts diff --git a/e2e/poms/staking_page.ts b/e2e/poms/staking_page.ts index 403781af..6a6b0d16 100644 --- a/e2e/poms/staking_page.ts +++ b/e2e/poms/staking_page.ts @@ -3,11 +3,13 @@ import type { Page } from "@playwright/test"; import type { TStakingContext } from "@src/screens/staking/lib/staking_sdk/context"; import type { Account, - Coin, - StakingNetworkId, Wallet, } from "@src/screens/staking/lib/staking_sdk/core"; -import { WalletId } from "@src/screens/staking/lib/staking_sdk/core"; +import type { + Coin, + StakingNetworkId, +} from "@src/screens/staking/lib/staking_sdk/core/base"; +import { WalletId } from "@src/screens/staking/lib/staking_sdk/core/base"; import type { NetworkKey } from "@src/utils/network_info"; const networkCard = (network: NetworkKey) => diff --git a/e2e/staking.spec.ts b/e2e/staking.spec.ts index 6c31a355..4a6e13ab 100644 --- a/e2e/staking.spec.ts +++ b/e2e/staking.spec.ts @@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test"; import { StakingNetworkId, WalletId, -} from "@src/screens/staking/lib/staking_sdk/core"; +} from "@src/screens/staking/lib/staking_sdk/core/base"; import type { NetworkKey } from "@src/utils/network_info"; import { StakingPage } from "./poms/staking_page"; diff --git a/public/images/network/dymension.svg b/public/images/network/dymension.svg new file mode 100644 index 00000000..3c5026d4 --- /dev/null +++ b/public/images/network/dymension.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/network/evmos.svg b/public/images/network/evmos.svg new file mode 100644 index 00000000..5f8dcc79 --- /dev/null +++ b/public/images/network/evmos.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/components/stats/hooks.tsx b/src/components/stats/hooks.tsx index 503ae5e6..5adc8b48 100644 --- a/src/components/stats/hooks.tsx +++ b/src/components/stats/hooks.tsx @@ -9,7 +9,7 @@ import { fetchNetworksInfo, } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getNetworkTVL } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import { StakingNetworkId } from "@src/screens/staking/lib/staking_sdk/core"; +import { StakingNetworkId } from "@src/screens/staking/lib/staking_sdk/core/base"; import { networkFunctions } from "@src/utils/network_functions"; import { EthData, VSYSData, networkNumber } from "@src/utils/network_info"; diff --git a/src/screens/staking/components/networks/components/network_grid/components/network_card/index.module.scss b/src/screens/staking/components/networks/components/network_grid/components/network_card/index.module.scss index 0d1e0252..f8c2b30b 100644 --- a/src/screens/staking/components/networks/components/network_grid/components/network_card/index.module.scss +++ b/src/screens/staking/components/networks/components/network_grid/components/network_card/index.module.scss @@ -52,6 +52,7 @@ $image-box-shadow: max-width: spacing(6); min-height: spacing(6); min-width: spacing(6); + overflow: hidden; padding: 0; } diff --git a/src/screens/staking/components/networks/components/network_grid/components/network_card/popover.tsx b/src/screens/staking/components/networks/components/network_grid/components/network_card/popover.tsx index c9fc0656..bc9aec19 100644 --- a/src/screens/staking/components/networks/components/network_grid/components/network_card/popover.tsx +++ b/src/screens/staking/components/networks/components/network_grid/components/network_card/popover.tsx @@ -35,15 +35,15 @@ import { getUnbondingTokensForNetwork, } from "@src/screens/staking/lib/staking_sdk/context/selectors"; import { - WalletId, networkKeyToNetworkId, networksWithStaking, } from "@src/screens/staking/lib/staking_sdk/core"; import type { Account, - Coin, - NetworkInfo, + StakingNetworkInfo, } 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, @@ -93,7 +93,7 @@ const PopOver = ({ const { t } = useTranslation("staking"); const [stakingNetworkInfo, setStakingNetworkInfo] = - useState(null); + useState(null); const { state: stakingState } = useContext(StakingContext); diff --git a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx index 32b79bc6..7a935f45 100644 --- a/src/screens/staking/components/staking_section/claim_rewards_modal.tsx +++ b/src/screens/staking/components/staking_section/claim_rewards_modal.tsx @@ -14,7 +14,7 @@ import { syncAccountData, } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getSelectedAccount } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import type { Coin } from "@src/screens/staking/lib/staking_sdk/core"; +import type { Coin } from "@src/screens/staking/lib/staking_sdk/core/base"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { accountHasRewards } from "@src/screens/staking/lib/staking_sdk/utils/accounts"; import { diff --git a/src/screens/staking/components/staking_section/networks_select.tsx b/src/screens/staking/components/staking_section/networks_select.tsx index df573d3a..68d071d0 100644 --- a/src/screens/staking/components/staking_section/networks_select.tsx +++ b/src/screens/staking/components/staking_section/networks_select.tsx @@ -15,15 +15,13 @@ import { getSelectedAccount, getWalletCustomName, } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import type { - Account, - StakingNetworkId, -} from "@src/screens/staking/lib/staking_sdk/core"; +import type { Account } from "@src/screens/staking/lib/staking_sdk/core"; import { - WalletId, - mainNetworkDenom, networkIdToNetworkKey, + walletsSupported, } from "@src/screens/staking/lib/staking_sdk/core"; +import type { StakingNetworkId } from "@src/screens/staking/lib/staking_sdk/core/base"; +import { mainNetworkDenom } from "@src/screens/staking/lib/staking_sdk/core/base"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { getClaimableRewardsForAccount, @@ -179,7 +177,7 @@ const NetworksSelect = ({ disabled, variant }: Props) => { if (isWallet) { const otherWalletsAccounts = allAccounts - .filter(({ wallet }) => wallet !== WalletId.Leap) // TODO remove this line when staking with Leap Wallet is reliable + .filter(({ wallet }) => walletsSupported.has(wallet)) .filter((account) => account.networkId === selectedAccount.networkId); if (otherWalletsAccounts.length < 2) { diff --git a/src/screens/staking/components/staking_section/staking_modal.tsx b/src/screens/staking/components/staking_section/staking_modal.tsx index f2db213e..13268753 100644 --- a/src/screens/staking/components/staking_section/staking_modal.tsx +++ b/src/screens/staking/components/staking_section/staking_modal.tsx @@ -19,8 +19,8 @@ import { syncAccountData, } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getSelectedAccount } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import type { NetworkInfo } from "@src/screens/staking/lib/staking_sdk/core"; -import { mainNetworkDenom } from "@src/screens/staking/lib/staking_sdk/core"; +import type { StakingNetworkInfo } from "@src/screens/staking/lib/staking_sdk/core"; +import { mainNetworkDenom } from "@src/screens/staking/lib/staking_sdk/core/base"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { getAccountNormalisedBalance } from "@src/screens/staking/lib/staking_sdk/utils/accounts"; import { getEmptyCoin } from "@src/screens/staking/lib/staking_sdk/utils/coins"; @@ -43,7 +43,10 @@ const StakingModal = () => { const [isLoading, setIsLoading] = useState(false); const { selectedAccount, selectedAction } = stakingRef.current.state; - const [networkInfo, setNetworkInfo] = useState(null); + const [networkInfo, setNetworkInfo] = useState( + null, + ); + const [amount, setAmount] = useState(""); const [amountError, setAmountError] = useState(""); const [memoError, setMemoError] = useState(""); diff --git a/src/screens/staking/components/staking_section/unstaking_modal.tsx b/src/screens/staking/components/staking_section/unstaking_modal.tsx index 8f8f8af9..da062024 100644 --- a/src/screens/staking/components/staking_section/unstaking_modal.tsx +++ b/src/screens/staking/components/staking_section/unstaking_modal.tsx @@ -20,7 +20,7 @@ import { syncAccountData, } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getSelectedAccount } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import type { NetworkInfo } from "@src/screens/staking/lib/staking_sdk/core"; +import type { StakingNetworkInfo } from "@src/screens/staking/lib/staking_sdk/core"; import { formatCoin } from "@src/screens/staking/lib/staking_sdk/formatters"; import { getAccountNormalisedDelegation } from "@src/screens/staking/lib/staking_sdk/utils/accounts"; import { @@ -43,8 +43,13 @@ const UnstakingModal = () => { const stakingRef = useStakingRef(); const { locale } = useRouter(); - const { selectedAccount, selectedAction } = stakingRef.current.state; - const [networkInfo, setNetworkInfo] = useState(null); + const { selectedAction } = stakingRef.current.state; + + const [networkInfo, setNetworkInfo] = useState( + null, + ); + + const selectedAccount = getSelectedAccount(stakingRef.current.state); const isOpen = !!selectedAccount && selectedAction === "unstake"; diff --git a/src/screens/staking/components/staking_widget/index.tsx b/src/screens/staking/components/staking_widget/index.tsx index 9faa6054..434c1677 100644 --- a/src/screens/staking/components/staking_widget/index.tsx +++ b/src/screens/staking/components/staking_widget/index.tsx @@ -14,10 +14,8 @@ import { setSelectedAccount, } from "@src/screens/staking/lib/staking_sdk/context/actions"; import { getCanAddWallet } from "@src/screens/staking/lib/staking_sdk/context/selectors"; -import type { - Wallet, - WalletId, -} from "@src/screens/staking/lib/staking_sdk/core"; +import type { Wallet } from "@src/screens/staking/lib/staking_sdk/core"; +import type { WalletId } from "@src/screens/staking/lib/staking_sdk/core/base"; import { getWalletName, walletsIcons, diff --git a/src/screens/staking/lib/staking_sdk/context/actions.ts b/src/screens/staking/lib/staking_sdk/context/actions.ts index 802ad7ba..6fc164c4 100644 --- a/src/screens/staking/lib/staking_sdk/context/actions.ts +++ b/src/screens/staking/lib/staking_sdk/context/actions.ts @@ -1,19 +1,18 @@ import type { TStakingContext } from "."; +import { networksWithStaking } from "../core"; +import type { + Account, + StakingNetworkInfo, + StakingState, + Wallet, +} from "../core"; +import type { CoinDenom, StakingNetworkId } from "../core/base"; import { ENABLE_TESTNETS, WalletId, mainNetworkDenom, - networksWithStaking, testnetNetworks, -} from "../core"; -import type { - Account, - CoinDenom, - NetworkInfo, - StakingNetworkId, - State, - Wallet, -} from "../core"; +} from "../core/base"; import type { CoinsPricesResult } from "../gecko_client"; import { geckoClient } from "../gecko_client"; import { stakingClient } from "../staking_client"; @@ -24,7 +23,7 @@ import { disconnectWalletFns } from "../wallet_operations"; // Actions const networkInfoRequests: { - [key in StakingNetworkId]?: Promise; + [key in StakingNetworkId]?: Promise; } = {}; export const getNetworkStakingInfo = async ( @@ -32,7 +31,7 @@ export const getNetworkStakingInfo = async ( networkId: StakingNetworkId, ) => { if (context.state.networksInfo[networkId]) - return context.state.networksInfo[networkId] as NetworkInfo; + return context.state.networksInfo[networkId] as StakingNetworkInfo; const request = networkInfoRequests[networkId]; @@ -49,7 +48,7 @@ export const getNetworkStakingInfo = async ( networkInfoRequests[networkId] = undefined; - return newInfo as NetworkInfo; + return newInfo as StakingNetworkInfo; }); networkInfoRequests[networkId] = newRequest; @@ -139,8 +138,8 @@ export const setUserWallet = ( export const setSelectedAccount = ( context: TStakingContext, - selectedAction: State["selectedAction"], - selectedAccount: State["selectedAccount"], + selectedAction: StakingState["selectedAction"], + selectedAccount: StakingState["selectedAccount"], ) => { context.setState({ selectedAccount: selectedAccount diff --git a/src/screens/staking/lib/staking_sdk/context/index.tsx b/src/screens/staking/lib/staking_sdk/context/index.tsx index 3bf3501a..b3abe542 100644 --- a/src/screens/staking/lib/staking_sdk/context/index.tsx +++ b/src/screens/staking/lib/staking_sdk/context/index.tsx @@ -8,17 +8,19 @@ import { useState, } from "react"; -import type { State } from "../core"; +import type { StakingState } from "../core"; import { useWalletsListeners } from "../wallet_operations"; -type SetState = (state: ((s: State) => State) | Partial) => void; +type SetState = ( + state: ((s: StakingState) => StakingState) | Partial, +) => void; export type TStakingContext = { setState: SetState; - state: State; + state: StakingState; }; -const defaultState: State = { +const defaultState: StakingState = { coinsPrices: {}, hasInit: false, networksInfo: {}, @@ -35,7 +37,7 @@ const baseContext: TStakingContext = { export const StakingContext = createContext(baseContext); export const StakingProvider = ({ children }: PropsWithChildren) => { - const [state, setState] = useState( + const [state, setState] = useState( (typeof window !== "undefined" && window.stakingContext?.state) || baseContext.state, ); diff --git a/src/screens/staking/lib/staking_sdk/context/selectors.ts b/src/screens/staking/lib/staking_sdk/context/selectors.ts index b480c831..0ab612fc 100644 --- a/src/screens/staking/lib/staking_sdk/context/selectors.ts +++ b/src/screens/staking/lib/staking_sdk/context/selectors.ts @@ -1,14 +1,9 @@ import BigNumber from "bignumber.js"; -import type { - Account, - Coin, - CoinDenom, - StakingNetworkId, - State, - WalletId, -} from "../core"; -import { mainNetworkDenom, walletsSupported } from "../core"; +import type { Account, StakingState } from "../core"; +import { walletsSupported } from "../core"; +import type { Coin, CoinDenom, StakingNetworkId, WalletId } from "../core/base"; +import { mainNetworkDenom } from "../core/base"; import { filterOutTestnets, filterUniqueAddresses, @@ -26,7 +21,7 @@ import { doesWalletSupportNetwork } from "../wallet_operations"; // This functions are only intended to be used for extracting data, so they // should not be setting the state. Also they should be synchronous functions. -export const getSelectedAccount = (state: State) => { +export const getSelectedAccount = (state: StakingState) => { const { selectedAccount } = state; if (!selectedAccount) { @@ -40,7 +35,7 @@ export const getSelectedAccount = (state: State) => { ); }; -export const getCanAddWallet = (state: State) => { +export const getCanAddWallet = (state: StakingState) => { const { wallets } = state; const connectedWallets = new Set(Object.keys(wallets)); @@ -53,7 +48,7 @@ export const getCanAddWallet = (state: State) => { }; export const getAccountsForNetwork = ( - state: State, + state: StakingState, network: StakingNetworkId, ) => { const wallets = Object.values(state.wallets); @@ -65,7 +60,7 @@ export const getAccountsForNetwork = ( }; export const getStakedDataForNetwork = ( - state: State, + state: StakingState, network: StakingNetworkId, ): Coin | null => { const accountsForNetwork = getAccountsForNetwork(state, network); @@ -95,7 +90,7 @@ export type NetworkClaimableRewards = Coin | null; // This assumes that the rewards coins have been normalized (which happens in // the staking client) export const getClaimableRewardsForNetwork = ( - state: State, + state: StakingState, network: StakingNetworkId, ): NetworkClaimableRewards => { const accountsForNetwork = getAccountsForNetwork(state, network); @@ -121,7 +116,7 @@ export const getClaimableRewardsForNetwork = ( type UnbondingTokensResult = { coin: Coin; period: string } | null; export const getUnbondingTokensForNetwork = ( - state: State, + state: StakingState, network: StakingNetworkId, ): UnbondingTokensResult => { const accountsForNetwork = getAccountsForNetwork(state, network); @@ -160,14 +155,16 @@ export const getUnbondingTokensForNetwork = ( }, null as UnbondingTokensResult); }; -export const getHasConnectedWallets = (state: State) => +export const getHasConnectedWallets = (state: StakingState) => Object.keys(state.wallets).length > 0; -export const getHasConnectedWallet = (state: State, walletId: WalletId) => - state.wallets[walletId] !== undefined; +export const getHasConnectedWallet = ( + state: StakingState, + walletId: WalletId, +) => state.wallets[walletId] !== undefined; export const getNetworkVotingPower = ( - state: State, + state: StakingState, network: StakingNetworkId, ): Coin | null => { const networkInfo = state.networksInfo[network]; @@ -189,7 +186,7 @@ export const getNetworkVotingPower = ( }; export const getNetworkTVL = ( - state: State, + state: StakingState, network: StakingNetworkId, ): BigNumber | null => { const votingPower = getNetworkVotingPower(state, network); @@ -208,14 +205,14 @@ export const getNetworkTVL = ( }; export const getHasNetworkSupportedWallet = ( - state: State, + state: StakingState, network: StakingNetworkId, ) => Object.keys(state.wallets).some((walletId) => doesWalletSupportNetwork(walletId as WalletId, network), ); -export const getAllAccounts = (state: State) => +export const getAllAccounts = (state: StakingState) => Object.values(state.wallets).reduce( (acc, wallet) => [ ...acc, @@ -228,7 +225,7 @@ export const getAllAccounts = (state: State) => ); export const getAllStaked = ( - state: State, + state: StakingState, accountsProp?: Account[], ): number => { const accounts = accountsProp || getAllAccounts(state); @@ -260,7 +257,10 @@ export const getAllStaked = ( }, 0); }; -export const getAllRewards = (state: State, accountsProp?: Account[]) => { +export const getAllRewards = ( + state: StakingState, + accountsProp?: Account[], +) => { const accounts = accountsProp || getAllAccounts(state); const uniqueMainnetAccounts = accounts @@ -287,7 +287,7 @@ export const getAllRewards = (state: State, accountsProp?: Account[]) => { }; export const getCoinPriceForNetwork = ( - state: State, + state: StakingState, networkId: StakingNetworkId, ) => { const mainDenom = mainNetworkDenom[networkId]; @@ -301,5 +301,5 @@ export const getCoinPriceForNetwork = ( return coinPrice; }; -export const getWalletCustomName = (state: State, walletId: WalletId) => +export const getWalletCustomName = (state: StakingState, walletId: WalletId) => state.wallets[walletId]?.name; diff --git a/src/screens/staking/lib/staking_sdk/core.ts b/src/screens/staking/lib/staking_sdk/core.ts deleted file mode 100644 index 7b3f6768..00000000 --- a/src/screens/staking/lib/staking_sdk/core.ts +++ /dev/null @@ -1,185 +0,0 @@ -import type { NetworkKey } from "@src/utils/network_info"; - -import type { - AccountDetailResponse, - ClaimableRewardsResponse, -} from "./staking_client_types"; - -export const ENABLE_TESTNETS = - process.env.NEXT_PUBLIC_STAKING_ENABLE_TESTNETS === "true"; - -export type Coin = { - amount: string; - denom: string; -}; - -export enum WalletId { - Keplr = "keplr", - Leap = "leap", -} - -export enum CoinDenom { - AKT = "AKT", - ATOM = "ATOM", - DYDX = "DYDX", - KAVA = "KAVA", - OSMO = "OSMO", - PICA = "PICA", - REGEN = "REGEN", - STARS = "STARS", - TIA = "TIA", -} - -// For now these values match the id in the chain registry: -// - https://github.com/cosmos/chain-registry -// - https://github.com/cosmos/chain-registry/tree/master/testnets -export enum StakingNetworkId { - Akash = "akashnet-2", - Celestia = "celestia", - CelestiaTestnet = "mocha-4", - ComposableFinance = "centauri-1", - CosmosHub = "cosmoshub-4", - CosmosHubTestnet = "theta-testnet-001", - DyDx = "dydx-mainnet-1", - Kava = "kava_2222-10", - KavaTestnet = "kava_2221-16000", - Osmosis = "osmosis-1", - Regen = "regen-1", - Stargaze = "stargaze-1", - StargazeTestnet = "elgafar-1", -} - -export const mainNetworkDenom: Record = { - [StakingNetworkId.Akash]: CoinDenom.AKT, - [StakingNetworkId.Celestia]: CoinDenom.TIA, - [StakingNetworkId.CelestiaTestnet]: CoinDenom.TIA, - [StakingNetworkId.ComposableFinance]: CoinDenom.PICA, - [StakingNetworkId.CosmosHub]: CoinDenom.ATOM, - [StakingNetworkId.CosmosHubTestnet]: CoinDenom.ATOM, - [StakingNetworkId.DyDx]: CoinDenom.DYDX, - [StakingNetworkId.Kava]: CoinDenom.KAVA, - [StakingNetworkId.KavaTestnet]: CoinDenom.KAVA, - [StakingNetworkId.Osmosis]: CoinDenom.OSMO, - [StakingNetworkId.Regen]: CoinDenom.REGEN, - [StakingNetworkId.Stargaze]: CoinDenom.STARS, - [StakingNetworkId.StargazeTestnet]: CoinDenom.STARS, -}; - -export const testnetNetworks = new Set([ - StakingNetworkId.CosmosHubTestnet, - StakingNetworkId.CelestiaTestnet, - StakingNetworkId.KavaTestnet, - StakingNetworkId.StargazeTestnet, -]); - -export const keplrNetworks = new Set( - [ - StakingNetworkId.Akash, - StakingNetworkId.Celestia, - StakingNetworkId.CelestiaTestnet, - StakingNetworkId.ComposableFinance, - StakingNetworkId.CosmosHub, - StakingNetworkId.CosmosHubTestnet, - StakingNetworkId.DyDx, - StakingNetworkId.Kava, - StakingNetworkId.KavaTestnet, - StakingNetworkId.Osmosis, - StakingNetworkId.Regen, - StakingNetworkId.Stargaze, - StakingNetworkId.StargazeTestnet, - ].filter( - ENABLE_TESTNETS ? () => true : (network) => !testnetNetworks.has(network), - ), -); - -export const keplrNonNativeChains = new Set([ - StakingNetworkId.ComposableFinance, - StakingNetworkId.CelestiaTestnet, - StakingNetworkId.CosmosHubTestnet, - StakingNetworkId.KavaTestnet, - StakingNetworkId.StargazeTestnet, -]); - -const leapExcludedNetworks = new Set([ - StakingNetworkId.Celestia, - StakingNetworkId.ComposableFinance, - StakingNetworkId.DyDx, - StakingNetworkId.Regen, - StakingNetworkId.KavaTestnet, -]); - -export const leapNetworks = new Set( - Array.from(keplrNetworks).filter( - (network) => !leapExcludedNetworks.has(network), - ), -); - -export const networksWithStaking = new Set([...Array.from(keplrNetworks)]); - -export const walletsSupported = new Set([WalletId.Keplr]); // TODO add WalletId.Leap back when staking with Leap Wallet is reliable - -export const networkIdToNetworkKey: Record = { - [StakingNetworkId.Akash]: "akash", - [StakingNetworkId.Celestia]: "celestia", - [StakingNetworkId.CelestiaTestnet]: "celestia-testnet", - [StakingNetworkId.ComposableFinance]: "composable-finance", - [StakingNetworkId.CosmosHub]: "cosmos", - [StakingNetworkId.CosmosHubTestnet]: "cosmos-testnet", - [StakingNetworkId.DyDx]: "dydx", - [StakingNetworkId.Kava]: "kava", - [StakingNetworkId.KavaTestnet]: "kava-testnet", - [StakingNetworkId.Osmosis]: "osmosis", - [StakingNetworkId.Regen]: "regen", - [StakingNetworkId.Stargaze]: "stargaze", - [StakingNetworkId.StargazeTestnet]: "stargaze-testnet", -}; - -export const networkKeyToNetworkId: { [key in NetworkKey]?: StakingNetworkId } = - Object.fromEntries( - Object.entries(networkIdToNetworkKey) - .filter(([k]) => networksWithStaking.has(k as StakingNetworkId)) - .map(([k, v]) => [v, k]), - ); - -export type Account = { - address: string; - info?: AccountDetailResponse; - networkId: StakingNetworkId; - rewards?: ClaimableRewardsResponse; - wallet: WalletId; -}; - -type StakeAction = "claim_rewards" | "connect_wallet" | "stake" | "unstake"; - -export type Wallet = { - name?: string; - networks: { - [key in StakingNetworkId]?: { - accounts: Account[]; - networkId: StakingNetworkId; - }; - }; - wallet: WalletId; -}; - -type SelectedAccount = { - address: string; - networkId: StakingNetworkId; - wallet: WalletId; -}; - -export type NetworkInfo = { - apy: number; - rpc: string; - unbonding_period: null | string; - voting_power: number; -}; - -export type State = { - coinsPrices: { [key in CoinDenom]?: string }; - hasInit: boolean; - networksInfo: { [key in StakingNetworkId]?: NetworkInfo }; - selectedAccount: null | SelectedAccount; - selectedAction: null | StakeAction; - wallets: { [key in WalletId]?: Wallet }; -}; diff --git a/src/screens/staking/lib/staking_sdk/core/base.ts b/src/screens/staking/lib/staking_sdk/core/base.ts new file mode 100644 index 00000000..1fb03d30 --- /dev/null +++ b/src/screens/staking/lib/staking_sdk/core/base.ts @@ -0,0 +1,66 @@ +export const ENABLE_TESTNETS = + process.env.NEXT_PUBLIC_STAKING_ENABLE_TESTNETS === "true"; + +export type Coin = { + amount: string; + denom: string; +}; + +export enum WalletId { + Keplr = "keplr", + Leap = "leap", +} + +export enum CoinDenom { + AKT = "AKT", + ATOM = "ATOM", + DYDX = "DYDX", + KAVA = "KAVA", + OSMO = "OSMO", + PICA = "PICA", + REGEN = "REGEN", + STARS = "STARS", + TIA = "TIA", +} + +// For now these values match the id in the chain registry: +// - https://github.com/cosmos/chain-registry +// - https://github.com/cosmos/chain-registry/tree/master/testnets +export enum StakingNetworkId { + Akash = "akashnet-2", + Celestia = "celestia", + CelestiaTestnet = "mocha-4", + ComposableFinance = "centauri-1", + CosmosHub = "cosmoshub-4", + CosmosHubTestnet = "theta-testnet-001", + DyDx = "dydx-mainnet-1", + Kava = "kava_2222-10", + KavaTestnet = "kava_2221-16000", + Osmosis = "osmosis-1", + Regen = "regen-1", + Stargaze = "stargaze-1", + StargazeTestnet = "elgafar-1", +} + +export const mainNetworkDenom: Record = { + [StakingNetworkId.Akash]: CoinDenom.AKT, + [StakingNetworkId.Celestia]: CoinDenom.TIA, + [StakingNetworkId.CelestiaTestnet]: CoinDenom.TIA, + [StakingNetworkId.ComposableFinance]: CoinDenom.PICA, + [StakingNetworkId.CosmosHub]: CoinDenom.ATOM, + [StakingNetworkId.CosmosHubTestnet]: CoinDenom.ATOM, + [StakingNetworkId.DyDx]: CoinDenom.DYDX, + [StakingNetworkId.Kava]: CoinDenom.KAVA, + [StakingNetworkId.KavaTestnet]: CoinDenom.KAVA, + [StakingNetworkId.Osmosis]: CoinDenom.OSMO, + [StakingNetworkId.Regen]: CoinDenom.REGEN, + [StakingNetworkId.Stargaze]: CoinDenom.STARS, + [StakingNetworkId.StargazeTestnet]: CoinDenom.STARS, +}; + +export const testnetNetworks = new Set([ + StakingNetworkId.CelestiaTestnet, + StakingNetworkId.CosmosHubTestnet, + StakingNetworkId.KavaTestnet, + StakingNetworkId.StargazeTestnet, +]); diff --git a/src/screens/staking/lib/staking_sdk/core/cosmos.ts b/src/screens/staking/lib/staking_sdk/core/cosmos.ts new file mode 100644 index 00000000..6723d0ef --- /dev/null +++ b/src/screens/staking/lib/staking_sdk/core/cosmos.ts @@ -0,0 +1,58 @@ +import { + ENABLE_TESTNETS, + StakingNetworkId, + WalletId, + testnetNetworks, +} from "./base"; + +export const keplrNetworks = new Set( + [ + StakingNetworkId.Akash, + StakingNetworkId.Celestia, + StakingNetworkId.CelestiaTestnet, + StakingNetworkId.ComposableFinance, + StakingNetworkId.CosmosHub, + StakingNetworkId.CosmosHubTestnet, + StakingNetworkId.DyDx, + StakingNetworkId.Kava, + StakingNetworkId.KavaTestnet, + StakingNetworkId.Osmosis, + StakingNetworkId.Regen, + StakingNetworkId.Stargaze, + StakingNetworkId.StargazeTestnet, + ].filter( + ENABLE_TESTNETS ? () => true : (network) => !testnetNetworks.has(network), + ), +); + +export const keplrNonNativeChains = new Set([ + StakingNetworkId.CelestiaTestnet, + StakingNetworkId.ComposableFinance, + StakingNetworkId.CosmosHubTestnet, + StakingNetworkId.KavaTestnet, + StakingNetworkId.StargazeTestnet, +]); + +const leapExcludedNetworks = new Set([ + StakingNetworkId.Celestia, + StakingNetworkId.ComposableFinance, + StakingNetworkId.DyDx, + StakingNetworkId.Regen, + StakingNetworkId.KavaTestnet, +]); + +export const leapNetworks = new Set( + Array.from(keplrNetworks).filter( + (network) => !leapExcludedNetworks.has(network), + ), +); + +export const cosmosWallets = new Set([ + WalletId.Keplr, + // WalletId.Leap // @TODO: Enable when ready +]); + +export const cosmosStakingNetworks = new Set([ + ...Array.from(cosmosWallets.has(WalletId.Keplr) ? keplrNetworks : []), + ...Array.from(cosmosWallets.has(WalletId.Leap) ? leapNetworks : []), +]); diff --git a/src/screens/staking/lib/staking_sdk/core/index.ts b/src/screens/staking/lib/staking_sdk/core/index.ts new file mode 100644 index 00000000..aff27b1d --- /dev/null +++ b/src/screens/staking/lib/staking_sdk/core/index.ts @@ -0,0 +1,81 @@ +import type { NetworkKey } from "@src/utils/network_info"; + +import type { + AccountDetailResponse, + ClaimableRewardsResponse, +} from "../staking_client_types"; +import type { CoinDenom, WalletId } from "./base"; +import { StakingNetworkId } from "./base"; +import { cosmosStakingNetworks, cosmosWallets } from "./cosmos"; + +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 networkIdToNetworkKey: Record = { + [StakingNetworkId.Akash]: "akash", + [StakingNetworkId.Celestia]: "celestia", + [StakingNetworkId.CelestiaTestnet]: "celestia-testnet", + [StakingNetworkId.ComposableFinance]: "composable-finance", + [StakingNetworkId.CosmosHub]: "cosmos", + [StakingNetworkId.CosmosHubTestnet]: "cosmos-testnet", + [StakingNetworkId.DyDx]: "dydx", + [StakingNetworkId.Kava]: "kava", + [StakingNetworkId.KavaTestnet]: "kava-testnet", + [StakingNetworkId.Osmosis]: "osmosis", + [StakingNetworkId.Regen]: "regen", + [StakingNetworkId.Stargaze]: "stargaze", + [StakingNetworkId.StargazeTestnet]: "stargaze-testnet", +}; + +export const networkKeyToNetworkId: { [key in NetworkKey]?: StakingNetworkId } = + Object.fromEntries( + Object.entries(networkIdToNetworkKey) + .filter(([k]) => networksWithStaking.has(k as StakingNetworkId)) + .map(([k, v]) => [v, k]), + ); + +export type Account = { + address: string; + info?: AccountDetailResponse; + networkId: StakingNetworkId; + rewards?: ClaimableRewardsResponse; + wallet: WalletId; +}; + +type StakeAction = "claim_rewards" | "connect_wallet" | "stake" | "unstake"; + +type SelectedAccount = { + address: string; + networkId: StakingNetworkId; + wallet: WalletId; +}; + +export type Wallet = { + name?: string; + networks: { + [key in StakingNetworkId]?: { + accounts: Account[]; + networkId: StakingNetworkId; + }; + }; + wallet: WalletId; +}; + +export type StakingNetworkInfo = { + apy: number; + rpc: string; + unbonding_period: null | string; + voting_power: number; +}; + +export type StakingState = { + coinsPrices: { [key in CoinDenom]?: string }; + hasInit: boolean; + networksInfo: { [key in StakingNetworkId]?: StakingNetworkInfo }; + selectedAccount: null | SelectedAccount; + selectedAction: null | StakeAction; + wallets: { [key in WalletId]?: Wallet }; +}; diff --git a/src/screens/staking/lib/staking_sdk/formatters.ts b/src/screens/staking/lib/staking_sdk/formatters.ts index 9c2dfc45..79f0631f 100644 --- a/src/screens/staking/lib/staking_sdk/formatters.ts +++ b/src/screens/staking/lib/staking_sdk/formatters.ts @@ -1,6 +1,6 @@ import BigNumber from "bignumber.js"; -import type { Coin } from "./core"; +import type { Coin } from "./core/base"; import { normaliseCoin } from "./utils/coins"; type FormatOpts = { diff --git a/src/screens/staking/lib/staking_sdk/gecko_client.ts b/src/screens/staking/lib/staking_sdk/gecko_client.ts index af1a5c77..801a0aa0 100644 --- a/src/screens/staking/lib/staking_sdk/gecko_client.ts +++ b/src/screens/staking/lib/staking_sdk/gecko_client.ts @@ -1,6 +1,6 @@ import { IS_E2E } from "@src/utils/e2e"; -import { CoinDenom } from "./core"; +import { CoinDenom } from "./core/base"; export type CoinsPricesResult = { [key in CoinDenom]?: string }; diff --git a/src/screens/staking/lib/staking_sdk/staking_client.ts b/src/screens/staking/lib/staking_sdk/staking_client.ts index e39eb4d4..d32c856e 100644 --- a/src/screens/staking/lib/staking_sdk/staking_client.ts +++ b/src/screens/staking/lib/staking_sdk/staking_client.ts @@ -1,7 +1,6 @@ import BigNumber from "bignumber.js"; -import type { StakingNetworkId } from "@src/screens/staking/lib/staking_sdk/core"; - +import type { StakingNetworkId } from "./core/base"; import type { AccountDetailResponse, ClaimableRewardsResponse, @@ -46,6 +45,10 @@ const parseStakingRewards = async (res: ClaimableRewardsResponse) => : res; type StakeResponse = { + ethAccount?: { + account_number: string; + sequence: number; + }; tx: { authInfo: { fee: { diff --git a/src/screens/staking/lib/staking_sdk/utils/accounts.ts b/src/screens/staking/lib/staking_sdk/utils/accounts.ts index e561c902..4713e601 100644 --- a/src/screens/staking/lib/staking_sdk/utils/accounts.ts +++ b/src/screens/staking/lib/staking_sdk/utils/accounts.ts @@ -4,7 +4,8 @@ import BigNumber from "bignumber.js"; import { getNetworkInfo } from "@src/utils/network_info"; import type { Account } from "../core"; -import { networkIdToNetworkKey, testnetNetworks } from "../core"; +import { networkIdToNetworkKey } from "../core"; +import { testnetNetworks } from "../core/base"; import { normaliseCoin, sumAllCoins, sumCoins } from "./coins"; import { sortNetworksByName } from "./networks"; diff --git a/src/screens/staking/lib/staking_sdk/utils/coins.ts b/src/screens/staking/lib/staking_sdk/utils/coins.ts index ad74da6f..23357d0d 100644 --- a/src/screens/staking/lib/staking_sdk/utils/coins.ts +++ b/src/screens/staking/lib/staking_sdk/utils/coins.ts @@ -1,7 +1,7 @@ import BigNumber from "bignumber.js"; -import type { Coin } from "../core"; -import { CoinDenom, StakingNetworkId } from "../core"; +import type { Coin } from "../core/base"; +import { CoinDenom, StakingNetworkId } from "../core/base"; export const networkToUnnormalisedDenom = { [StakingNetworkId.Akash]: "UAKT", diff --git a/src/screens/staking/lib/staking_sdk/utils/networks.ts b/src/screens/staking/lib/staking_sdk/utils/networks.ts index 452a65a6..d0da3948 100644 --- a/src/screens/staking/lib/staking_sdk/utils/networks.ts +++ b/src/screens/staking/lib/staking_sdk/utils/networks.ts @@ -1,6 +1,6 @@ import type { Network, NetworkKey } from "@src/utils/network_info"; -import type { NetworkInfo } from "../core"; +import type { StakingNetworkInfo } from "../core"; import { networkKeyToNetworkId } from "../core"; export const sortNetworksByName = (a: Network, b: Network) => { @@ -19,7 +19,7 @@ export const sortNetworksByName = (a: Network, b: Network) => { }; export const getUnbondingTimeForNetwork = ( - networkInfo: NetworkInfo | null, + networkInfo: null | StakingNetworkInfo, locale?: string, ) => { if (!networkInfo) { diff --git a/src/screens/staking/lib/staking_sdk/utils/storage.ts b/src/screens/staking/lib/staking_sdk/utils/storage.ts index a2e93060..913420f7 100644 --- a/src/screens/staking/lib/staking_sdk/utils/storage.ts +++ b/src/screens/staking/lib/staking_sdk/utils/storage.ts @@ -1,4 +1,4 @@ -import { WalletId } from "../core"; +import { WalletId } from "../core/base"; const localStorageKey = "connectedWallets"; diff --git a/src/screens/staking/lib/staking_sdk/utils/wallets.ts b/src/screens/staking/lib/staking_sdk/utils/wallets.ts index 68b72e55..fff24fd1 100644 --- a/src/screens/staking/lib/staking_sdk/utils/wallets.ts +++ b/src/screens/staking/lib/staking_sdk/utils/wallets.ts @@ -1,3 +1,3 @@ -import type { WalletId } from "../core"; +import type { WalletId } from "../core/base"; export const sortWallets = (a: WalletId, b: WalletId) => a.localeCompare(b); diff --git a/src/screens/staking/lib/staking_sdk/wallet_operations.ts b/src/screens/staking/lib/staking_sdk/wallet_operations.ts index caa2bab2..db1fe6ec 100644 --- a/src/screens/staking/lib/staking_sdk/wallet_operations.ts +++ b/src/screens/staking/lib/staking_sdk/wallet_operations.ts @@ -1,6 +1,7 @@ import type { TStakingContext } from "./context"; -import type { Coin, StakingNetworkId } from "./core"; -import { WalletId, keplrNetworks, leapNetworks } from "./core"; +import type { Coin, StakingNetworkId } from "./core/base"; +import { WalletId } from "./core/base"; +import { keplrNetworks, leapNetworks } from "./core/cosmos"; import type { ClaimOpts, ClaimRewardsError, 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 3b0aed58..3cd4e9bc 100644 --- a/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts +++ b/src/screens/staking/lib/staking_sdk/wallet_operations/cosmos.ts @@ -1,11 +1,12 @@ import type { EncodeObject } from "@cosmjs/proto-signing"; +import { SigningStargateClient } from "@cosmjs/stargate"; import type { MsgDelegateEncodeObject, MsgUndelegateEncodeObject, MsgWithdrawDelegatorRewardEncodeObject, StdFee, + Event as TxEvent, } from "@cosmjs/stargate"; -import { SigningStargateClient } from "@cosmjs/stargate"; import type { AccountData } from "@keplr-wallet/types"; import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; import { @@ -20,14 +21,15 @@ import { toastError, toastSuccess } from "@src/components/notification"; import type { TStakingContext } from "../context"; import { fetchAccountData, setUserWallet } from "../context/actions"; import { getHasConnectedWallet } from "../context/selectors"; -import type { Account, Coin, StakingNetworkId, Wallet } from "../core"; +import type { Account, Wallet } from "../core"; +import { networksWithStaking } from "../core"; +import type { Coin, StakingNetworkId } from "../core/base"; +import { WalletId } from "../core/base"; import { - WalletId, keplrNetworks, keplrNonNativeChains, leapNetworks, - networksWithStaking, -} from "../core"; +} from "../core/cosmos"; import { stakingClient } from "../staking_client"; import { addToConnectedWallets, getConnectedWallets } from "../utils/storage"; import type { @@ -39,8 +41,17 @@ import type { } from "./base"; import { ClaimRewardsError, StakeError, UnstakeError } from "./base"; +type TxEventType = "delegate" | "unbond" | "withdraw_rewards"; + +const verifyEvent = (eventName: TxEventType) => (events?: readonly TxEvent[]) => + !!events?.find((ev) => ev.type === eventName); + +const verifyDelegate = verifyEvent("delegate"); +const verifyWithdraw = verifyEvent("withdraw_rewards"); +const verifyUnbond = verifyEvent("unbond"); + type FeeOpts = { - address: string; + account: Account; amount: Coin[]; client: SigningStargateClient; gasLimit: string; @@ -49,7 +60,7 @@ type FeeOpts = { }; const getCosmosFee = async ({ - address, + account, amount, client, gasLimit, @@ -57,7 +68,7 @@ const getCosmosFee = async ({ msgs, }: FeeOpts) => { const gasEstimate = await client - .simulate(address, msgs, memo) + .simulate(account.address, msgs, memo) .catch((err) => { // eslint-disable-next-line no-console console.log("debug: wallet_operations.ts: Estimate error", err); @@ -147,7 +158,7 @@ export const stakeAmountCosmos = ({ ); const fee = await getCosmosFee({ - address: account.address, + account, amount: info.tx.authInfo.fee.amount, client, gasLimit: info.tx.authInfo.fee.gas_limit, @@ -155,37 +166,34 @@ export const stakeAmountCosmos = ({ msgs: [msgAny], }); + const handleSuccess = (events?: readonly TxEvent[]) => { + const hasDelegated = verifyDelegate(events); + + return hasDelegated + ? ({ success: true } as const) + : { error: StakeError.NotEnoughGas, success: false }; + }; + + const handleError = (err: Error) => + ( + ({ + [CosmosError.None]: { error: StakeError.None, success: false }, + [CosmosError.NotEnoughGas]: { + error: StakeError.NotEnoughGas, + success: false, + }, + [CosmosError.Success]: { success: true }, + [CosmosError.Unknown]: { + error: StakeError.Unknown, + success: false, + }, + }) satisfies Record> + )[getCosmosError(err)]; + return client .signAndBroadcast(account.address, [msgAny], fee, memo) - .then((result) => { - const hasDelegated = !!result?.events?.find( - (ev) => ev.type === "delegate", - ); - - return hasDelegated - ? ({ success: true } as const) - : { error: StakeError.NotEnoughGas, success: false }; - }) - .catch( - (err) => - ( - ({ - [CosmosError.None]: { error: StakeError.None, success: false }, - [CosmosError.NotEnoughGas]: { - error: StakeError.NotEnoughGas, - success: false, - }, - [CosmosError.Success]: { success: true }, - [CosmosError.Unknown]: { - error: StakeError.Unknown, - success: false, - }, - }) satisfies Record< - CosmosError, - WalletOperationResult - > - )[getCosmosError(err)], - ); + .then((result) => handleSuccess(result?.events)) + .catch(handleError); }); export const claimRewardsCosmos = async ({ @@ -225,7 +233,7 @@ export const claimRewardsCosmos = async ({ ); const fee = await getCosmosFee({ - address: account.address, + account, amount: info.tx.authInfo.fee.amount, client, gasLimit: info.tx.authInfo.fee.gas_limit, @@ -233,40 +241,40 @@ export const claimRewardsCosmos = async ({ msgs: [msgAny], }); + const handleSuccess = (events?: readonly TxEvent[]) => { + const hasClaimed = !!verifyWithdraw(events); + + return hasClaimed + ? ({ success: true } as const) + : { error: ClaimRewardsError.NotEnoughGas, success: false }; + }; + + const handleError = (err: Error) => + ( + ({ + [CosmosError.None]: { + error: ClaimRewardsError.None, + success: false, + }, + [CosmosError.NotEnoughGas]: { + error: ClaimRewardsError.NotEnoughGas, + success: false, + }, + [CosmosError.Success]: { success: true }, + [CosmosError.Unknown]: { + error: ClaimRewardsError.Unknown, + success: false, + }, + }) satisfies Record< + CosmosError, + WalletOperationResult + > + )[getCosmosError(err)]; + return client .signAndBroadcast(account.address, [msgAny], fee) - .then((result) => { - const hasClaimed = !!result?.events?.find( - (ev) => ev.type === "withdraw_rewards", - ); - - return hasClaimed - ? ({ success: true } as const) - : { error: ClaimRewardsError.NotEnoughGas, success: false }; - }) - .catch( - (err) => - ( - ({ - [CosmosError.None]: { - error: ClaimRewardsError.None, - success: false, - }, - [CosmosError.NotEnoughGas]: { - error: ClaimRewardsError.NotEnoughGas, - success: false, - }, - [CosmosError.Success]: { success: true }, - [CosmosError.Unknown]: { - error: ClaimRewardsError.Unknown, - success: false, - }, - }) satisfies Record< - CosmosError, - WalletOperationResult - > - )[getCosmosError(err)], - ); + .then((result) => handleSuccess(result?.events)) + .catch(handleError); }); export const getCosmosClaimRewardsFee = async ({ @@ -322,7 +330,7 @@ export const unstakeCosmos = async ( ); const fee = await getCosmosFee({ - address: opts.account.address, + account: opts.account, amount: info.tx.authInfo.fee.amount, client, gasLimit: info.tx.authInfo.fee.gas_limit, @@ -330,43 +338,40 @@ export const unstakeCosmos = async ( msgs: [msgAny], }); + const handleSuccess = (events?: readonly TxEvent[]) => { + const hasUnbonded = verifyUnbond(events); + + return hasUnbonded + ? ({ success: true } as const) + : { + error: UnstakeError.NotEnoughGas, + success: false, + }; + }; + + const handleError = (err: Error) => + ( + ({ + [CosmosError.None]: { + error: UnstakeError.None, + success: false, + }, + [CosmosError.NotEnoughGas]: { + error: UnstakeError.NotEnoughGas, + success: false, + }, + [CosmosError.Success]: { success: true }, + [CosmosError.Unknown]: { + error: UnstakeError.Unknown, + success: false, + }, + }) satisfies Record> + )[getCosmosError(err)]; + return client .signAndBroadcast(opts.account.address, [msgAny], fee, opts.memo) - .then((result) => { - const hasUnbonded = !!result?.events?.find( - (ev) => ev.type === "unbond", - ); - - return hasUnbonded - ? ({ success: true } as const) - : { - error: UnstakeError.NotEnoughGas, - success: false, - }; - }) - .catch( - (err) => - ( - ({ - [CosmosError.None]: { - error: UnstakeError.None, - success: false, - }, - [CosmosError.NotEnoughGas]: { - error: UnstakeError.NotEnoughGas, - success: false, - }, - [CosmosError.Success]: { success: true }, - [CosmosError.Unknown]: { - error: UnstakeError.Unknown, - success: false, - }, - }) satisfies Record< - CosmosError, - WalletOperationResult - > - )[getCosmosError(err)], - ); + .then((result) => handleSuccess(result?.events)) + .catch(handleError); }); export const tryToConnectKeplr = async ( diff --git a/src/screens/staking/lib/wallet_info.ts b/src/screens/staking/lib/wallet_info.ts index fc693bd4..60365907 100644 --- a/src/screens/staking/lib/wallet_info.ts +++ b/src/screens/staking/lib/wallet_info.ts @@ -4,7 +4,7 @@ import type { FC } from "react"; import IconKeplr from "@src/components/icons/keplr.svg"; import IconLeap from "@src/components/icons/leap.svg"; -import { WalletId } from "./staking_sdk/core"; +import { WalletId } from "./staking_sdk/core/base"; export const walletsIcons: Record> = { [WalletId.Keplr]: IconKeplr, diff --git a/src/utils/network_info.ts b/src/utils/network_info.ts index 8e034992..a1dd96b2 100644 --- a/src/utils/network_info.ts +++ b/src/utils/network_info.ts @@ -1,4 +1,4 @@ -import { ENABLE_TESTNETS } from "@src/screens/staking/lib/staking_sdk/core"; +import { ENABLE_TESTNETS } from "@src/screens/staking/lib/staking_sdk/core/base"; export type Network = { address?: string; @@ -266,6 +266,12 @@ const networks = { key: "dydx", name: "dydx", }, + "dymension": { + graphql: "dymension", + image: "/images/network/dymension.svg", + key: "dymension", + name: "Dymension", + }, "e-money": { address: "emoneyvaloper1293pqwtzu67zp8txuya4yts03ccw5kgf98hz9y", bigDipper: "https://e-money.network/", @@ -309,7 +315,7 @@ const networks = { denom: "evmos", graphql: "evmos", guide: "how-to-stake-evmos-on-evmos", - image: "/images/network/evmos.png", + image: "/images/network/evmos.svg", key: "evmos", label: "Evmos - EVMOS", name: "Evmos", @@ -801,6 +807,7 @@ export const cosmosNetworkKeys = [ "crescent", "crypto.org", "dydx", + "dymension", "e-money", "evmos", "fetch-ai",