@@ -447,11 +440,7 @@ const ManageStaking = (props: { isOpen: boolean; }) => {
metadata?.totalUserStaked.toString() !== "0" ? (
@@ -512,12 +501,12 @@ const ManageStaking = (props: { isOpen: boolean; }) => {
diff --git a/src/providers/balance.tsx b/src/providers/balance.tsx
new file mode 100644
index 0000000..5a5654e
--- /dev/null
+++ b/src/providers/balance.tsx
@@ -0,0 +1,42 @@
+import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
+import BigNumber from 'bignumber.js';
+import useApi from '../hooks/useApi';
+import useAccount from '../stores/account';
+
+interface BalanceContextType {
+ availableBalance: BigNumber;
+ reloadAccountInfo: () => void;
+}
+
+const BalanceContext = createContext({
+ availableBalance: new BigNumber(0),
+ reloadAccountInfo: () => { },
+});
+
+export const BalanceProvider = ({ children }: { children: ReactNode; }) => {
+ const [availableBalance, setAvailableBalance] = useState(new BigNumber(0));
+ const api = useApi();
+ const { selectedAccount } = useAccount();
+
+ const loadAccountInfo = useCallback(async () => {
+ if (!selectedAccount || !api) return;
+ const account = await api.query.system.account(selectedAccount.address);
+ const balance = account.toPrimitive() as { data: { free: string; }; };
+ const locked = (await api.query.ocifStaking.ledger(selectedAccount.address)).toPrimitive() as { locked: string; };
+ const currentBalance = new BigNumber(balance.data.free).minus(new BigNumber(locked.locked));
+
+ setAvailableBalance(currentBalance);
+ }, [api, selectedAccount]);
+
+ useEffect(() => {
+ loadAccountInfo();
+ }, [selectedAccount, api, loadAccountInfo]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useBalance = () => useContext(BalanceContext);
\ No newline at end of file
diff --git a/src/routes/staking.tsx b/src/routes/staking.tsx
index 9f1d851..9f55166 100644
--- a/src/routes/staking.tsx
+++ b/src/routes/staking.tsx
@@ -456,19 +456,19 @@ const Staking = () => {
setTotalUnclaimed(new BigNumber(0));
setUnclaimedEras({ cores: [], total: 0 });
- setClaimAllSuccess(result);
+ setClaimAllSuccess(true);
refreshQuery();
};
- const refreshQuery = () => {
+ const refreshQuery = useCallback(() => {
if (!claimAllSuccess) return;
reexecuteQuery({ requestPolicy: 'network-only' });
reexecuteCoreQuery({ requestPolicy: 'network-only' });
setClaimAllSuccess(false);
- };
+ }, [claimAllSuccess, reexecuteQuery, reexecuteCoreQuery]);
const disableClaiming = useMemo(() => {
- return isWaiting || unclaimedEras.total === 0 && totalUnclaimed.toNumber() > 0;
+ return isWaiting || unclaimedEras.total === 0 && totalUnclaimed.toNumber() === 0;
}, [isWaiting, unclaimedEras, totalUnclaimed]);
useEffect(() => {
@@ -525,7 +525,7 @@ const Staking = () => {
if (initialUnclaimed.current === null) {
initialUnclaimed.current = totalUnclaimed;
}
- }, [selectedAccount, rewardsUserClaimedQuery.fetching, rewardsUserClaimedQuery.data, claimAllSuccess]);
+ }, [selectedAccount, rewardsUserClaimedQuery.fetching, rewardsUserClaimedQuery.data, claimAllSuccess, refreshQuery]);
useEffect(() => {
if (rewardsCoreClaimedQuery.fetching || !rewardsCoreClaimedQuery.data?.cores?.length || !selectedAccount) return;
diff --git a/src/utils/formatBalanceSafely.ts b/src/utils/formatBalanceSafely.ts
new file mode 100644
index 0000000..bb960b7
--- /dev/null
+++ b/src/utils/formatBalanceSafely.ts
@@ -0,0 +1,37 @@
+import { formatBalance } from "@polkadot/util";
+import BigNumber from "bignumber.js";
+
+export const formatBalanceSafely = (value: string | BigNumber) => {
+ try {
+ let valueAsBigNumber;
+ if (BigNumber.isBigNumber(value)) {
+ valueAsBigNumber = value;
+ } else {
+ // Convert string to BigNumber
+ valueAsBigNumber = new BigNumber(value);
+ }
+
+ // Scale the BigNumber value by 10^12 to avoid scientific notation for large/small numbers
+ const scaledValue = valueAsBigNumber.multipliedBy(new BigNumber(10).pow(12));
+ let valueAsString = scaledValue.toString(10);
+ // Check if the value is in scientific notation, even after scaling
+ if (/^(\d+(\.\d+)?)(e[+-]\d+)$/.test(valueAsString)) {
+ const numParts = valueAsString.split('e');
+ valueAsString = new BigNumber(numParts[0]).multipliedBy(new BigNumber(10).pow(numParts[1])).toString(10);
+ }
+ // Adjust the string back by dividing the scale, ensuring integer division
+ valueAsString = new BigNumber(valueAsString).dividedBy(new BigNumber(10).pow(12)).toString(10);
+
+ // Validate that the value is a string containing only digits and optionally a single dot for decimal values
+ if (!/^\d*\.?\d*$/.test(valueAsString)) {
+ console.error("Invalid value for formatting, contains non-numeric characters:", value);
+ return "Invalid Input"; // Return a placeholder or handle the error as appropriate
+ }
+
+ // If the value is valid, call formatBalance
+ return formatBalance(valueAsString, { decimals: 12, withUnit: "TNKR", forceUnit: "-" });
+ } catch (error) {
+ console.error("Error formatting balance:", error);
+ return "Error"; // Error or fallback value
+ }
+};
\ No newline at end of file
diff --git a/src/utils/restakeClaim.ts b/src/utils/restakeClaim.ts
index 5518fbe..9a0e685 100644
--- a/src/utils/restakeClaim.ts
+++ b/src/utils/restakeClaim.ts
@@ -61,7 +61,7 @@ export const restakeClaim = async ({
uniqueCores.forEach(core => {
if (!core?.earliestEra) return;
const restakeUnclaimedAmount = handleRestakingLogic(undefined, uniqueCores.length);
- if (restakeUnclaimedAmount && !restakeUnclaimedAmount.isZero()) {
+ if (restakeUnclaimedAmount && restakeUnclaimedAmount.isGreaterThan(0)) {
const restakeAmountInteger = restakeUnclaimedAmount.integerValue().toString();
batch.push(api.tx.ocifStaking.stake(core.coreId, restakeAmountInteger));
}
@@ -110,7 +110,7 @@ export const restakeClaim = async ({
// Send the transaction batch
// Casting batch to the correct type to satisfy the linting error
const castedBatch = rebuildBatch as Vec;
-
+
// FIX: Changed the batchAll to batch to solve the claim issues.
// Issue is caused by batchAll failing when trying to claim an era where stake == 0, prob due to stake being moved to another core.
// TODO: Proper solution is to still use batchAll but not attempt to claim eras where stake == 0
diff --git a/src/utils/vestingServices.ts b/src/utils/vestingServices.ts
index 8ee6acf..0c46e51 100644
--- a/src/utils/vestingServices.ts
+++ b/src/utils/vestingServices.ts
@@ -1,8 +1,8 @@
-import { formatBalance } from "@polkadot/util";
import BigNumber from "bignumber.js";
import { VestingScheduleLineItem, DataResultType, LockType, SystemAccount, VestingSchedule } from "../routes/claim";
import { ApiPromise } from "@polkadot/api";
import { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";
+import { formatBalanceSafely } from "./formatBalanceSafely";
export const fetchSystemData = async (selectedAccount: InjectedAccountWithMeta, api: ApiPromise): Promise => {
if (!selectedAccount || !api) {
@@ -129,11 +129,17 @@ export const calculateVestingData = (results: DataResultType, vestingSchedules:
// Calculate the end of the vesting period
const endOfVestingPeriod = new Date(currentDate.getTime() + remainingVestingPeriodInSeconds * 1000);
+ // Use formatBalanceSafely instead of formatBalance in your calculations
+ const vestedClaimable = formatBalanceSafely(unlockedClaimableTokens);
+ const vestedRemaining = formatBalanceSafely(totalFutureLockedTokens);
+ const frozenFormatted = formatBalanceSafely(frozen);
+ const availableFormatted = formatBalanceSafely(available);
+
return {
- vestedClaimable: formatBalance(unlockedClaimableTokens.toString(), { decimals: 12, withUnit: "TNKR", forceUnit: "-" }),
- vestedRemaining: formatBalance(totalFutureLockedTokens.toString(), { decimals: 12, withUnit: "TNKR", forceUnit: "-" }),
- frozen: formatBalance(frozen.toString(), { decimals: 12, withUnit: "TNKR", forceUnit: "-" }),
- available: formatBalance(available.toString(), { decimals: 12, withUnit: "TNKR", forceUnit: "-" }),
+ vestedClaimable,
+ vestedRemaining,
+ frozen: frozenFormatted,
+ available: availableFormatted,
remainingVestingPeriod: new Intl.NumberFormat("en-US", {}).format(remainingVestingPeriod),
endOfVestingPeriod
};