diff --git a/src/app/pages/RewardPage/components/ClaimForms/FeesEarnedClaimRow/index.tsx b/src/app/pages/RewardPage/components/ClaimForms/FeesEarnedClaimRow/index.tsx index 33e89a437..35106830b 100644 --- a/src/app/pages/RewardPage/components/ClaimForms/FeesEarnedClaimRow/index.tsx +++ b/src/app/pages/RewardPage/components/ClaimForms/FeesEarnedClaimRow/index.tsx @@ -1,4 +1,10 @@ -import React, { useCallback, useMemo } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import { useTranslation } from 'react-i18next'; import { IClaimFormProps } from '../BaseClaimForm/types'; import { useAccount } from 'app/hooks/useAccount'; @@ -8,7 +14,7 @@ import { translations } from 'locales/i18n'; import { AssetRenderer } from 'app/components/AssetRenderer'; import { Asset } from 'types'; import { useCacheCallWithValue } from 'app/hooks/useCacheCallWithValue'; -import { gasLimit } from 'utils/classifiers'; +import { currentChainId, gasLimit } from 'utils/classifiers'; import { useMaintenance } from 'app/hooks/useMaintenance'; import { weiToNumberFormat } from 'utils/display-text/format'; import { ActionButton } from 'app/components/Form/ActionButton'; @@ -18,6 +24,11 @@ import { bignumber } from 'mathjs'; import classNames from 'classnames'; import { LoadableValue } from 'app/components/LoadableValue'; import { TransactionDialog } from 'app/components/TransactionDialog'; +import { simulateTx } from 'utils/simulator/simulateTx'; +import { TxTuple } from 'utils/simulator/types'; +import { getContract } from 'utils/blockchain/contract-helpers'; +import { Sovryn } from 'utils/sovryn'; +import { toastError } from 'utils/toaster'; interface IFeesEarnedClaimRowProps extends IClaimFormProps { rbtcValue: number; @@ -40,10 +51,12 @@ export const FeesEarnedClaimRow: React.FC = ({ const { checkMaintenance, States } = useMaintenance(); const claimFeesEarnedLocked = checkMaintenance(States.CLAIM_FEES_EARNED); + const controllerRef = useRef(); + const { value: maxCheckpoints } = useCacheCallWithValue( 'feeSharingProxy', 'numTokenCheckpoints', - 100, + -1, contractAddress, ); const { send, ...tx } = useSendContractTx('feeSharingProxy', 'withdraw'); @@ -52,12 +65,15 @@ export const FeesEarnedClaimRow: React.FC = ({ 'withdrawRBTC', ); + const [isSimulating, setIsSimulating] = useState(false); + const isClaimDisabled = useMemo( () => + isSimulating || claimFeesEarnedLocked || !bignumber(amountToClaim).greaterThan(0) || assetClaimLocked, - [claimFeesEarnedLocked, amountToClaim, assetClaimLocked], + [isSimulating, claimFeesEarnedLocked, amountToClaim, assetClaimLocked], ); const onSubmit = useCallback(() => { @@ -76,6 +92,64 @@ export const FeesEarnedClaimRow: React.FC = ({ } }, [address, asset, contractAddress, maxCheckpoints, send, withdrawRBTC]); + const handleCheckBeforeSubmit = useCallback(() => { + if (controllerRef.current) { + controllerRef.current.abort(); + } + setIsSimulating(true); + + controllerRef.current = new AbortController(); + + const args = + asset === Asset.RBTC + ? [0, address] + : [contractAddress, maxCheckpoints, address]; + + const method = asset === Asset.RBTC ? 'withdrawRBTC' : 'withdraw'; + + const tx: TxTuple = [ + { + to: getContract('feeSharingProxy').address, + from: address, + value: '0', + input: Sovryn.contracts['feeSharingProxy'].methods[method]( + ...args, + ).encodeABI(), + gas_price: '0', + gas: 6_800_000, + }, + ]; + + simulateTx(currentChainId, tx, controllerRef.current.signal) + .then(([{ transaction }]) => { + console.log('simulation response', asset, transaction); + if (transaction.status) { + onSubmit(); + } else { + toastError( + t(translations.rewardPage.claimForm.contractFailure, { + currency: asset, + }), + ); + } + }) + .catch(() => { + // error from the simulator itself + toastError(t(translations.rewardPage.claimForm.simulatorFailure)); + }) + .finally(() => { + setIsSimulating(false); + }); + }, [address, asset, contractAddress, maxCheckpoints, onSubmit, t]); + + useEffect(() => { + return () => { + if (controllerRef.current) { + controllerRef.current.abort(); + } + }; + }, []); + return ( = ({