diff --git a/.env.example b/.env.example
index 6b59863c..d244241d 100644
--- a/.env.example
+++ b/.env.example
@@ -1,6 +1,5 @@
NEXT_PUBLIC_MEMPOOL_API=https://mempool.space
NEXT_PUBLIC_API_URL=https://staking-api.phase-2-devnet.babylonlabs.io
-NEXT_PUBLIC_POINTS_API_URL=https://points.testnet.babylonchain.io
NEXT_PUBLIC_NETWORK=signet
NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=true
NEXT_PUBLIC_SENTRY_DSN=http://f4de35dcc28cf83853663a4a6d2ee496@127.0.0.1:9000/1
\ No newline at end of file
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 55c9243f..12bfd8c5 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -39,7 +39,6 @@ jobs:
build-args: |
NEXT_PUBLIC_MEMPOOL_API=${{ vars.NEXT_PUBLIC_MEMPOOL_API }}
NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }}
- NEXT_PUBLIC_POINTS_API_URL=${{ vars.NEXT_PUBLIC_POINTS_API_URL }}
NEXT_PUBLIC_NETWORK=${{ vars.NEXT_PUBLIC_NETWORK }}
NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=${{ vars.NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES }}
NEXT_PUBLIC_SENTRY_DSN=${{ vars.NEXT_PUBLIC_SENTRY_DSN }}
diff --git a/README.md b/README.md
index 9b97fce3..f370b0ef 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,6 @@ where,
node queries
- `NEXT_PUBLIC_API_URL` specifies the back-end API to use for the staking
system queries
-- `NEXT_PUBLIC_POINTS_API_URL` specifies the Points API to use for the points
- system (Optional)
- `NEXT_PUBLIC_NETWORK` specifies the BTC network environment
- `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES` boolean value to indicate whether display
testing network related message. Default to true
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 5d6e2328..04b677fc 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -20,9 +20,6 @@ ENV NEXT_PUBLIC_MEMPOOL_API=${NEXT_PUBLIC_MEMPOOL_API}
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
-ARG NEXT_PUBLIC_POINTS_API_URL
-ENV NEXT_PUBLIC_POINTS_API_URL=${NEXT_PUBLIC_POINTS_API_URL}
-
ARG NEXT_PUBLIC_NETWORK
ENV NEXT_PUBLIC_NETWORK=${NEXT_PUBLIC_NETWORK}
diff --git a/src/app/api/getPoints.ts b/src/app/api/getPoints.ts
deleted file mode 100644
index df9601f5..00000000
--- a/src/app/api/getPoints.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { encode } from "url-safe-base64";
-
-import { Pagination } from "../types/api";
-
-import { pointsApiWrapper } from "./pointsApiWrapper";
-
-interface StakerPointsAPIResponse {
- data: StakerPointsAPI[];
-}
-
-export interface StakerPointsAPI {
- staker_btc_pk: string;
- points: number;
-}
-
-export interface DelegationPointsAPI {
- staking_tx_hash_hex: string;
- staker: {
- pk: string;
- points: number;
- };
- finality_provider: {
- pk: string;
- points: number;
- };
- staking_height: number;
- unbonding_height: number | null;
- expiry_height: number;
-}
-
-interface PaginatedDelegationsPointsAPIResponse {
- data: DelegationPointsAPI[];
- pagination: Pagination;
-}
-
-export const getStakersPoints = async (
- stakerBtcPks: string[],
-): Promise => {
- const params = new URLSearchParams();
-
- stakerBtcPks.forEach((pk) => {
- params.append("staker_btc_pk", encode(pk));
- });
-
- const response = await pointsApiWrapper(
- "GET",
- "/v1/points/stakers",
- "Error getting staker points",
- params,
- );
-
- const responseData: StakerPointsAPIResponse = response.data;
- return responseData.data;
-};
-
-// Get delegation points by staking transaction hash hex
-export const getDelegationPointsByStakingTxHashHexes = async (
- stakingTxHashHexes: string[],
-): Promise => {
- try {
- const response = await pointsApiWrapper(
- "POST",
- "/v1/points/delegations",
- "Error getting delegation points by staking transaction hashes",
- { staking_tx_hash_hex: stakingTxHashHexes },
- );
-
- const responseData: PaginatedDelegationsPointsAPIResponse = response.data;
- return responseData.data;
- } catch (error) {
- throw error;
- }
-};
diff --git a/src/app/api/pointsApiWrapper.ts b/src/app/api/pointsApiWrapper.ts
deleted file mode 100644
index c48b9566..00000000
--- a/src/app/api/pointsApiWrapper.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import axios from "axios";
-
-export const pointsApiWrapper = async (
- method: "GET" | "POST",
- path: string,
- generalErrorMessage: string,
- params?: any,
- timeout?: number,
-) => {
- let response;
- let handler;
- switch (method) {
- case "GET":
- handler = axios.get;
- break;
- case "POST":
- handler = axios.post;
- break;
- default:
- throw new Error("Invalid method");
- }
-
- try {
- // destructure params in case of post request
- response = await handler(
- `${process.env.NEXT_PUBLIC_POINTS_API_URL}${path}`,
- method === "POST"
- ? { ...params }
- : {
- params,
- },
- {
- timeout: timeout || 0, // 0 is no timeout
- },
- );
- } catch (error) {
- if (axios.isAxiosError(error)) {
- const message = error?.response?.data?.message;
- throw new Error(message || generalErrorMessage);
- } else {
- throw new Error(generalErrorMessage);
- }
- }
- return response;
-};
diff --git a/src/app/components/Delegations/Delegations.tsx b/src/app/components/Delegations/Delegations.tsx
index a0528ecf..589704c2 100644
--- a/src/app/components/Delegations/Delegations.tsx
+++ b/src/app/components/Delegations/Delegations.tsx
@@ -1,6 +1,5 @@
import { Heading } from "@babylonlabs-io/bbn-core-ui";
-import type { networks } from "bitcoinjs-lib";
-import { useEffect, useMemo, useState } from "react";
+import { useEffect, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { useLocalStorage } from "usehooks-ts";
@@ -10,73 +9,30 @@ import {
MODE_WITHDRAW,
WithdrawModal,
} from "@/app/components/Modals/WithdrawModal";
-import { DelegationsPointsProvider } from "@/app/context/api/DelegationsPointsProvider";
import { useError } from "@/app/context/Error/ErrorContext";
import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useDelegations } from "@/app/hooks/client/api/useDelegations";
-import { useHealthCheck } from "@/app/hooks/useHealthCheck";
+import { useNetworkFees } from "@/app/hooks/client/api/useNetworkFees";
+import { useV1TransactionService } from "@/app/hooks/services/useV1TransactionService";
import { useDelegationState } from "@/app/state/DelegationState";
import {
Delegation as DelegationInterface,
DelegationState,
} from "@/app/types/delegations";
import { ErrorState } from "@/app/types/errors";
-import { shouldDisplayPoints } from "@/config";
-import { signWithdrawalTx } from "@/utils/delegations/signWithdrawalTx";
import { getIntermediateDelegationsLocalStorageKey } from "@/utils/local_storage/getIntermediateDelegationsLocalStorageKey";
import { toLocalStorageIntermediateDelegation } from "@/utils/local_storage/toLocalStorageIntermediateDelegation";
import { Delegation } from "./Delegation";
-export const Delegations = () => {
- const { data: delegationsAPI } = useDelegations();
- const { address, publicKeyNoCoord, connected, network } = useBTCWallet();
-
- if (!connected || !delegationsAPI || !network) {
- return;
- }
-
- return (
-
- {/* If there are no delegations, don't render the content */}
- {delegationsAPI.delegations.length > 0 && (
-
- )}
-
- );
-};
-
-interface DelegationsContentProps {
- delegationsAPI: DelegationInterface[];
- publicKeyNoCoord: string;
- btcWalletNetwork: networks.Network;
- address: string;
- isWalletConnected: boolean;
-}
-
-const DelegationsContent: React.FC = ({
- delegationsAPI,
- address,
- btcWalletNetwork,
- publicKeyNoCoord,
-}) => {
+export const Delegations = ({}) => {
+ const { publicKeyNoCoord, connected, network } = useBTCWallet();
const [modalOpen, setModalOpen] = useState(false);
const [txID, setTxID] = useState("");
const [modalMode, setModalMode] = useState();
- const { showError, captureError } = useError();
- const { isApiNormal, isGeoBlocked } = useHealthCheck();
+ const { showError } = useError();
const [awaitingWalletResponse, setAwaitingWalletResponse] = useState(false);
+ const { data: delegationsAPI } = useDelegations();
const {
delegations = [],
fetchMoreDelegations,
@@ -84,16 +40,13 @@ const DelegationsContent: React.FC = ({
isLoading,
} = useDelegationState();
- const { signPsbt, getNetworkFees, pushTx } = useBTCWallet();
+ const { submitWithdrawalTx } = useV1TransactionService();
+ const { data: networkFees } = useNetworkFees();
- const delegation = useMemo(
- () =>
- delegationsAPI.find((delegation) => delegation.stakingTxHashHex === txID),
- [delegationsAPI, txID],
+ const selectedDelegation = delegationsAPI?.delegations.find(
+ (delegation) => delegation.stakingTxHashHex === txID,
);
- const shouldShowPoints =
- isApiNormal && !isGeoBlocked && shouldDisplayPoints();
// Local storage state for intermediate delegations (transitioning, withdrawing)
const intermediateDelegationsLocalStorageKey =
getIntermediateDelegationsLocalStorageKey(publicKeyNoCoord);
@@ -141,24 +94,37 @@ const DelegationsContent: React.FC = ({
};
// Handles withdrawing requests for delegations that have expired timelocks
- // It constructs a withdrawal transaction, creates a signature for it, and submits it to the Bitcoin network
+ // It constructs a withdrawal transaction, creates a signature for it,
+ // and submits it to the Bitcoin network
const handleWithdraw = async (id: string) => {
try {
+ if (!networkFees) {
+ throw new Error("Network fees not found");
+ }
// Prevent the modal from closing
setAwaitingWalletResponse(true);
+
+ if (selectedDelegation?.stakingTxHashHex != id) {
+ throw new Error("Wrong delegation selected for withdrawal");
+ }
// Sign the withdrawal transaction
- const { delegation } = await signWithdrawalTx(
- id,
- delegationsAPI,
- publicKeyNoCoord,
- btcWalletNetwork,
- signPsbt,
- address,
- getNetworkFees,
- pushTx,
+ const { stakingTx, finalityProviderPkHex, stakingValueSat, unbondingTx } =
+ selectedDelegation;
+ submitWithdrawalTx(
+ {
+ stakingTimelock: stakingTx.timelock,
+ finalityProviderPkNoCoordHex: finalityProviderPkHex,
+ stakingAmountSat: stakingValueSat,
+ },
+ stakingTx.startHeight,
+ stakingTx.txHex,
+ unbondingTx?.txHex,
);
// Update the local state with the new intermediate delegation
- updateLocalStorage(delegation, DelegationState.INTERMEDIATE_WITHDRAWAL);
+ updateLocalStorage(
+ selectedDelegation,
+ DelegationState.INTERMEDIATE_WITHDRAWAL,
+ );
} catch (error: Error | any) {
showError({
error: {
@@ -192,7 +158,7 @@ const DelegationsContent: React.FC = ({
}
return intermediateDelegations.filter((intermediateDelegation) => {
- const matchingDelegation = delegationsAPI.find(
+ const matchingDelegation = delegationsAPI.delegations.find(
(delegation) =>
delegation?.stakingTxHashHex ===
intermediateDelegation?.stakingTxHashHex,
@@ -223,7 +189,7 @@ const DelegationsContent: React.FC = ({
}, [delegationsAPI, setIntermediateDelegationsLocalStorage]);
useEffect(() => {
- if (modalOpen && !delegation) {
+ if (modalOpen && !selectedDelegation) {
showError({
error: {
message: "Delegation not found",
@@ -235,11 +201,15 @@ const DelegationsContent: React.FC = ({
setTxID("");
setModalMode(undefined);
}
- }, [modalOpen, delegation, showError]);
+ }, [modalOpen, selectedDelegation, showError]);
+
+ if (!connected || !delegationsAPI || !network) {
+ return;
+ }
// combine delegations from the API and local storage, prioritizing API data
const combinedDelegationsData = delegationsAPI
- ? [...delegations, ...delegationsAPI]
+ ? [...delegations, ...delegationsAPI.delegations]
: // if no API data, fallback to using only local storage delegations
delegations;
@@ -296,7 +266,7 @@ const DelegationsContent: React.FC = ({
- {modalMode && txID && delegation && (
+ {modalMode && txID && selectedDelegation && (
setModalOpen(false)}
diff --git a/src/app/components/FAQ/data/questions.tsx b/src/app/components/FAQ/data/questions.tsx
index 2a028d99..d59cd26b 100644
--- a/src/app/components/FAQ/data/questions.tsx
+++ b/src/app/components/FAQ/data/questions.tsx
@@ -1,6 +1,6 @@
import { ReactNode } from "react";
-import { shouldDisplayPoints, shouldDisplayTestingMsg } from "@/config";
+import { shouldDisplayTestingMsg } from "@/config";
export interface Question {
title: string;
@@ -291,21 +291,6 @@ export const questions = (
),
},
];
- if (shouldDisplayPoints()) {
- questionList.push({
- title: "What are the points for?",
- content: (
-
- We use points to track staking activity. Points are not blockchain
- tokens. Points do not, and may never, convert to, accrue to, be used
- as a basis to calculate, or become tokens, other digital assets, or
- distributions thereof. Points are virtual calculations with no
- monetary value. Points do not constitute any currency or property of
- any type and are not redeemable, refundable, or transferable.
-
- ),
- });
- }
if (shouldDisplayTestingMsg()) {
questionList.push({
title: "What is the goal of this testnet?",
diff --git a/src/app/components/Modals/PreviewModal.tsx b/src/app/components/Modals/PreviewModal.tsx
index a7069c7c..445a3f26 100644
--- a/src/app/components/Modals/PreviewModal.tsx
+++ b/src/app/components/Modals/PreviewModal.tsx
@@ -25,7 +25,7 @@ interface PreviewModalProps {
finalityProvider: string | undefined;
finalityProviderAvatar: string | undefined;
stakingAmountSat: number;
- stakingTimeBlocks: number;
+ stakingTimelock: number;
stakingFeeSat: number;
feeRate: number;
unbondingFeeSat: number;
@@ -38,7 +38,7 @@ export const PreviewModal = ({
finalityProvider,
finalityProviderAvatar,
stakingAmountSat,
- stakingTimeBlocks,
+ stakingTimelock,
onSign,
stakingFeeSat,
feeRate,
@@ -99,7 +99,7 @@ export const PreviewModal = ({
{
key: "Term",
value: (
- {blocksToDisplayTime(stakingTimeBlocks)}
+ {blocksToDisplayTime(stakingTimelock)}
),
},
{
diff --git a/src/app/components/PersonalBalance/PersonalBalance.tsx b/src/app/components/PersonalBalance/PersonalBalance.tsx
index afede1d4..3f224aad 100644
--- a/src/app/components/PersonalBalance/PersonalBalance.tsx
+++ b/src/app/components/PersonalBalance/PersonalBalance.tsx
@@ -24,17 +24,17 @@ export function PersonalBalance() {
const { getRewards } = useRewardsService();
const { claimRewards } = useRewardsService();
- const { data: rewards } = useQuery({
+ const { data: rewards, isLoading: rewardsLoading } = useQuery({
queryKey: [QUERY_KEYS.REWARDS],
queryFn: getRewards,
});
- const { data: btcBalance } = useQuery({
+ const { data: btcBalance, isLoading: btcBalanceLoading } = useQuery({
queryKey: [QUERY_KEYS.BTC_BALANCE],
queryFn: getBTCBalance,
});
- const { data: cosmosBalance } = useQuery({
+ const { data: cosmosBalance, isLoading: cosmosBalanceLoading } = useQuery({
queryKey: [QUERY_KEYS.COSMOS_BALANCE],
queryFn: getBalance,
});
@@ -52,7 +52,7 @@ export function PersonalBalance() {
{/* TODO: Need to add the staker tvl value for the bitcoin balance
as well as remove the filtering on inscription balance*/}
@@ -60,7 +60,7 @@ export function PersonalBalance() {
@@ -68,7 +68,7 @@ export function PersonalBalance() {
@@ -76,7 +76,7 @@ export function PersonalBalance() {
= ({
- stakingTxHashHex,
- className,
-}) => {
- const { isApiNormal, isGeoBlocked } = useHealthCheck();
- const { delegationPoints, isLoading } = useDelegationsPoints();
- // Early return if the API is not normal or the user is geo-blocked
- if (!isApiNormal || isGeoBlocked || !shouldDisplayPoints()) {
- return null;
- }
-
- const points = delegationPoints.get(stakingTxHashHex);
- if (isLoading) {
- return (
-
- );
- }
-
- return (
-
- );
-};
diff --git a/src/app/components/Points/Points.tsx b/src/app/components/Points/Points.tsx
deleted file mode 100644
index 815cb2a8..00000000
--- a/src/app/components/Points/Points.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from "react";
-import { NumericFormat } from "react-number-format";
-import { Tooltip } from "react-tooltip";
-
-interface PointsProps {
- points: number | undefined;
-}
-
-export const Points: React.FC = ({ points }) => {
- if (points === undefined || points === 0) {
- return <>n.a.>;
- }
-
- if (points < 0.001 && points > 0) {
- return (
- <>
-
- <0.001
-
-
- >
- );
- }
-
- return (
-
- );
-};
diff --git a/src/app/components/Points/StakerPoints.tsx b/src/app/components/Points/StakerPoints.tsx
deleted file mode 100644
index b3ab859a..00000000
--- a/src/app/components/Points/StakerPoints.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { useQuery } from "@tanstack/react-query";
-import React from "react";
-
-import { getStakersPoints } from "@/app/api/getPoints";
-
-import { Points } from "./Points";
-
-interface StakerPointsProps {
- publicKeyNoCoord: string;
-}
-
-export const StakerPoints: React.FC = ({
- publicKeyNoCoord,
-}) => {
- const { data: stakerPoints, isLoading } = useQuery({
- queryKey: ["stakerPoints", publicKeyNoCoord],
- queryFn: () => getStakersPoints([publicKeyNoCoord]),
- enabled: Boolean(publicKeyNoCoord),
- refetchInterval: 300000, // Refresh every 5 minutes
- refetchOnWindowFocus: false,
- retry: 1,
- });
-
- if (isLoading) {
- return (
-
- );
- }
-
- const points = stakerPoints?.[0]?.points;
-
- return (
-
- );
-};
diff --git a/src/app/components/Staking/Form/StakingTime.tsx b/src/app/components/Staking/Form/StakingTime.tsx
index 8d6ea79b..42eb1b45 100644
--- a/src/app/components/Staking/Form/StakingTime.tsx
+++ b/src/app/components/Staking/Form/StakingTime.tsx
@@ -14,7 +14,6 @@ interface StakingTimeProps {
export const StakingTime: React.FC = ({
minStakingTimeBlocks,
maxStakingTimeBlocks,
- unbondingTimeBlocks,
onStakingTimeBlocksChange,
reset,
}) => {
diff --git a/src/app/components/Staking/Staking.tsx b/src/app/components/Staking/Staking.tsx
index bf518f8d..349e8236 100644
--- a/src/app/components/Staking/Staking.tsx
+++ b/src/app/components/Staking/Staking.tsx
@@ -542,7 +542,7 @@ export const Staking = () => {
finalityProvider?.description.identity
}
stakingAmountSat={stakingAmountSat}
- stakingTimeBlocks={stakingTimeBlocksWithFixed}
+ stakingTimelock={stakingTimeBlocksWithFixed}
stakingFeeSat={stakingFeeSat}
feeRate={feeRate}
unbondingFeeSat={unbondingFeeSat}
diff --git a/src/app/components/Summary/Summary.tsx b/src/app/components/Summary/Summary.tsx
index 1e8d2589..c9762fc2 100644
--- a/src/app/components/Summary/Summary.tsx
+++ b/src/app/components/Summary/Summary.tsx
@@ -4,23 +4,19 @@ import { Tooltip } from "react-tooltip";
import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider";
import { useNetworkInfo } from "@/app/hooks/client/api/useNetworkInfo";
-import { useHealthCheck } from "@/app/hooks/useHealthCheck";
import { useAppState } from "@/app/state";
import { useDelegationState } from "@/app/state/DelegationState";
-import { shouldDisplayPoints } from "@/config";
import { getNetworkConfig } from "@/config/network.config";
import { satoshiToBtc } from "@/utils/btc";
import { maxDecimals } from "@/utils/maxDecimals";
import { Network } from "@/utils/wallet/btc_wallet_provider";
import { LoadingSmall } from "../Loading/Loading";
-import { StakerPoints } from "../Points/StakerPoints";
export const Summary = () => {
- const { isApiNormal, isGeoBlocked } = useHealthCheck();
const { totalStaked } = useDelegationState();
const { totalBalance, isLoading: loading } = useAppState();
- const { address, publicKeyNoCoord } = useBTCWallet();
+ const { address } = useBTCWallet();
const { coinName } = getNetworkConfig();
const onMainnet = getNetworkConfig().network === Network.MAINNET;
@@ -58,30 +54,6 @@ export const Summary = () => {
- {isApiNormal && !isGeoBlocked && shouldDisplayPoints() && (
- <>
-
-
- >
- )}
diff --git a/src/app/context/api/DelegationsPointsProvider.tsx b/src/app/context/api/DelegationsPointsProvider.tsx
deleted file mode 100644
index 40a906eb..00000000
--- a/src/app/context/api/DelegationsPointsProvider.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { useQuery } from "@tanstack/react-query";
-import React, { createContext, useContext, useEffect, useState } from "react";
-
-import { getDelegationPointsByStakingTxHashHexes } from "@/app/api/getPoints";
-import { useHealthCheck } from "@/app/hooks/useHealthCheck";
-import { Delegation } from "@/app/types/delegations";
-import { shouldDisplayPoints } from "@/config";
-
-interface PointsContextType {
- delegationPoints: Map
;
- isLoading: boolean;
- error: Error | null;
-}
-
-interface DelegationsPointsProviderProps {
- children: React.ReactNode;
- publicKeyNoCoord: string;
- delegationsAPI: Delegation[];
- isWalletConnected: boolean;
- address: string;
-}
-
-const MAX_DELEGATION_POINTS_BATCH_SIZE = 200;
-const DelegationsPointsContext = createContext(
- undefined,
-);
-
-export const useDelegationsPoints = () => {
- const context = useContext(DelegationsPointsContext);
- if (context === undefined) {
- throw new Error(
- "useDelegationsPoints must be used within a DelegationsPointsProvider",
- );
- }
- return context;
-};
-
-export const DelegationsPointsProvider: React.FC<
- DelegationsPointsProviderProps
-> = ({
- children,
- publicKeyNoCoord,
- delegationsAPI,
- isWalletConnected,
- address,
-}) => {
- const [delegationPoints, setDelegationPoints] = useState