diff --git a/src/app/api/getDelegations.ts b/src/app/api/getDelegations.ts index e0ef035a..d4f2c609 100644 --- a/src/app/api/getDelegations.ts +++ b/src/app/api/getDelegations.ts @@ -24,7 +24,6 @@ interface DelegationAPI { staking_tx: StakingTxAPI; unbonding_tx?: UnbondingTxAPI; is_overflow: boolean; - transitioned: boolean; is_eligible_for_transition: boolean; } @@ -49,13 +48,12 @@ export const getDelegations = async ( throw new Error("No public key provided"); } - // const limit = 100; - // const reverse = false; - const params = { pagination_key: encode(key), staker_btc_pk: encode(publicKeyNoCoord), - state: ["active", "unbonded"], + // We only fetch for states that can have pending actions. + // We don't care terminal states such as "withdrawn" or "transitioned". + state: ["active", "unbonded", "unbonding", "unbonding_requested"], }; const response = await apiWrapper( diff --git a/src/app/api/getGlobalParams.ts b/src/app/api/getGlobalParams.ts deleted file mode 100644 index 97c180c6..00000000 --- a/src/app/api/getGlobalParams.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { AxiosResponse } from "axios"; - -import { GlobalParamsVersion } from "../types/globalParams"; - -import { apiWrapper } from "./apiWrapper"; - -interface GlobalParamsDataResponse { - versions: { - version: number; - activation_height: number; - staking_cap: number; - cap_height: number; - tag: string; - covenant_pks: string[]; - covenant_quorum: number; - unbonding_time: number; - unbonding_fee: number; - max_staking_amount: number; - min_staking_amount: number; - max_staking_time: number; - min_staking_time: number; - confirmation_depth: number; - }[]; -} - -export const getGlobalParams = async (): Promise => { - const { data } = (await apiWrapper( - "GET", - "/v1/global-params", - "Error getting global params", - )) as AxiosResponse<{ data: GlobalParamsDataResponse }>; - const { versions } = data.data; - - // covert them into GlobalParamsVersion - return versions.map((v) => ({ - version: v.version, - activationHeight: v.activation_height, - stakingCapSat: v.staking_cap, - stakingCapHeight: v.cap_height, - tag: v.tag, - covenantPks: v.covenant_pks, - covenantQuorum: v.covenant_quorum, - unbondingTime: v.unbonding_time, - unbondingFeeSat: v.unbonding_fee, - maxStakingAmountSat: v.max_staking_amount, - minStakingAmountSat: v.min_staking_amount, - maxStakingTimeBlocks: v.max_staking_time, - minStakingTimeBlocks: v.min_staking_time, - confirmationDepth: v.confirmation_depth, - })); -}; diff --git a/src/app/components/Summary/Summary.tsx b/src/app/components/Summary/Summary.tsx deleted file mode 100644 index c9762fc2..00000000 --- a/src/app/components/Summary/Summary.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { AiOutlineInfoCircle } from "react-icons/ai"; -import { FaBitcoin } from "react-icons/fa"; -import { Tooltip } from "react-tooltip"; - -import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider"; -import { useNetworkInfo } from "@/app/hooks/client/api/useNetworkInfo"; -import { useAppState } from "@/app/state"; -import { useDelegationState } from "@/app/state/DelegationState"; -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"; - -export const Summary = () => { - const { totalStaked } = useDelegationState(); - const { totalBalance, isLoading: loading } = useAppState(); - const { address } = useBTCWallet(); - - const { coinName } = getNetworkConfig(); - const onMainnet = getNetworkConfig().network === Network.MAINNET; - const { data: networkInfo } = useNetworkInfo(); - const confirmationDepth = - networkInfo?.params.btcEpochCheckParams?.latestParam - ?.btcConfirmationDepth || 10; - - if (!address) return; - - return ( -
-

Your staking summary

-
-
-
-
-
-

Total staked

- - - - -
-
- -

- {totalStaked ? maxDecimals(satoshiToBtc(totalStaked), 8) : 0}{" "} - {coinName} -

-
-
-
-
-
-

Stakable Balance

- - - - -
-
- - {typeof totalBalance === "number" ? ( -

- {maxDecimals(satoshiToBtc(totalBalance), 8)} {coinName} -

- ) : loading ? ( - - ) : ( - "n.a." - )} -
-
-
-
- {!onMainnet && ( - - Get Test Tokens - - )} -
-
- ); -}; diff --git a/src/app/state/DelegationState.tsx b/src/app/state/DelegationState.tsx index 2ee95b1d..a30faf78 100644 --- a/src/app/state/DelegationState.tsx +++ b/src/app/state/DelegationState.tsx @@ -4,7 +4,6 @@ import { useLocalStorage } from "usehooks-ts"; import { useBTCWallet } from "@/app/context/wallet/BTCWalletProvider"; import { useDelegations } from "@/app/hooks/client/api/useDelegations"; import type { Delegation } from "@/app/types/delegations"; -import { DelegationState as DelegationEnum } from "@/app/types/delegations"; import { createStateUtils } from "@/utils/createStateUtils"; import { calculateDelegationsDiff } from "@/utils/local_storage/calculateDelegationsDiff"; import { getDelegationsLocalStorageKey as getDelegationsKey } from "@/utils/local_storage/getDelegationsLocalStorageKey"; @@ -12,7 +11,6 @@ import { getDelegationsLocalStorageKey as getDelegationsKey } from "@/utils/loca interface DelegationState { isLoading: boolean; hasMoreDelegations: boolean; - totalStaked: number; delegations: Delegation[]; addDelegation: (delegation: Delegation) => void; fetchMoreDelegations: () => void; @@ -21,7 +19,6 @@ interface DelegationState { const { StateProvider, useState } = createStateUtils({ isLoading: false, delegations: [], - totalStaked: 0, hasMoreDelegations: false, addDelegation: () => null, fetchMoreDelegations: () => null, @@ -57,18 +54,6 @@ export function DelegationState({ children }: PropsWithChildren) { [data?.delegations, setDelegations, delegations], ); - // Computed - const totalStaked = useMemo( - () => - (data?.delegations ?? []) - .filter((delegation) => delegation?.state === DelegationEnum.ACTIVE) - .reduce( - (accumulator: number, item) => accumulator + item?.stakingValueSat, - 0, - ), - [data?.delegations], - ); - // Methods const addDelegation = useCallback( (newDelegation: Delegation) => { @@ -92,7 +77,6 @@ export function DelegationState({ children }: PropsWithChildren) { const state = useMemo( () => ({ delegations, - totalStaked, isLoading: isFetchingNextPage, hasMoreDelegations: hasNextPage, addDelegation, @@ -100,7 +84,6 @@ export function DelegationState({ children }: PropsWithChildren) { }), [ delegations, - totalStaked, isFetchingNextPage, hasNextPage, addDelegation, diff --git a/src/app/types/globalParams.ts b/src/app/types/globalParams.ts deleted file mode 100644 index 3f1ccabc..00000000 --- a/src/app/types/globalParams.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface GlobalParamsVersion { - version: number; - activationHeight: number; - stakingCapSat: number; - stakingCapHeight: number; - tag: string; - covenantPks: string[]; - covenantQuorum: number; - unbondingTime: number; - unbondingFeeSat: number; - maxStakingAmountSat: number; - minStakingAmountSat: number; - maxStakingTimeBlocks: number; - minStakingTimeBlocks: number; - confirmationDepth: number; -} diff --git a/src/utils/apiDataToStakingScripts.ts b/src/utils/apiDataToStakingScripts.ts deleted file mode 100644 index a94d4bff..00000000 --- a/src/utils/apiDataToStakingScripts.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { - ObservableStakingScriptData, - StakingScripts, -} from "@babylonlabs-io/btc-staking-ts"; - -import { GlobalParamsVersion } from "@/app/types/globalParams"; -import { getPublicKeyNoCoord } from "@/utils/wallet/index"; - -// Used to recreate scripts from the data received from the API -export const apiDataToStakingScripts = ( - finalityProviderPkHex: string, - stakingTxTimelock: number, - globalParams: GlobalParamsVersion, - publicKeyNoCoord: string, -): StakingScripts => { - if (!globalParams || !publicKeyNoCoord) { - throw new Error("Invalid data"); - } - - // Convert covenant PKs to buffers - const covenantPKsBuffer = globalParams?.covenantPks?.map((pk) => - getPublicKeyNoCoord(pk), - ); - - // Create staking script data - let stakingScriptData; - try { - stakingScriptData = new ObservableStakingScriptData( - Buffer.from(publicKeyNoCoord, "hex"), - [Buffer.from(finalityProviderPkHex, "hex")], - covenantPKsBuffer, - globalParams.covenantQuorum, - stakingTxTimelock, - globalParams.unbondingTime, - Buffer.from(globalParams.tag, "hex"), - ); - } catch (error: Error | any) { - throw new Error(error?.message || "Cannot build staking script data"); - } - - // Build scripts - let scripts; - try { - scripts = stakingScriptData.buildScripts(); - } catch (error: Error | any) { - throw new Error(error?.message || "Error while recreating scripts"); - } - - return scripts; -}; diff --git a/src/utils/params/globalParams.ts b/src/utils/params/globalParams.ts deleted file mode 100644 index 8ceeb529..00000000 --- a/src/utils/params/globalParams.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { GlobalParamsVersion } from "@/app/types/globalParams"; - -export interface ParamsWithContext { - currentVersion?: GlobalParamsVersion; - nextVersion?: GlobalParamsVersion; - isApprochingNextVersion: boolean; - firstActivationHeight: number; -} - -// This function returns the current global params version and whether the next version is approaching -// The current version is the one that is active at the current height -// Return currentVersion being undefined if no version is found, -// which means the current height is lower than the first version -export const getCurrentGlobalParamsVersion = ( - height: number, - versionedParams: GlobalParamsVersion[], -): ParamsWithContext => { - if (!versionedParams.length) { - throw new Error("No global params versions found"); - } - // Step 1: Sort the versions in descending order based on activationHeight - // Note, we have cloned the array to avoid mutating the original array - const sorted = [...versionedParams].sort( - (a, b) => b.activationHeight - a.activationHeight, - ); - - const firstActivationHeight = sorted[sorted.length - 1].activationHeight; - - for (let i = 0; i < sorted.length; i++) { - const curr = sorted[i]; - let isApprochingNextVersion = false; - let nextVersion: GlobalParamsVersion | undefined; - // Check if the current version is active at the given height - if (curr.activationHeight <= height) { - // Check if the next version is approaching - if (sorted[i - 1]) { - // Return the current version and whether the next version is approaching - if (sorted[i - 1].activationHeight <= height + curr.confirmationDepth) { - isApprochingNextVersion = true; - } - nextVersion = sorted[i - 1]; - } - // Return the current version if the next version is not approaching - return { - currentVersion: curr, - nextVersion, - isApprochingNextVersion, - firstActivationHeight, - }; - } - } - return { - currentVersion: undefined, - nextVersion: undefined, - isApprochingNextVersion: false, - firstActivationHeight, - }; -}; diff --git a/tests/helper/index.ts b/tests/helper/index.ts index 26370053..616df89f 100644 --- a/tests/helper/index.ts +++ b/tests/helper/index.ts @@ -1,13 +1,8 @@ -import { - initBTCCurve, - ObservableStakingScriptData, - StakingScripts, -} from "@babylonlabs-io/btc-staking-ts"; +import { initBTCCurve } from "@babylonlabs-io/btc-staking-ts"; import * as ecc from "@bitcoin-js/tiny-secp256k1-asmjs"; import * as bitcoin from "bitcoinjs-lib"; import ECPairFactory from "ecpair"; -import { GlobalParamsVersion } from "@/app/types/globalParams"; import { getPublicKeyNoCoord } from "@/utils/wallet"; import { UTXO } from "@/utils/wallet/btc_wallet_provider"; @@ -98,122 +93,10 @@ export class DataGenerator { return buffer; }; - // Generate a single global param - generateRandomGlobalParams = ( - isFixedTimelock = false, - previousPram: GlobalParamsVersion | undefined = undefined, - ) => { - const stakingTerm = this.generateRandomStakingTerm(); - const committeeSize = Math.floor(Math.random() * 20) + 5; - const covenantPks = this.generateRandomCovenantCommittee(committeeSize).map( - (buffer) => buffer.toString("hex"), - ); - const covenantQuorum = Math.floor(Math.random() * (committeeSize - 1)) + 1; - const unbondingTime = this.generateRandomUnbondingTime(stakingTerm); - const tag = this.generateRandomTag().toString("hex"); - - let minStakingTimeBlocks = this.getRandomIntegerBetween(1, 100); - let maxStakingTimeBlocks = - minStakingTimeBlocks + this.getRandomIntegerBetween(1, 1000); - if (isFixedTimelock) { - maxStakingTimeBlocks = minStakingTimeBlocks; - } - - const minStakingAmountSat = this.getRandomIntegerBetween(10000, 100000); - const maxStakingAmountSat = this.getRandomIntegerBetween( - minStakingAmountSat, - 100000000, - ); - - const defaultParams = { - version: 0, - activationHeight: 0, - stakingCapSat: 0, - stakingCapHeight: 0, - covenantPks: covenantPks, - covenantQuorum: covenantQuorum, - }; - const prev = previousPram ? previousPram : defaultParams; - - return { - version: prev.version + 1, - activationHeight: - prev.activationHeight + this.getRandomIntegerBetween(0, 10000), - stakingCapSat: - prev.stakingCapSat + this.getRandomIntegerBetween(0, 10000), - stakingCapHeight: - prev.stakingCapHeight + Math.floor(Math.random() * 10000), - covenantPks: prev.covenantPks, - covenantQuorum: prev.covenantQuorum, - unbondingFeeSat: this.getRandomIntegerBetween(0, 100), - maxStakingAmountSat, - minStakingAmountSat, - maxStakingTimeBlocks, - minStakingTimeBlocks, - confirmationDepth: this.getRandomIntegerBetween(1, 20), - unbondingTime, - tag, - }; - }; - - // Generate a list of global params - generateGlobalPramsVersions = ( - numVersions: number, - ): GlobalParamsVersion[] => { - let versions = []; - let lastVersion; - for (let i = 0; i < numVersions; i++) { - const isFixedTimelock = Math.random() > 0.5; - versions.push( - this.generateRandomGlobalParams(isFixedTimelock, lastVersion), - ); - lastVersion = versions[i]; - } - return versions; - }; - getNetwork = () => { return this.network; }; - generateMockStakingScripts = ( - globalParams: GlobalParamsVersion, - publicKeyNoCoord: string, - finalityProviderPk: string, - stakingTxTimelock: number, - ): StakingScripts => { - // Convert covenant PKs to buffers - const covenantPKsBuffer = globalParams.covenantPks.map((pk: string) => - Buffer.from(pk, "hex"), - ); - - // Create staking script data - let stakingScriptData; - try { - stakingScriptData = new ObservableStakingScriptData( - Buffer.from(publicKeyNoCoord, "hex"), - [Buffer.from(finalityProviderPk, "hex")], - covenantPKsBuffer, - globalParams.covenantQuorum, - stakingTxTimelock, - globalParams.unbondingTime, - Buffer.from(globalParams.tag, "hex"), - ); - } catch (error: Error | any) { - throw new Error(error?.message || "Cannot build staking script data"); - } - - // Build scripts - let scripts; - try { - scripts = stakingScriptData.buildScripts(); - } catch (error: Error | any) { - throw new Error(error?.message || "Error while recreating scripts"); - } - - return scripts; - }; - generateRandomUTXOs = ( minAvailableBalance: number, numberOfUTXOs: number, diff --git a/tests/utils/apiDataToStakingScripts.test.ts b/tests/utils/apiDataToStakingScripts.test.ts deleted file mode 100644 index 19ccc27a..00000000 --- a/tests/utils/apiDataToStakingScripts.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as bitcoin from "bitcoinjs-lib"; - -import { apiDataToStakingScripts } from "@/utils/apiDataToStakingScripts"; - -import { DataGenerator } from "../helper"; - -describe("apiDataToStakingScripts", () => { - const dataGen = new DataGenerator(bitcoin.networks.testnet); - it("should throw an error if the publicKeyNoCoord is not set", () => { - const { noCoordPublicKey: finalityProviderPk } = - dataGen.generateRandomKeyPair(); - const stakingTxTimelock = dataGen.generateRandomStakingTerm(); - const globalParams = dataGen.generateRandomGlobalParams(); - expect(() => { - apiDataToStakingScripts( - finalityProviderPk, - stakingTxTimelock, - globalParams, - "", - ); - }).toThrow("Invalid data"); - }); -}); diff --git a/tests/utils/globalParams.test.ts b/tests/utils/globalParams.test.ts deleted file mode 100644 index d7316a4b..00000000 --- a/tests/utils/globalParams.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { GlobalParamsVersion } from "@/app/types/globalParams"; -import { getCurrentGlobalParamsVersion } from "@/utils/params/globalParams"; - -import { testingNetworks } from "../helper"; - -describe("globalParams", () => { - const { dataGenerator } = testingNetworks[0]; - let globalParams: GlobalParamsVersion[]; - let lastActivationHeight: number; - let firstActivationHeight: number; - - beforeEach(() => { - globalParams = dataGenerator.generateGlobalPramsVersions( - dataGenerator.getRandomIntegerBetween(2, 100), - ); - lastActivationHeight = - globalParams[globalParams.length - 1].activationHeight; - firstActivationHeight = globalParams[0].activationHeight; - }); - - it("should not modify the original globalParams array", () => { - const clonedGlobalParams = [...globalParams]; - getCurrentGlobalParamsVersion(0, globalParams); - expect(globalParams).toEqual(clonedGlobalParams); - }); - - it("should get the correct currentVersion global param", () => { - const randomHeight = dataGenerator.getRandomIntegerBetween( - firstActivationHeight, - lastActivationHeight + 1, - ); - const clonedGlobalParams = [...globalParams]; - const { currentVersion } = getCurrentGlobalParamsVersion( - randomHeight, - globalParams, - ); - const expected = clonedGlobalParams - .sort((a, b) => b.activationHeight - a.activationHeight) - .find((v) => v.activationHeight <= randomHeight); - expect(currentVersion).toEqual(expected); - }); - - it("should return undefined currentVersion if the height is lower than the first version", () => { - const randomHeight = dataGenerator.getRandomIntegerBetween( - 0, - firstActivationHeight - 1, - ); - const { - currentVersion, - nextVersion, - isApprochingNextVersion, - firstActivationHeight: firstHeight, - } = getCurrentGlobalParamsVersion(randomHeight, globalParams); - expect(currentVersion).toBeUndefined(); - expect(nextVersion).toBeUndefined(); - expect(isApprochingNextVersion).toBeFalsy(); - expect(firstHeight).toEqual(firstActivationHeight); - }); - - it("should return correct values before next activation height", () => { - const param = globalParams[0]; - let approachingHeight = param.activationHeight - 1; - let result = getCurrentGlobalParamsVersion(approachingHeight, globalParams); - expect(result.currentVersion).toBeUndefined(); - expect(result.nextVersion).toBeUndefined(); - expect(result.isApprochingNextVersion).toBeFalsy(); - // after passed the first activation height - result = getCurrentGlobalParamsVersion( - param.activationHeight, - globalParams, - ); - expect(result.currentVersion).toEqual(param); - expect(result.nextVersion).toEqual(globalParams[1]); - expect(result.isApprochingNextVersion).toBeFalsy(); - }); - - it("should return correct values after the last activation height", () => { - const lastParamIndex = globalParams.length - 1; - const param = globalParams[lastParamIndex]; - // last version - const lastConfirmationDepth = - globalParams[lastParamIndex - 1].confirmationDepth; - // before approaching - let approachingHeight = param.activationHeight - lastConfirmationDepth - 1; - let result = getCurrentGlobalParamsVersion(approachingHeight, globalParams); - expect(result.currentVersion).toEqual(globalParams[lastParamIndex - 1]); - expect(result.nextVersion).toEqual(param); - expect(result.isApprochingNextVersion).toBeFalsy(); - // approaching - approachingHeight = param.activationHeight - lastConfirmationDepth; - result = getCurrentGlobalParamsVersion(approachingHeight, globalParams); - expect(result.currentVersion).toEqual(globalParams[lastParamIndex - 1]); - expect(result.nextVersion).toEqual(param); - expect(result.isApprochingNextVersion).toBeTruthy(); - // after approaching - result = getCurrentGlobalParamsVersion( - param.activationHeight, - globalParams, - ); - expect(result.currentVersion).toEqual(param); - expect(result.nextVersion).toBeUndefined(); - expect(result.isApprochingNextVersion).toBeFalsy(); - }); - - describe("should return correct values for params version that are not first or last", () => { - const globalParams = dataGenerator.generateGlobalPramsVersions(10); - const paramIndexes = globalParams.map((_, i) => i).slice(1, -1); - - it.each(paramIndexes)("param #%i", (index) => { - const param = globalParams[index]; - // before approaching - const lastConfirmationDepth = globalParams[index - 1].confirmationDepth; - // before approaching - let approachingHeight = - param.activationHeight - lastConfirmationDepth - 1; - let result = getCurrentGlobalParamsVersion( - approachingHeight, - globalParams, - ); - expect(result.currentVersion).toEqual(globalParams[index - 1]); - expect(result.nextVersion).toEqual(param); - expect(result.isApprochingNextVersion).toBeFalsy(); - // approaching - approachingHeight = param.activationHeight - lastConfirmationDepth; - result = getCurrentGlobalParamsVersion(approachingHeight, globalParams); - expect(result.currentVersion).toEqual(globalParams[index - 1]); - expect(result.nextVersion).toEqual(param); - expect(result.isApprochingNextVersion).toBeTruthy(); - // after approaching - result = getCurrentGlobalParamsVersion( - param.activationHeight, - globalParams, - ); - expect(result.currentVersion).toEqual(param); - expect(result.nextVersion).toEqual(globalParams[index + 1]); - expect(result.isApprochingNextVersion).toBeFalsy(); - }); - }); -});