/ src / components / transactions / StakeRewardClaim / StakeRewardClaimModalContent.tsx
StakeRewardClaimModalContent.tsx
  1  import { ChainId, Stake } from '@aave/contract-helpers';
  2  import { normalize } from '@aave/math-utils';
  3  import { Trans } from '@lingui/macro';
  4  import { Typography } from '@mui/material';
  5  import { parseUnits } from 'ethers/lib/utils';
  6  import React, { useRef, useState } from 'react';
  7  import { useGeneralStakeUiData } from 'src/hooks/stake/useGeneralStakeUiData';
  8  import { useUserStakeUiData } from 'src/hooks/stake/useUserStakeUiData';
  9  import { useModalContext } from 'src/hooks/useModal';
 10  import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
 11  import { useRootStore } from 'src/store/root';
 12  import { stakeConfig } from 'src/ui-config/stakeConfig';
 13  import { getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
 14  
 15  import { AssetInput } from '../AssetInput';
 16  import { TxErrorView } from '../FlowCommons/Error';
 17  import { GasEstimationError } from '../FlowCommons/GasEstimationError';
 18  import { TxSuccessView } from '../FlowCommons/Success';
 19  import { TxModalTitle } from '../FlowCommons/TxModalTitle';
 20  import { GasStation } from '../GasStation/GasStation';
 21  import { ChangeNetworkWarning } from '../Warnings/ChangeNetworkWarning';
 22  import { StakeRewardClaimActions } from './StakeRewardClaimActions';
 23  
 24  export type StakeRewardClaimProps = {
 25    stakeAssetName: Stake;
 26    icon: string;
 27  };
 28  
 29  export enum ErrorType {
 30    NOT_ENOUGH_BALANCE,
 31  }
 32  
 33  export const StakeRewardClaimModalContent = ({ stakeAssetName, icon }: StakeRewardClaimProps) => {
 34    const { chainId: connectedChainId, readOnlyModeAddress } = useWeb3Context();
 35    const { gasLimit, mainTxState: txState, txError } = useModalContext();
 36    const currentNetworkConfig = useRootStore((store) => store.currentNetworkConfig);
 37    const currentChainId = useRootStore((store) => store.currentChainId);
 38    const currentMarketData = useRootStore((store) => store.currentMarketData);
 39    const [_amount, setAmount] = useState('');
 40    const amountRef = useRef<string>();
 41  
 42    const { data: stakeUserResult } = useUserStakeUiData(currentMarketData, stakeAssetName);
 43    const { data: stakeGeneralResult } = useGeneralStakeUiData(currentMarketData, stakeAssetName);
 44  
 45    const stakeData = stakeGeneralResult?.[0];
 46    const stakeUserData = stakeUserResult?.[0];
 47  
 48    // hardcoded as all rewards will be in aave token
 49    const rewardsSymbol = 'AAVE';
 50  
 51    const maxAmountToClaim = normalize(stakeUserData?.userIncentivesToClaim || '0', 18);
 52    const isMaxSelected = _amount === '-1';
 53    const amount = isMaxSelected ? maxAmountToClaim : _amount;
 54    const handleChange = (value: string) => {
 55      const maxSelected = value === '-1';
 56      amountRef.current = maxSelected ? maxAmountToClaim : value;
 57      setAmount(value);
 58    };
 59  
 60    const amountInUsd = Number(amount) * Number(stakeData?.rewardTokenPriceUSDFormatted);
 61  
 62    // error handler
 63    let blockingError: ErrorType | undefined = undefined;
 64    if (maxAmountToClaim === '0') {
 65      blockingError = ErrorType.NOT_ENOUGH_BALANCE;
 66    }
 67  
 68    const handleBlocked = () => {
 69      switch (blockingError) {
 70        case ErrorType.NOT_ENOUGH_BALANCE:
 71          return <Trans>No rewards to claim</Trans>;
 72        default:
 73          return null;
 74      }
 75    };
 76  
 77    // is Network mismatched
 78    const stakingChain =
 79      currentNetworkConfig.isFork && currentNetworkConfig.underlyingChainId === stakeConfig.chainId
 80        ? currentChainId
 81        : stakeConfig.chainId;
 82    const isWrongNetwork = connectedChainId !== stakingChain;
 83  
 84    const networkConfig = getNetworkConfig(stakingChain);
 85  
 86    if (txError && txError.blocking) {
 87      return <TxErrorView txError={txError} />;
 88    }
 89    if (txState.success)
 90      return (
 91        <TxSuccessView
 92          action={<Trans>Claimed</Trans>}
 93          amount={amountRef.current}
 94          symbol={rewardsSymbol}
 95        />
 96      );
 97  
 98    return (
 99      <>
100        <TxModalTitle title="Claim" symbol={rewardsSymbol} />
101        {isWrongNetwork && !readOnlyModeAddress && (
102          <ChangeNetworkWarning networkName={networkConfig.name} chainId={stakingChain} />
103        )}
104        {blockingError !== undefined && (
105          <Typography variant="helperText" color="red">
106            {handleBlocked()}
107          </Typography>
108        )}
109        <AssetInput
110          value={amount}
111          onChange={handleChange}
112          usdValue={amountInUsd.toString()}
113          symbol={icon}
114          assets={[
115            {
116              balance: maxAmountToClaim.toString(),
117              symbol: icon,
118            },
119          ]}
120          isMaxSelected={isMaxSelected}
121          maxValue={maxAmountToClaim.toString()}
122          balanceText={<Trans>Amount claimable</Trans>}
123        />
124        <GasStation gasLimit={parseUnits(gasLimit || '0', 'wei')} chainId={ChainId.mainnet} />
125  
126        {txError && <GasEstimationError txError={txError} />}
127  
128        <StakeRewardClaimActions
129          sx={{ mt: '48px' }}
130          amountToClaim={amount}
131          isWrongNetwork={isWrongNetwork}
132          symbol={rewardsSymbol}
133          blocked={blockingError !== undefined || Number(amount) === 0}
134          selectedToken={stakeAssetName}
135        />
136      </>
137    );
138  };