diff --git a/README.md b/README.md index d484211..c50c0c0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Xion Staking +# XION Staking -A proof of concept application to stake tokens in Xion, using the native +A proof of concept application to stake tokens in XION, using the native authentication via the dashboard. diff --git a/src/features/core/components/base.tsx b/src/features/core/components/base.tsx index dec7424..b60c07f 100644 --- a/src/features/core/components/base.tsx +++ b/src/features/core/components/base.tsx @@ -95,7 +95,7 @@ export const ButtonPill = ({ {...props} className={[ "cursor-pointer rounded-full bg-bg-550 px-[8px] py-[4px] text-white hover:bg-bg-600 disabled:cursor-not-allowed disabled:bg-bg-600 disabled:text-typo-150", - variant === "danger" ? "[&]:text-danger" : "", + variant === "danger" ? "[&]:bg-dangerBg [&]:text-danger" : "", className, ].join(" ")} /> diff --git a/src/features/staking/components/delegation-details.tsx b/src/features/staking/components/delegation-details.tsx index 0126446..674d14c 100644 --- a/src/features/staking/components/delegation-details.tsx +++ b/src/features/staking/components/delegation-details.tsx @@ -254,8 +254,8 @@ const UnbondingRow = ({ onClick={() => { staking.dispatch( setModalOpened({ - content: { unbonding }, - type: "cancel-staking", + content: { unbondings: [unbonding] }, + type: "cancel-unstaking", }), ); }} diff --git a/src/features/staking/components/modals/cancel-unstaking.tsx b/src/features/staking/components/modals/cancel-unstaking.tsx index cfb8292..15a0841 100644 --- a/src/features/staking/components/modals/cancel-unstaking.tsx +++ b/src/features/staking/components/modals/cancel-unstaking.tsx @@ -6,10 +6,10 @@ import CommonModal, { ModalDescription, } from "@/features/core/components/common-modal"; -import { cancelUnstakingAction } from "../../context/actions"; +import { fetchUserDataAction } from "../../context/actions"; import { useStaking } from "../../context/hooks"; import { setModalOpened } from "../../context/reducer"; -import type { StakeAddresses } from "../../lib/core/tx"; +import { type StakeAddresses, cancelUnbonding } from "../../lib/core/tx"; type Step = "completed" | "confirm"; @@ -24,13 +24,13 @@ const CancelUnstakingModal = () => { const { modal } = staking.state; - const isOpen = modal?.type === "cancel-staking"; + const isOpen = modal?.type === "cancel-unstaking"; if (!isOpen) return null; - const { unbonding } = modal?.content || {}; + const { unbondings } = modal?.content || {}; - if (!unbonding) return null; + if (!unbondings?.length) return null; const content = (() => { if (currentStep === "confirm") { @@ -52,14 +52,21 @@ const CancelUnstakingModal = () => { setIsLoading(true); - const addresses: StakeAddresses = { - delegator: account.bech32Address, - validator: unbonding.validator, - }; + unbondings + .reduce(async (promise, unbonding) => { + await promise; + + const addresses: StakeAddresses = { + delegator: account.bech32Address, + validator: unbonding.validator, + }; + + await cancelUnbonding(addresses, unbonding, client); + }, Promise.resolve()) + .then(() => { + // Don't await for this so the button can be enabled earlier + fetchUserDataAction(account.bech32Address, staking); - cancelUnstakingAction(addresses, unbonding, client, staking) - .then((fetchFn) => { - fetchFn(); setStep("completed"); }) .catch(() => { diff --git a/src/features/staking/components/validator-delegation.tsx b/src/features/staking/components/validator-delegation.tsx index ae5977f..dcd2c41 100644 --- a/src/features/staking/components/validator-delegation.tsx +++ b/src/features/staking/components/validator-delegation.tsx @@ -71,6 +71,7 @@ export default function ValidatorDelegation() { const totalRewards = getTotalRewards(null, staking.state); const canShowDetail = getCanShowDetails(staking.state); + const unbondings = staking.state.unbondings?.items || []; const content = !isConnected ? (
@@ -163,6 +164,28 @@ export default function ValidatorDelegation() { {userTotalUnbondings ? formatXionToUSD(userTotalUnbondings) : "-"}
+ {!!unbondings?.length && ( +
+ + { + staking.dispatch( + setModalOpened({ + content: { + unbondings, + }, + type: "cancel-unstaking", + }), + ); + }} + variant="danger" + > + Cancel Unstake + + +
+ )} ); diff --git a/src/features/staking/context/actions.ts b/src/features/staking/context/actions.ts index 21871d6..1457664 100644 --- a/src/features/staking/context/actions.ts +++ b/src/features/staking/context/actions.ts @@ -13,7 +13,7 @@ import { import type { AbstraxionSigningClient } from "../lib/core/client"; import { sumAllCoins } from "../lib/core/coins"; import type { StakeAddresses } from "../lib/core/tx"; -import { cancelUnbonding, stakeAmount, unstakeAmount } from "../lib/core/tx"; +import { stakeAmount, unstakeAmount } from "../lib/core/tx"; import { addDelegations, addUnbondings, @@ -172,19 +172,6 @@ export const stakeValidatorAction = async ( }; }; -export const cancelUnstakingAction = async ( - addresses: StakeAddresses, - unbonding: Unbonding, - client: AbstraxionSigningClient, - staking: StakingContextType, -) => { - await cancelUnbonding(addresses, unbonding, client); - - return async () => { - await fetchUserDataAction(addresses.delegator, staking); - }; -}; - export const unstakeValidatorAction = async ( addresses: StakeAddresses, amount: Coin, diff --git a/src/features/staking/context/selectors.ts b/src/features/staking/context/selectors.ts index 6c6ed77..b2bae65 100644 --- a/src/features/staking/context/selectors.ts +++ b/src/features/staking/context/selectors.ts @@ -105,16 +105,16 @@ export const getAllValidators = ( Object.values(state.validators) .map((v) => v?.items) .flat() - .reduce((acc, v) => { - if (!v) { - return acc; - } + .reduce( + (acc, v) => { + if (v) { + acc[v.operatorAddress] = v; + } - return { - ...acc, - [v.operatorAddress]: v, - }; - }, state.extraValidators); + return acc; + }, + { ...state.extraValidators }, + ); // As discussed internally, in XION the APR is the same as the inflation export const getAPR = (state: StakingState) => diff --git a/src/features/staking/context/state.tsx b/src/features/staking/context/state.tsx index 0d9b149..30de6b9 100644 --- a/src/features/staking/context/state.tsx +++ b/src/features/staking/context/state.tsx @@ -35,8 +35,8 @@ type ModalContent = type: "rewards"; } | { - content: { unbonding: Unbonding }; - type: "cancel-staking"; + content: { unbondings: Unbonding[] }; + type: "cancel-unstaking"; } | { content: { validator: Validator }; diff --git a/tailwind.config.ts b/tailwind.config.ts index a5d8d61..43a727d 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -19,6 +19,7 @@ const config: Config = { 600: "#1A1A1A", }, danger: "#D74506", + dangerBg: "#402217", success: "#04C700", successBg: "#04C7001A", typo: {