/ src / components / transactions / Stake / StakeModalContent.tsx
StakeModalContent.tsx
  1  import { ChainId, Stake } from '@aave/contract-helpers';
  2  import { normalize, valueToBigNumber } from '@aave/math-utils';
  3  import { Trans } from '@lingui/macro';
  4  import { Typography } from '@mui/material';
  5  import React, { useRef, useState } from 'react';
  6  import { useGeneralStakeUiData } from 'src/hooks/stake/useGeneralStakeUiData';
  7  import { useUserStakeUiData } from 'src/hooks/stake/useUserStakeUiData';
  8  import { useModalContext } from 'src/hooks/useModal';
  9  import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
 10  import { useRootStore } from 'src/store/root';
 11  import { stakeAssetNameFormatted, stakeConfig } from 'src/ui-config/stakeConfig';
 12  import { getNetworkConfig } from 'src/utils/marketsAndNetworksConfig';
 13  import { STAKE } from 'src/utils/mixPanelEvents';
 14  
 15  import { CooldownWarning } from '../../Warnings/CooldownWarning';
 16  import { AssetInput } from '../AssetInput';
 17  import { TxErrorView } from '../FlowCommons/Error';
 18  import { GasEstimationError } from '../FlowCommons/GasEstimationError';
 19  import { TxSuccessView } from '../FlowCommons/Success';
 20  import { DetailsNumberLine, TxModalDetails } from '../FlowCommons/TxModalDetails';
 21  import { TxModalTitle } from '../FlowCommons/TxModalTitle';
 22  import { ChangeNetworkWarning } from '../Warnings/ChangeNetworkWarning';
 23  import { StakeActions } from './StakeActions';
 24  
 25  export type StakeProps = {
 26    stakeAssetName: Stake;
 27    icon: string;
 28  };
 29  
 30  export enum ErrorType {
 31    NOT_ENOUGH_BALANCE,
 32  }
 33  
 34  export const StakeModalContent = ({ stakeAssetName, icon }: StakeProps) => {
 35    const { chainId: connectedChainId, readOnlyModeAddress } = useWeb3Context();
 36    const { gasLimit, mainTxState: txState, txError } = useModalContext();
 37    const currentMarketData = useRootStore((store) => store.currentMarketData);
 38    const currentNetworkConfig = useRootStore((store) => store.currentNetworkConfig);
 39    const currentChainId = useRootStore((store) => store.currentChainId);
 40  
 41    const { data: stakeUserResult } = useUserStakeUiData(currentMarketData, stakeAssetName);
 42    const { data: stakeGeneralResult } = useGeneralStakeUiData(currentMarketData, stakeAssetName);
 43  
 44    const stakeData = stakeGeneralResult?.[0];
 45    const stakeUserData = stakeUserResult?.[0];
 46  
 47    // states
 48    const [_amount, setAmount] = useState('');
 49    const amountRef = useRef<string>();
 50  
 51    const walletBalance = normalize(stakeUserData?.underlyingTokenUserBalance || '0', 18);
 52  
 53    const isMaxSelected = _amount === '-1';
 54    const amount = isMaxSelected ? walletBalance : _amount;
 55  
 56    const handleChange = (value: string) => {
 57      const maxSelected = value === '-1';
 58      amountRef.current = maxSelected ? walletBalance : value;
 59      setAmount(value);
 60    };
 61  
 62    // staking token usd value
 63    const amountInUsd = Number(amount) * Number(stakeData?.stakeTokenPriceUSDFormatted);
 64  
 65    // error handler
 66    let blockingError: ErrorType | undefined = undefined;
 67    if (valueToBigNumber(amount).gt(walletBalance)) {
 68      blockingError = ErrorType.NOT_ENOUGH_BALANCE;
 69    }
 70  
 71    const handleBlocked = () => {
 72      switch (blockingError) {
 73        case ErrorType.NOT_ENOUGH_BALANCE:
 74          return <Trans>Not enough balance on your wallet</Trans>;
 75        default:
 76          return null;
 77      }
 78    };
 79  
 80    const nameFormatted = stakeAssetNameFormatted(stakeAssetName);
 81  
 82    // is Network mismatched
 83    const stakingChain =
 84      currentNetworkConfig.isFork && currentNetworkConfig.underlyingChainId === stakeConfig.chainId
 85        ? currentChainId
 86        : stakeConfig.chainId;
 87    const isWrongNetwork = connectedChainId !== stakingChain;
 88  
 89    const networkConfig = getNetworkConfig(stakingChain);
 90  
 91    if (txError && txError.blocking) {
 92      return <TxErrorView txError={txError} />;
 93    }
 94    if (txState.success)
 95      return (
 96        <TxSuccessView
 97          action={<Trans>Staked</Trans>}
 98          amount={amountRef.current}
 99          symbol={nameFormatted}
100        />
101      );
102  
103    return (
104      <>
105        <TxModalTitle title="Stake" symbol={nameFormatted} />
106        {isWrongNetwork && !readOnlyModeAddress && (
107          <ChangeNetworkWarning
108            networkName={networkConfig.name}
109            chainId={stakingChain}
110            funnel={'Stake Modal'}
111          />
112        )}
113  
114        <CooldownWarning />
115  
116        <AssetInput
117          value={amount}
118          onChange={handleChange}
119          usdValue={amountInUsd.toString()}
120          symbol={nameFormatted}
121          assets={[
122            {
123              balance: walletBalance.toString(),
124              symbol: icon,
125            },
126          ]}
127          isMaxSelected={isMaxSelected}
128          maxValue={walletBalance.toString()}
129          balanceText={<Trans>Wallet balance</Trans>}
130        />
131        {blockingError !== undefined && (
132          <Typography variant="helperText" color="red">
133            {handleBlocked()}
134          </Typography>
135        )}
136        <TxModalDetails gasLimit={gasLimit} chainId={ChainId.mainnet}>
137          <DetailsNumberLine
138            description={<Trans>Staking APR</Trans>}
139            value={Number(stakeData?.stakeApy || '0') / 10000}
140            percent
141          />
142        </TxModalDetails>
143  
144        {txError && <GasEstimationError txError={txError} />}
145  
146        <StakeActions
147          sx={{ mt: '48px' }}
148          amountToStake={amount}
149          isWrongNetwork={isWrongNetwork}
150          symbol={nameFormatted}
151          blocked={blockingError !== undefined}
152          selectedToken={stakeAssetName}
153          event={STAKE.STAKE_TOKEN}
154        />
155      </>
156    );
157  };