From a8ad1509028ef92f669ae004d6b2797c400b7784 Mon Sep 17 00:00:00 2001 From: Pietro Maximoff <74987028+pietro-maximoff@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:57:54 +0200 Subject: [PATCH] SOV-3077: update claim button logic (#2575) * SOV-3077: update claim button logic * chore: update text --- .../hooks/useGetFilteredDates.ts | 31 +++++++++++++++++ .../hooks/useGetVestingAddresses.ts | 28 ++++++++++++++++ .../ClaimForms/BaseClaimForm/index.tsx | 33 ++++++++++++++++++- src/locales/en/translation.json | 3 +- 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetFilteredDates.ts create mode 100644 src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetVestingAddresses.ts diff --git a/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetFilteredDates.ts b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetFilteredDates.ts new file mode 100644 index 000000000..c40f85d41 --- /dev/null +++ b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetFilteredDates.ts @@ -0,0 +1,31 @@ +import { useEffect, useState } from 'react'; +import { contractReader } from 'utils/sovryn/contract-reader'; + +const useGetFilteredDates = (vestingAddresses: string[]) => { + const [filteredDates, setFilteredDates] = useState([]); + + useEffect(() => { + const fetchDatesForAddresses = async () => { + const datesArray: string[] = []; + + for (const address of vestingAddresses) { + try { + const res = await contractReader.call('staking', 'getStakes', [ + address, + ]); + const dates = res['dates']; + datesArray.push(...dates); + } catch (error) { + console.error('Error fetching dates for address', address, error); + } + } + setFilteredDates(datesArray); + }; + + fetchDatesForAddresses(); + }, [vestingAddresses]); + + return filteredDates; +}; + +export default useGetFilteredDates; diff --git a/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetVestingAddresses.ts b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetVestingAddresses.ts new file mode 100644 index 000000000..e3d60bd82 --- /dev/null +++ b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/hooks/useGetVestingAddresses.ts @@ -0,0 +1,28 @@ +import { useListOfUserVestings } from 'app/components/UserAssets/Vesting/useListOfUserVestings'; +import { useEffect, useState } from 'react'; + +const useGetVestingAddresses = () => { + const { loading, items } = useListOfUserVestings(); + + const [vestingAddresses, setVestingAddresses] = useState([]); + + useEffect(() => { + const getVestingContractAddresses = async () => { + try { + const vestingContracts: string[] = await Promise.all( + items.map(async item => item.vestingContract), + ); + setVestingAddresses(vestingContracts); + } catch (error) { + console.error('Error fetching vesting contract addresses:', error); + } + }; + if (!loading) { + getVestingContractAddresses(); + } + }, [items, loading]); + + return vestingAddresses; +}; + +export default useGetVestingAddresses; diff --git a/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/index.tsx b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/index.tsx index 526119ff3..c727cb898 100644 --- a/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/index.tsx +++ b/src/app/pages/RewardPage/components/ClaimForms/BaseClaimForm/index.tsx @@ -18,6 +18,8 @@ import { Asset } from 'types'; import { weiTo18 } from 'utils/blockchain/math-helpers'; import { discordInvite } from 'utils/classifiers'; import { weiToNumberFormat } from 'utils/display-text/format'; +import useGetVestingAddresses from './hooks/useGetVestingAddresses'; +import useGetFilteredDates from './hooks/useGetFilteredDates'; interface IBaseClaimFormProps { className?: string; @@ -31,6 +33,8 @@ interface IBaseClaimFormProps { dataActionId?: string; } +const MAX_LIQUID_STAKES = 44; + export const BaseClaimForm: React.FC = ({ className, amountToClaim, @@ -45,16 +49,36 @@ export const BaseClaimForm: React.FC = ({ const { t } = useTranslation(); const { checkMaintenance, States } = useMaintenance(); const rewardsLocked = checkMaintenance(States.CLAIM_REWARDS); + const currentDate = useMemo(() => Math.ceil(new Date().getTime() / 1e3), []); + + const vestingAddresses = useGetVestingAddresses(); + + const filteredDates = useGetFilteredDates(vestingAddresses); + const datesLessThanCurrentTime = useMemo( + () => + filteredDates.filter( + dateInSeconds => parseInt(dateInSeconds) < currentDate, + ), + [filteredDates, currentDate], + ); + + const isAboveThreshold = useMemo( + () => + datesLessThanCurrentTime.length > MAX_LIQUID_STAKES && + vestingAddresses.length > 0, + [datesLessThanCurrentTime, vestingAddresses], + ); const isDisabled = useMemo( () => + isAboveThreshold || parseFloat(amountToClaim) === 0 || !amountToClaim || rewardsLocked || claimLocked || tx.status === TxStatus.PENDING || tx.status === TxStatus.PENDING_FOR_USER, - [amountToClaim, rewardsLocked, claimLocked, tx.status], + [amountToClaim, rewardsLocked, claimLocked, tx.status, isAboveThreshold], ); return ( @@ -127,6 +151,13 @@ export const BaseClaimForm: React.FC = ({ )} + {isAboveThreshold && ( +

+ {t(translations.rewardPage.claimForm.liquidityMiningError, { + count: MAX_LIQUID_STAKES, + })} +

+ )}
{footer}
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 13e14cc46..96495d6f4 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -1647,7 +1647,8 @@ "learn": "Learn more", "claimDisabled": "There is not enough SOV in the StakingRewardsProxy contract to facilitate a claim of rewards at this time. Therefore, to avoid a loss of gas fee by initiating a transaction that will inevitably fail, the CLAIM button has been disabled. Be assured that the team is aware and funds should be replenished shortly.", "contractFailure": "Due to a known issue, claiming {{currency}} transaction will fail. Work on a fix is in progress.", - "simulatorFailure": "Unknown error, please try again later." + "simulatorFailure": "Unknown error, please try again later.", + "liquidityMiningError": "Your liquidity mining vesting contract holds more than {{count}} checkpoints worth of rewards. Please withdraw liquid rewards from your vesting contract to enable the 'Claim' button and claim additional rewards." }, "liquidClaimForm": { "note": "Claiming your rewards automatically adds them to your SOV portfolio balance.",