Skip to content

Commit

Permalink
fix: update the states based on what backend return (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrwbabylonlab authored Nov 26, 2024
1 parent d6947ad commit 264ba9d
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 93 deletions.
14 changes: 3 additions & 11 deletions src/app/api/getDelegationsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { encode } from "url-safe-base64";
import { Pagination } from "../types/api";
import {
DelegationV2,
DelegationV2StakingStateMap,
getDelegationV2StakingState,
} from "../types/delegationsV2";

import { apiWrapper } from "./apiWrapper";
Expand Down Expand Up @@ -63,12 +63,7 @@ export const getDelegationV2 = async (

const delegationAPIResponse: DelegationV2APIResponse = response.data;

const state = DelegationV2StakingStateMap[delegationAPIResponse.data.state];
if (!state) {
throw new Error(
`Unknown delegation state: ${delegationAPIResponse.data.state}`,
);
}
const state = getDelegationV2StakingState(delegationAPIResponse.data.state);

return {
finalityProviderBtcPksHex:
Expand Down Expand Up @@ -120,10 +115,7 @@ export const getDelegationsV2 = async (

const delegations: DelegationV2[] = delegationsAPIResponse.data.map(
(apiDelegation: DelegationV2API): DelegationV2 => {
const state = DelegationV2StakingStateMap[apiDelegation.state];
if (!state) {
throw new Error(`Unknown delegation state: ${apiDelegation.state}`);
}
const state = getDelegationV2StakingState(apiDelegation.state);
return {
finalityProviderBtcPksHex: apiDelegation.finality_provider_btc_pks_hex,
stakingTxHex: apiDelegation.delegation_staking.staking_tx_hex,
Expand Down
10 changes: 4 additions & 6 deletions src/app/hooks/services/useTransactionService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
uint8ArrayToHex,
} from "@/utils/delegations";
import { getFeeRateFromMempool } from "@/utils/getFeeRateFromMempool";
import { getTxHex, getTxMerkleProof, MerkleProof } from "@/utils/mempool_api";
import { getTxMerkleProof, MerkleProof } from "@/utils/mempool_api";

import { useNetworkFees } from "../api/useNetworkFees";

Expand Down Expand Up @@ -416,7 +416,7 @@ export const useTransactionService = () => {
);

/**
* Submit the early unbonded withdrawal transaction
* Withdraw from the early unbonding transaction which is now unbonded
*
* @param stakingInput - The staking inputs
* @param paramVersion - The param version
Expand Down Expand Up @@ -484,13 +484,13 @@ export const useTransactionService = () => {
*
* @param stakingInput - The staking inputs
* @param paramVersion - The param version
* @param stakingTxHashHex - The staking transaction hash hex
* @param stakingTxHex - The staking transaction hex
*/
const submitTimelockUnbondedWithdrawalTx = useCallback(
async (
stakingInput: BtcStakingInputs,
paramVersion: number,
stakingTxHashHex: string,
stakingTxHex: string,
) => {
// Perform checks
if (!params || params.bbnStakingParams.versions.length === 0) {
Expand All @@ -515,8 +515,6 @@ export const useTransactionService = () => {
stakingInput.stakingTimeBlocks,
);

// Get the staking transaction hex from the mempool
const stakingTxHex = await getTxHex(stakingTxHashHex);
const { psbt } = staking.createWithdrawStakingExpiredTransaction(
Transaction.fromHex(stakingTxHex),
defaultFeeRate,
Expand Down
59 changes: 39 additions & 20 deletions src/app/types/delegationsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,50 @@ export interface DelegationV2 {
}

export enum DelegationV2StakingState {
// Basic states
PENDING = "PENDING",
VERIFIED = "VERIFIED",
ACTIVE = "ACTIVE",
UNBONDING = "UNBONDING",
WITHDRAWABLE = "WITHDRAWABLE",
WITHDRAWN = "WITHDRAWN",
INTERMEDIATE_PENDING_CONFIRMATION = "INTERMEDIATE_PENDING_CONFIRMATION",
INTERMEDIATE_UNBONDING = "INTERMEDIATE_UNBONDING",
INTERMEDIATE_WITHDRAWAL = "INTERMEDIATE_WITHDRAWAL",

// Unbonding states
TIMELOCK_UNBONDING = "TIMELOCK_UNBONDING",
EARLY_UNBONDING = "EARLY_UNBONDING",

// Withdrawable states
TIMELOCK_WITHDRAWABLE = "TIMELOCK_WITHDRAWABLE",
EARLY_UNBONDING_WITHDRAWABLE = "EARLY_UNBONDING_WITHDRAWABLE",
TIMELOCK_SLASHING_WITHDRAWABLE = "TIMELOCK_SLASHING_WITHDRAWABLE",
EARLY_UNBONDING_SLASHING_WITHDRAWABLE = "EARLY_UNBONDING_SLASHING_WITHDRAWABLE",

// Withdrawn states
TIMELOCK_WITHDRAWN = "TIMELOCK_WITHDRAWN",
EARLY_UNBONDING_WITHDRAWN = "EARLY_UNBONDING_WITHDRAWN",
TIMELOCK_SLASHING_WITHDRAWN = "TIMELOCK_SLASHING_WITHDRAWN",
EARLY_UNBONDING_SLASHING_WITHDRAWN = "EARLY_UNBONDING_SLASHING_WITHDRAWN",

// Slashed states
TIMELOCK_SLASHED = "TIMELOCK_SLASHED",
EARLY_UNBONDING_SLASHED = "EARLY_UNBONDING_SLASHED",

// Intermediate states
INTERMEDIATE_PENDING_VERIFICATION = "INTERMEDIATE_PENDING_VERIFICATION",
INTERMEDIATE_PENDING_BTC_CONFIRMATION = "INTERMEDIATE_PENDING_BTC_CONFIRMATION",
INTERMEDIATE_UNBONDING_SUBMITTED = "INTERMEDIATE_UNBONDING_SUBMITTED",
INTERMEDIATE_WITHDRAWAL_SUBMITTED = "INTERMEDIATE_WITHDRAWAL_SUBMITTED",
}

export const DelegationV2StakingStateMap: Record<
string,
DelegationV2StakingState
> = {
PENDING: DelegationV2StakingState.PENDING,
VERIFIED: DelegationV2StakingState.VERIFIED,
ACTIVE: DelegationV2StakingState.ACTIVE,
UNBONDING: DelegationV2StakingState.UNBONDING,
WITHDRAWABLE: DelegationV2StakingState.WITHDRAWABLE,
WITHDRAWN: DelegationV2StakingState.WITHDRAWN,
INTERMEDIATE_PENDING_CONFIRMATION:
DelegationV2StakingState.INTERMEDIATE_PENDING_CONFIRMATION,
INTERMEDIATE_UNBONDING: DelegationV2StakingState.INTERMEDIATE_UNBONDING,
INTERMEDIATE_WITHDRAWAL: DelegationV2StakingState.INTERMEDIATE_WITHDRAWAL,
export const getDelegationV2StakingState = (
state: string,
): DelegationV2StakingState => {
const validState = Object.values(DelegationV2StakingState).find(
(enumState) => enumState === state,
);

if (!validState) {
throw new Error(`Invalid delegation state: ${state}`);
}

return validState;
};

export interface DelegationV2Params {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ interface ActionButtonProps {
type ButtonAdapter = (props: ActionButtonProps) => JSX.Element;
type ButtonStrategy = Record<string, ButtonAdapter>;

const WithdrawButton = (props: ActionButtonProps) => (
<button
className="btn btn-outline btn-xs inline-flex text-sm font-normal text-primary-dark"
onClick={() => props.onClick?.("withdraw", props.txHash)}
disabled={props.state === state.INTERMEDIATE_WITHDRAWAL_SUBMITTED}
>
Withdraw
</button>
);

const ACTION_BUTTONS: ButtonStrategy = {
[state.VERIFIED]: (props: ActionButtonProps) => (
<button
className="btn btn-outline btn-xs inline-flex text-sm font-normal text-primary-dark"
onClick={() => props.onClick?.("stake", props.txHash)}
disabled={props.state === state.INTERMEDIATE_PENDING_CONFIRMATION}
disabled={props.state === state.INTERMEDIATE_PENDING_BTC_CONFIRMATION}
>
Stake
</button>
Expand All @@ -23,30 +33,23 @@ const ACTION_BUTTONS: ButtonStrategy = {
<button
className="btn btn-outline btn-xs inline-flex text-sm font-normal text-primary-dark"
onClick={() => props.onClick?.("unbound", props.txHash)}
disabled={props.state === state.INTERMEDIATE_UNBONDING}
disabled={props.state === state.INTERMEDIATE_UNBONDING_SUBMITTED}
>
Unbond
</button>
),
// TODO: Check which withdrawable state the delegation is in
// 1. EARLY_UNBONDED_WITHDRAWAL
// 2. NATURAL_UNBONDED_WITHDRAWAL
// 3. SLASHING_UNBONDED_WITHDRAWAL
// Below code is for the first state - EARLY_UNBONDED_WITHDRAWAL until
// the remaining other states are implemented
[state.WITHDRAWABLE]: (props: ActionButtonProps) => (
<button
className="btn btn-outline btn-xs inline-flex text-sm font-normal text-primary-dark"
onClick={() => props.onClick?.("withdraw", props.txHash)}
disabled={props.state === state.INTERMEDIATE_WITHDRAWAL}
>
Withdraw
</button>
),

[state.EARLY_UNBONDING_WITHDRAWABLE]: WithdrawButton,
[state.TIMELOCK_WITHDRAWABLE]: WithdrawButton,
[state.TIMELOCK_SLASHING_WITHDRAWABLE]: WithdrawButton,
[state.EARLY_UNBONDING_SLASHING_WITHDRAWABLE]: WithdrawButton,
};

export function ActionButton(props: ActionButtonProps) {
const Button = ACTION_BUTTONS[props.state];
if (!Button) {
return null;
}

return <Button {...props} />;
}
73 changes: 56 additions & 17 deletions src/components/delegations/DelegationList/components/Status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,81 @@ const STATUSES: Record<
string,
(param?: BbnStakingParamsVersion) => { label: string; tooltip: string }
> = {
[state.ACTIVE]: () => ({
label: "Active",
tooltip: "Stake is active",
[state.PENDING]: () => ({
label: "Pending",
tooltip: "Stake is pending verification",
}),
[state.VERIFIED]: () => ({
label: "Verified",
tooltip: "Stake is verified, you can start staking",
}),
[state.UNBONDING]: (param) => ({
[state.ACTIVE]: () => ({
label: "Active",
tooltip: "Stake is active",
}),
[state.TIMELOCK_UNBONDING]: (param) => ({
label: "Unbonding",
tooltip:
"Stake is about to be unbonded as it's reaching the timelock period",
}),
[state.EARLY_UNBONDING]: (param) => ({
label: "Unbonding",
tooltip: `Unbonding process of ${blocksToDisplayTime(param?.unbondingTime)} has started`,
}),
[state.WITHDRAWABLE]: () => ({
[state.TIMELOCK_WITHDRAWABLE]: () => ({
label: "Withdrawable",
tooltip: "Stake is withdrawable as it's reached the timelock period",
}),
[state.EARLY_UNBONDING_WITHDRAWABLE]: () => ({
label: "Withdrawable",
tooltip: "Stake is withdrawable after the unbonding period",
}),
[state.TIMELOCK_SLASHING_WITHDRAWABLE]: () => ({
label: "Withdrawable",
tooltip: "Slashed Stake is now withdrawable",
}),
[state.EARLY_UNBONDING_SLASHING_WITHDRAWABLE]: () => ({
label: "Withdrawable",
tooltip: "Stake is withdrawable",
tooltip: "Slashed Stake is now withdrawable",
}),
[state.TIMELOCK_SLASHED]: () => ({
label: "Slashed",
tooltip: "Stake has been slashed",
}),
[state.WITHDRAWN]: () => ({
[state.EARLY_UNBONDING_SLASHED]: () => ({
label: "Slashed",
tooltip: "Stake has been slashed",
}),
[state.TIMELOCK_WITHDRAWN]: () => ({
label: "Withdrawn",
tooltip: "Stake has been withdrawn",
}),
[state.PENDING]: () => ({
[state.EARLY_UNBONDING_WITHDRAWN]: () => ({
label: "Withdrawn",
tooltip: "Stake has been withdrawn",
}),
[state.EARLY_UNBONDING_SLASHING_WITHDRAWN]: () => ({
label: "Withdrawn",
tooltip: "Slashed Stake has been withdrawn",
}),
[state.TIMELOCK_SLASHING_WITHDRAWN]: () => ({
label: "Withdrawn",
tooltip: "Slashed Stake has been withdrawn",
}),
[state.INTERMEDIATE_PENDING_VERIFICATION]: () => ({
label: "Pending",
// TODO: get confirmation depth from params
// https://github.com/babylonlabs-io/simple-staking/issues/325
tooltip: `Stake that is pending ${10} Bitcoin confirmations will only be visible from this device`,
tooltip: "Stake is pending verification",
}),
[state.INTERMEDIATE_PENDING_CONFIRMATION]: () => ({
[state.INTERMEDIATE_PENDING_BTC_CONFIRMATION]: () => ({
label: "Pending",
tooltip: "Stake is pending confirmation",
tooltip: "Stake is pending 10 BTC confirmations",
}),
[state.INTERMEDIATE_UNBONDING]: () => ({
label: "Requesting Unbonding",
[state.INTERMEDIATE_UNBONDING_SUBMITTED]: () => ({
label: "Unbonding",
tooltip: "Stake is requesting unbonding",
}),
[state.INTERMEDIATE_WITHDRAWAL]: () => ({
label: "Withdrawal Submitted",
[state.INTERMEDIATE_WITHDRAWAL_SUBMITTED]: () => ({
label: "Withdrawal",
tooltip: "Withdrawal transaction pending confirmation on Bitcoin",
}),
};
Expand Down
Loading

0 comments on commit 264ba9d

Please sign in to comment.