From 28e78e56dc553205ae2b33d75161cd209aa494f1 Mon Sep 17 00:00:00 2001 From: Ladislav Martincik Date: Wed, 11 Sep 2024 07:48:41 +0200 Subject: [PATCH] Add timer after stake 5s and allow claim always with redirect to HUB --- src/components/ProgressModal.tsx | 58 ++++++---- src/routes/Actions.tsx | 189 ++++++++++++++++++------------- src/routes/Claim.tsx | 118 +++++++++++-------- 3 files changed, 218 insertions(+), 147 deletions(-) diff --git a/src/components/ProgressModal.tsx b/src/components/ProgressModal.tsx index d1aa765..3f72985 100644 --- a/src/components/ProgressModal.tsx +++ b/src/components/ProgressModal.tsx @@ -1,11 +1,9 @@ -import { Fragment, h } from 'preact'; - -import { RouteLink } from '../layout/Router'; - -import { useContext } from 'preact/hooks'; -import { ConfigContext } from '../AppContext'; -import { clsxp } from '../libs/utils'; -import Loading from './Loading'; +import { Fragment, h } from "preact"; +import { RouteLink } from "../layout/Router"; +import { useContext, useEffect, useState } from "preact/hooks"; +import { ConfigContext } from "../AppContext"; +import { clsxp } from "../libs/utils"; +import Loading from "./Loading"; const ProgressModal = ({ working, @@ -15,35 +13,47 @@ const ProgressModal = ({ doneStepName: string; }) => { const { classPrefix } = useContext(ConfigContext); + const [countdown, setCountdown] = useState(5); + + useEffect(() => { + if (working === doneStepName && countdown > 0) { + const timer = setTimeout(() => setCountdown(countdown - 1), 1000); + return () => clearTimeout(timer); + } + return () => {}; + }, [working, doneStepName, countdown]); + + const isButtonDisabled = working !== doneStepName || countdown > 0; + return ( -
+
Sign a transaction
-
- { working === doneStepName ? - 'Transaction sent successfully.' : - 'We need you to sign a transaction to lock your funds.' } +
+ {working === doneStepName + ? "Transaction sent successfully." + : "We need you to sign a transaction to lock your funds."}
diff --git a/src/routes/Actions.tsx b/src/routes/Actions.tsx index ac175de..dc371b7 100644 --- a/src/routes/Actions.tsx +++ b/src/routes/Actions.tsx @@ -1,17 +1,34 @@ -import { h } from 'preact'; -import { useCallback, useContext, useEffect, useMemo, useState, } from 'preact/hooks'; -import { PublicKey } from '@solana/web3.js'; -import BN from 'bn.js'; +import { h } from "preact"; +import { + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from "preact/hooks"; +import { PublicKey } from "@solana/web3.js"; +import BN from "bn.js"; -import { calculateRewardForStaker, getBondAccounts, getStakeAccounts, getUserACSBalance, } from '../libs/program'; -import { ConfigContext } from '../AppContext'; -import { BondAccount, BondV2Account, getBondV2Accounts, StakeAccount, StakePool } from '@accessprotocol/js'; -import { clsxp, formatPenyACSCurrency } from '../libs/utils'; -import { RouteLink } from '../layout/Router'; -import { Header } from '../components/Header'; -import { useWallet } from '../components/wallet-adapter/useWallet'; -import { useConnection } from '../components/wallet-adapter/useConnection'; -import env from '../libs/env'; +import { + calculateRewardForStaker, + getBondAccounts, + getStakeAccounts, + getUserACSBalance, +} from "../libs/program"; +import { ConfigContext } from "../AppContext"; +import { + BondAccount, + BondV2Account, + getBondV2Accounts, + StakeAccount, + StakePool, +} from "@accessprotocol/js"; +import { clsxp, formatPenyACSCurrency } from "../libs/utils"; +import { RouteLink } from "../layout/Router"; +import { Header } from "../components/Header"; +import { useWallet } from "../components/wallet-adapter/useWallet"; +import { useConnection } from "../components/wallet-adapter/useConnection"; +import env from "../libs/env"; export const Actions = () => { const { poolId, classPrefix } = useContext(ConfigContext); @@ -83,8 +100,13 @@ export const Actions = () => { env.PROGRAM_ID ); setBondAccounts( - bAccounts.map((bAccount: any) => BondAccount.deserialize(bAccount.account.data)) - .filter((bAccount: BondAccount) => bAccount.stakePool.toBase58() === poolId) + bAccounts + .map((bAccount: any) => + BondAccount.deserialize(bAccount.account.data) + ) + .filter( + (bAccount: BondAccount) => bAccount.stakePool.toBase58() === poolId + ) ); })(); }, [publicKey, connection, poolId]); @@ -101,8 +123,13 @@ export const Actions = () => { ); setBondV2Accounts( - bV2Accounts.map((bAccount: any) => BondV2Account.deserialize(bAccount.account.data)) - .filter((bAccount: BondV2Account) => bAccount.pool.toBase58() === poolId) + bV2Accounts + .map((bAccount: any) => + BondV2Account.deserialize(bAccount.account.data) + ) + .filter( + (bAccount: BondV2Account) => bAccount.pool.toBase58() === poolId + ) ); })(); }, [publicKey, connection, poolId]); @@ -123,12 +150,16 @@ export const Actions = () => { return null; } - return bondAccounts.reduce((acc, ba) => - acc + calculateRewardForStaker( - stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), - stakePool, - ba.totalStaked as BN - ), 0); + return bondAccounts.reduce( + (acc, ba) => + acc + + calculateRewardForStaker( + stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), + stakePool, + ba.totalStaked as BN + ), + 0 + ); }, [bondAccounts, stakePool]); const claimableBondV2Amount = useMemo(() => { @@ -136,23 +167,31 @@ export const Actions = () => { return null; } - return bondV2Accounts.reduce((acc, ba) => - acc + calculateRewardForStaker( - stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), - stakePool, - ba.amount as BN - ), 0); + return bondV2Accounts.reduce( + (acc, ba) => + acc + + calculateRewardForStaker( + stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), + stakePool, + ba.amount as BN + ), + 0 + ); }, [bondV2Accounts, stakePool]); const claimableAmount = useMemo(() => { - return (claimableBondAmount ?? 0) + (claimableStakeAmount ?? 0) + (claimableBondV2Amount ?? 0); + return ( + (claimableBondAmount ?? 0) + + (claimableStakeAmount ?? 0) + + (claimableBondV2Amount ?? 0) + ); }, [claimableBondAmount, claimableStakeAmount, claimableBondV2Amount]); const disconnectHandler = useCallback(async () => { try { await disconnect(); } catch (error) { - console.error('Failed to disconnect:', error); + console.error("Failed to disconnect:", error); } }, [disconnect]); @@ -178,10 +217,10 @@ export const Actions = () => { }, [stakePool, bondV2Accounts]); return ( -
+
{connected && disconnecting && (
-
+
Disconnecting...
@@ -189,7 +228,7 @@ export const Actions = () => { {connected && !disconnecting && (
Disconnect @@ -197,17 +236,17 @@ export const Actions = () => {
)} -
+
@@ -216,25 +255,31 @@ export const Actions = () => {
{formatPenyACSCurrency( (stakedAccount?.stakeAmount.toNumber() ?? 0) + - (bondAccounts?.reduce((acc, ba) => acc + ba.totalStaked.toNumber(), 0) ?? 0) + - (bondV2Accounts?.reduce((acc, ba) => acc + ba.amount.toNumber(), 0) ?? 0) - )}{' '} + (bondAccounts?.reduce( + (acc, ba) => acc + ba.totalStaked.toNumber(), + 0 + ) ?? 0) + + (bondV2Accounts?.reduce( + (acc, ba) => acc + ba.amount.toNumber(), + 0 + ) ?? 0) + )}{" "} ACS locked
{formatPenyACSCurrency(balance?.toNumber() ?? 0)} ACS available @@ -242,26 +287,28 @@ export const Actions = () => {
{formatPenyACSCurrency(claimableAmount ?? 0)} ACS rewards
-
+
Lock - {(stakedAccount && stakedAccount.stakeAmount.toNumber() > 0) || hasUnlockableBonds || hasUnlockableBondsV2 ? ( + {(stakedAccount && stakedAccount.stakeAmount.toNumber() > 0) || + hasUnlockableBonds || + hasUnlockableBondsV2 ? ( Unlock ACS @@ -269,31 +316,19 @@ export const Actions = () => { Unlock ACS )} - {claimableAmount && claimableAmount > 0 ? ( - - Claim - - ) : ( - - Claim rewards - - )} + + Claim +
); diff --git a/src/routes/Claim.tsx b/src/routes/Claim.tsx index 2050c71..caca758 100644 --- a/src/routes/Claim.tsx +++ b/src/routes/Claim.tsx @@ -1,17 +1,27 @@ -import { h } from 'preact'; - -import { Header } from '../components/Header'; -import { RouteLink } from '../layout/Router'; -import { useContext, useEffect, useMemo, useState } from 'preact/hooks'; -import { ConfigContext } from '../AppContext'; -import env from '../libs/env'; -import { clsxp, formatPenyACSCurrency } from '../libs/utils'; -import { BondAccount, BondV2Account, getBondV2Accounts, StakeAccount, StakePool } from '@accessprotocol/js'; -import { calculateRewardForStaker, getBondAccounts, getStakeAccounts } from '../libs/program'; -import { PublicKey } from '@solana/web3.js'; -import BN from 'bn.js'; -import { useWallet } from '../components/wallet-adapter/useWallet'; -import { useConnection } from '../components/wallet-adapter/useConnection'; +import { h } from "preact"; + +import { Header } from "../components/Header"; +import { RouteLink } from "../layout/Router"; +import { useContext, useEffect, useMemo, useState } from "preact/hooks"; +import { ConfigContext } from "../AppContext"; +import env from "../libs/env"; +import { clsxp, formatPenyACSCurrency } from "../libs/utils"; +import { + BondAccount, + BondV2Account, + getBondV2Accounts, + StakeAccount, + StakePool, +} from "@accessprotocol/js"; +import { + calculateRewardForStaker, + getBondAccounts, + getStakeAccounts, +} from "../libs/program"; +import { PublicKey } from "@solana/web3.js"; +import BN from "bn.js"; +import { useWallet } from "../components/wallet-adapter/useWallet"; +import { useConnection } from "../components/wallet-adapter/useConnection"; export const Claim = () => { const { poolId, classPrefix } = useContext(ConfigContext); @@ -72,10 +82,12 @@ export const Claim = () => { env.PROGRAM_ID ); if (bAccounts != null && bAccounts.length > 0) { - const bas = bAccounts.filter((st) => { - const ba = BondAccount.deserialize(st.account.data); - return ba.stakePool.toBase58() === poolId; - }).map((bAccount) => BondAccount.deserialize(bAccount.account.data)); + const bas = bAccounts + .filter((st) => { + const ba = BondAccount.deserialize(st.account.data); + return ba.stakePool.toBase58() === poolId; + }) + .map((bAccount) => BondAccount.deserialize(bAccount.account.data)); setBondAccounts(bas); } else { setBondAccounts([]); @@ -95,8 +107,13 @@ export const Claim = () => { ); setBondV2Accounts( - bV2Accounts.map((bAccount: any) => BondV2Account.deserialize(bAccount.account.data)) - .filter((bAccount: BondV2Account) => bAccount.pool.toBase58() === poolId) + bV2Accounts + .map((bAccount: any) => + BondV2Account.deserialize(bAccount.account.data) + ) + .filter( + (bAccount: BondV2Account) => bAccount.pool.toBase58() === poolId + ) ); })(); }, [publicKey, connection, poolId]); @@ -117,12 +134,16 @@ export const Claim = () => { return null; } - return bondAccounts.reduce((acc, ba) => - acc + calculateRewardForStaker( - stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), - stakePool, - ba.totalStaked as BN - ), 0); + return bondAccounts.reduce( + (acc, ba) => + acc + + calculateRewardForStaker( + stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), + stakePool, + ba.totalStaked as BN + ), + 0 + ); }, [bondAccounts, stakePool]); const claimableBondV2Amount = useMemo(() => { @@ -130,50 +151,55 @@ export const Claim = () => { return null; } - return bondV2Accounts.reduce((acc, ba) => - acc + calculateRewardForStaker( - stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), - stakePool, - ba.amount as BN - ), 0); + return bondV2Accounts.reduce( + (acc, ba) => + acc + + calculateRewardForStaker( + stakePool.currentDayIdx - ba.lastClaimedOffset.toNumber(), + stakePool, + ba.amount as BN + ), + 0 + ); }, [bondV2Accounts, stakePool]); const claimableAmount = useMemo(() => { - return (claimableBondAmount ?? 0) + (claimableStakeAmount ?? 0) + (claimableBondV2Amount ?? 0); + return ( + (claimableBondAmount ?? 0) + + (claimableStakeAmount ?? 0) + + (claimableBondV2Amount ?? 0) + ); }, [claimableBondAmount, claimableStakeAmount, claimableBondV2Amount]); return ( -
+
- + Cancel
-
Claim ACS Rewards
+
Claim ACS Rewards
-
+
{formatPenyACSCurrency(claimableAmount)} ACS
-
+
ACS reward claim is currently only possible in the Access app.
Claim rewards on Access -
+
This will redirect you to accessprotocol.co