Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: withdraw slashing tx #585

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions package-lock.json

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

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
"dependencies": {
"@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.5",
"@babylonlabs-io/bbn-core-ui": "0.6.10",
"@babylonlabs-io/bbn-wallet-connect": "0.1.31",
"@babylonlabs-io/btc-staking-ts": "0.4.0-canary.5",
"@babylonlabs-io/bbn-wallet-connect": "0.1.34",
"@babylonlabs-io/btc-staking-ts": "0.4.0-canary.6",
"@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3",
"@bitcoinerlab/secp256k1": "^1.1.1",
"@cosmjs/proto-signing": "^0.32.4",
Expand Down Expand Up @@ -104,4 +104,4 @@
"tr46": "4.0.0"
}
}
}
}
17 changes: 13 additions & 4 deletions src/app/components/Modals/SlashingModal.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import { Text } from "@babylonlabs-io/bbn-core-ui";

import { BbnStakingParamsVersion } from "@/app/types/networkInfo";
import { NetworkConfig } from "@/config/network";

import { ConfirmationModal } from "./ConfirmationModal";

interface UnbondModalProps {
processing: boolean;
open: boolean;
onClose: () => void;
onSubmit: () => void;
networkConfig: NetworkConfig;
param: BbnStakingParamsVersion | null;
}

export const SlashingModal = (props: UnbondModalProps) => {
const { networkConfig, param } = props;
const slashingRate = (param?.slashing?.slashingRate ?? 0) * 100;

return (
<ConfirmationModal title="Withdraw Non-Slashed Balance" {...props}>
<ConfirmationModal title="Withdraw Balance" {...props}>
<Text variant="body1" className="pt-8 pb-10">
The Finality Provider you delegated to has been slashed and removed from
the network. You can withdraw your non-slashed balance after the
timelock period ends. Slashed funds cannot be recovered.
Your finality provider equivocated(double-voted) leading to{" "}
{slashingRate}% of your stake getting slashed. You are about to withdraw
the remaining balance. A transaction fee will be deducted from your
stake by the {networkConfig.btc.networkName} network.
</Text>
</ConfirmationModal>
);
Expand Down
19 changes: 15 additions & 4 deletions src/app/hooks/services/useDelegationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
DelegationV2,
DelegationV2StakingState as State,
} from "@/app/types/delegationsV2";
import { BbnStakingParamsVersion } from "@/app/types/networkInfo";
import { validateDelegation } from "@/utils/delegations";
import { getBbnParamByVersion } from "@/utils/params";

import { useTransactionService } from "./useTransactionService";

Expand Down Expand Up @@ -40,6 +42,7 @@ type DelegationCommand = (props: TxProps) => Promise<void>;
interface ConfirmationModalState {
action: ActionType;
delegation: DelegationV2;
param: BbnStakingParamsVersion;
}

export function useDelegationService() {
Expand All @@ -49,7 +52,7 @@ export function useDelegationService() {
Record<string, boolean>
>({});

const { availableUTXOs = [] } = useAppState();
const { availableUTXOs = [], networkInfo } = useAppState();
const {
delegations = [],
fetchMoreDelegations,
Expand All @@ -63,6 +66,7 @@ export function useDelegationService() {
submitUnbondingTx,
submitEarlyUnbondedWithdrawalTx,
submitTimelockUnbondedWithdrawalTx,
submitSlashingWithdrawalTx,
} = useTransactionService();

const validations = useMemo(
Expand Down Expand Up @@ -167,7 +171,7 @@ export function useDelegationService() {
);
}

await submitEarlyUnbondedWithdrawalTx(
await submitSlashingWithdrawalTx(
stakingInput,
paramsVersion,
slashing.unbondingSlashingTxHex,
Expand Down Expand Up @@ -207,7 +211,7 @@ export function useDelegationService() {
throw new Error("Slashing tx not found, can't submit withdrawal");
}

await submitTimelockUnbondedWithdrawalTx(
await submitSlashingWithdrawalTx(
stakingInput,
paramsVersion,
slashing.stakingSlashingTxHex,
Expand All @@ -225,17 +229,24 @@ export function useDelegationService() {
submitUnbondingTx,
submitEarlyUnbondedWithdrawalTx,
submitTimelockUnbondedWithdrawalTx,
submitSlashingWithdrawalTx,
],
);

const openConfirmationModal = useCallback(
(action: ActionType, delegation: DelegationV2) => {
const param = getBbnParamByVersion(
delegation.paramsVersion,
networkInfo?.params.bbnStakingParams.versions || [],
);

setConfirmationModal({
action,
delegation,
param,
});
},
[],
[networkInfo],
);

const closeConfirmationModal = useCallback(
Expand Down
63 changes: 63 additions & 0 deletions src/app/hooks/services/useTransactionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,68 @@ export const useTransactionService = () => {
],
);

/**
* Submit the withdrawal transaction for a slashed staking
*
* @param stakingInput - The staking inputs
* @param paramVersion - The param version of the EOI
* @param slashingTxHex - The slashing transaction hex that to be withdrawn
*/
const submitSlashingWithdrawalTx = useCallback(
async (
stakingInput: BtcStakingInputs,
paramVersion: number,
slashingTxHex: string,
) => {
// Perform checks
if (!versionedParams || versionedParams?.length === 0) {
throw new Error("Params not loaded");
}
if (!btcConnected || !btcNetwork)
throw new Error("BTC Wallet not connected");

validateStakingInput(stakingInput);

const p = getBbnParamByVersion(paramVersion, versionedParams);
if (!p)
throw new Error(
`Unable to find staking params for version ${paramVersion}`,
);

const staking = new Staking(
btcNetwork!,
{
address,
publicKeyNoCoordHex: publicKeyNoCoord,
},
p,
stakingInput.finalityProviderPkNoCoordHex,
stakingInput.stakingTimelock,
);

const { psbt } = staking.createWithdrawSlashingTransaction(
Transaction.fromHex(slashingTxHex),
defaultFeeRate,
);

const signedWithdrawalPsbtHex = await signPsbt(psbt.toHex());
const signedWithdrawalTx = Psbt.fromHex(
signedWithdrawalPsbtHex,
).extractTransaction();
await pushTx(signedWithdrawalTx.toHex());
},
[
versionedParams,
btcConnected,
btcNetwork,
address,
publicKeyNoCoord,
signPsbt,
pushTx,
defaultFeeRate,
],
);

return {
createDelegationEoi,
estimateStakingFee,
Expand All @@ -614,6 +676,7 @@ export const useTransactionService = () => {
submitUnbondingTx,
submitEarlyUnbondedWithdrawalTx,
submitTimelockUnbondedWithdrawalTx,
submitSlashingWithdrawalTx,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ import { WithdrawModal } from "@/app/components/Modals/WithdrawModal";
import { DELEGATION_ACTIONS as ACTIONS } from "@/app/constants";
import { ActionType } from "@/app/hooks/services/useDelegationService";
import { DelegationV2 } from "@/app/types/delegationsV2";
import { BbnStakingParamsVersion } from "@/app/types/networkInfo";
import { NetworkConfig } from "@/config/network";

interface ConfirmationModalProps {
processing: boolean;
action: ActionType | undefined;
delegation: DelegationV2 | null;
onSubmit: (action: ActionType, delegation: DelegationV2) => void;
onClose: () => void;
networkConfig: NetworkConfig;
param: BbnStakingParamsVersion | null;
}

export function DelegationModal({
Expand Down
8 changes: 5 additions & 3 deletions src/components/delegations/DelegationList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { type DelegationV2 } from "@/app/types/delegationsV2";
import { GridTable, type TableColumn } from "@/components/common/GridTable";
import { FinalityProviderMoniker } from "@/components/delegations/DelegationList/components/FinalityProviderMoniker";
import { getNetworkConfigBBN } from "@/config/network/bbn";
import { getNetworkConfig } from "@/config/network";

import { ActionButton } from "./components/ActionButton";
import { Amount } from "./components/Amount";
Expand All @@ -21,7 +21,7 @@ type TableParams = {
handleActionClick: (action: ActionType, delegation: DelegationV2) => void;
};

const { networkFullName: bbnNetworkFullName } = getNetworkConfigBBN();
const networkConfig = getNetworkConfig();

const columns: TableColumn<DelegationV2, TableParams>[] = [
{
Expand Down Expand Up @@ -90,7 +90,7 @@ export function DelegationList() {
return (
<div className="bg-secondary-contrast p-6 border border-primary-dark/20">
<Heading variant="h6" className="text-primary-light py-2 mb-6">
{bbnNetworkFullName} Stakes
{networkConfig.bbn.networkFullName} Stakes
</Heading>

<GridTable
Expand All @@ -116,9 +116,11 @@ export function DelegationList() {
<DelegationModal
action={confirmationModal?.action}
delegation={confirmationModal?.delegation ?? null}
param={confirmationModal?.param ?? null}
processing={processing}
onSubmit={executeDelegationAction}
onClose={closeConfirmationModal}
networkConfig={networkConfig}
/>
</div>
);
Expand Down
17 changes: 17 additions & 0 deletions src/config/network/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BBNConfig, BTCConfig } from "@babylonlabs-io/bbn-wallet-connect";

import { getNetworkConfigBBN } from "./bbn";
import { getNetworkConfigBTC } from "./btc";

export interface NetworkConfig {
bbn: BBNConfig;
btc: BTCConfig;
}

// Get all network configs
export const getNetworkConfig = (): NetworkConfig => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shall slowly move config calls to this one instead of calling getNetworkConfigBBN and getNetworkConfigBTC individually.

return {
bbn: getNetworkConfigBBN(),
btc: getNetworkConfigBTC(),
};
};