utils#returnTokenFromKey TypeScript Examples

The following examples show how to use utils#returnTokenFromKey. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SyrupAPR.tsx    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
SyrupAPR: React.FC<{ syrup: SyrupInfo; dQUICKAPY: string }> = ({
  syrup,
  dQUICKAPY,
}) => {
  const { palette } = useTheme();
  const isDQUICKStakingToken = syrup.stakingToken.equals(
    returnTokenFromKey('DQUICK'),
  );

  return (
    <>
      <Typography variant='body2' style={{ color: palette.success.main }}>
        {getTokenAPRSyrup(syrup).toLocaleString()}%
      </Typography>
      {isDQUICKStakingToken && (
        <Box display='flex'>
          <Box
            borderRadius='4px'
            border={`1px solid ${palette.grey.A400}`}
            padding='4px'
            marginTop='4px'
            display='flex'
            alignItems='center'
          >
            <CurrencyLogo currency={returnTokenFromKey('QUICK')} size='12px' />
            <Typography variant='caption' style={{ marginLeft: 4 }}>
              {dQUICKAPY}% <span style={{ color: palette.text.hint }}>APY</span>
            </Typography>
          </Box>
        </Box>
      )}
    </>
  );
}
Example #2
Source File: hooks.ts    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
export function useDQUICKtoQUICK() {
  const lair = useLairContract();
  const inputs = ['1000000000000000000'];
  const dQuickToQuickState = useSingleCallResult(
    lair,
    'dQUICKForQUICK',
    inputs,
  );
  if (dQuickToQuickState.loading || dQuickToQuickState.error) return 0;
  return Number(
    new TokenAmount(
      returnTokenFromKey('QUICK'),
      JSBI.BigInt(dQuickToQuickState?.result?.[0] ?? 0),
    ).toExact(),
  );
}
Example #3
Source File: useUSDCPrice.ts    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
export function useUSDCPricesToken(tokens: Token[]) {
  const dQUICKtoQUICK = useDQUICKtoQUICK();
  const [, quickUsdcPair] = usePair(
    returnTokenFromKey('QUICK'),
    returnTokenFromKey('USDC'),
  );
  const quickPrice = Number(
    quickUsdcPair?.priceOf(returnTokenFromKey('QUICK'))?.toSignificant(6) ?? 0,
  );
  const filteredTokens = tokens
    .filter((item, pos, self) => {
      return self.findIndex((token) => token.equals(item)) == pos;
    })
    .filter(
      (token) =>
        !token.equals(returnTokenFromKey('QUICK')) &&
        !token.equals(returnTokenFromKey('DQUICK')),
    );
  const currencies = filteredTokens.map((token) => unwrappedToken(token));
  const usdPrices = useUSDCPrices(currencies);
  const usdPricesWithToken = filteredTokens.map((token, index) => {
    return { token, price: Number(usdPrices[index]?.toSignificant(6) ?? 0) };
  });
  return tokens.map((token) => {
    if (token.equals(returnTokenFromKey('DQUICK'))) {
      return dQUICKtoQUICK * quickPrice;
    } else if (token.equals(returnTokenFromKey('QUICK'))) {
      return quickPrice;
    } else {
      const priceObj = usdPricesWithToken.find((item) =>
        item.token.equals(token),
      );
      return priceObj?.price ?? 0;
    }
  });
}
Example #4
Source File: index.ts    From interface-v2 with GNU General Public License v3.0 5 votes vote down vote up
GlobalData = {
  bases: {
    // used to construct intermediary pairs for trading
    BASES_TO_CHECK_TRADES_AGAINST: {
      ...WETH_ONLY,
      [ChainId.MATIC]: [
        ...WETH_ONLY[ChainId.MATIC],
        returnTokenFromKey('USDC'),
        returnTokenFromKey('USDT'),
        returnTokenFromKey('QUICK'),
        returnTokenFromKey('ETHER'),
        returnTokenFromKey('WBTC'),
        returnTokenFromKey('DAI'),
        returnTokenFromKey('MAUSDC'),
        returnTokenFromKey('MI'),
        returnTokenFromKey('CXETH'),
        returnTokenFromKey('GHST'),
      ],
    },
    // Some tokens can only be swapped via certain pairs, so we override the list of bases that are considered for these tokens.
    CUSTOM_BASES: { [ChainId.MATIC]: undefined, [ChainId.MUMBAI]: undefined },
    // used for display in the default list when adding liquidity
    SUGGESTED_BASES: {
      ...WETH_ONLY,
      [ChainId.MATIC]: [
        ...WETH_ONLY[ChainId.MATIC],
        returnTokenFromKey('DAI'),
        returnTokenFromKey('USDC'),
        returnTokenFromKey('USDT'),
        returnTokenFromKey('QUICK'),
        returnTokenFromKey('ETHER'),
        returnTokenFromKey('WBTC'),
        returnTokenFromKey('SAND'),
        returnTokenFromKey('MI'),
      ],
    },
    // used to construct the list of all pairs we consider by default in the frontend
    BASES_TO_TRACK_LIQUIDITY_FOR: {
      ...WETH_ONLY,
      [ChainId.MATIC]: [
        ...WETH_ONLY[ChainId.MATIC],
        returnTokenFromKey('DAI'),
        returnTokenFromKey('USDC'),
        returnTokenFromKey('USDT'),
        returnTokenFromKey('QUICK'),
        returnTokenFromKey('ETHER'),
        returnTokenFromKey('WBTC'),
      ],
    },
  },
  pairs: {
    PINNED_PAIRS: {
      [ChainId.MATIC]: [
        [returnTokenFromKey('USDC'), returnTokenFromKey('USDT')],
        [returnTokenFromKey('USDC'), returnTokenFromKey('DAI')],
        [returnTokenFromKey('ETHER'), returnTokenFromKey('USDC')],
        [returnTokenFromKey('WBTC'), returnTokenFromKey('ETHER')],
        [WETH[ChainId.MATIC], returnTokenFromKey('USDT')],
        [WETH[ChainId.MATIC], returnTokenFromKey('USDC')],
        [WETH[ChainId.MATIC], returnTokenFromKey('ETHER')],
        [returnTokenFromKey('ETHER'), returnTokenFromKey('QUICK')],
      ],
      [ChainId.MUMBAI]: undefined,
    },
  },
  analytics: {
    CHART_DURATIONS: [
      GlobalConst.analyticChart.ONE_MONTH_CHART,
      GlobalConst.analyticChart.THREE_MONTH_CHART,
      GlobalConst.analyticChart.SIX_MONTH_CHART,
      GlobalConst.analyticChart.ONE_YEAR_CHART,
      GlobalConst.analyticChart.ALL_CHART,
    ],
    CHART_DURATION_TEXTS: ['1M', '3M', '6M', '1Y', 'All'],
  },
}
Example #5
Source File: hooks.ts    From interface-v2 with GNU General Public License v3.0 5 votes vote down vote up
export function useLairInfo(): LairInfo {
  const { account } = useActiveWeb3React();

  let accountArg = useMemo(() => [account ?? undefined], [account]);

  const lair = useLairContract();
  const quick = useQUICKContract();

  const _dQuickTotalSupply = useSingleCallResult(lair, 'totalSupply', []);

  const quickBalance = useSingleCallResult(lair, 'QUICKBalance', accountArg);
  const dQuickBalance = useSingleCallResult(lair, 'balanceOf', accountArg);

  accountArg = [GlobalConst.addresses.LAIR_ADDRESS ?? undefined];

  const lairsQuickBalance = useSingleCallResult(quick, 'balanceOf', accountArg);

  useEffect(() => {
    getOneDayVolume();
  }, []);

  return useMemo(() => {
    return {
      lairAddress: GlobalConst.addresses.LAIR_ADDRESS,
      dQUICKBalance: new TokenAmount(
        returnTokenFromKey('DQUICK'),
        JSBI.BigInt(dQuickBalance?.result?.[0] ?? 0),
      ),
      QUICKBalance: new TokenAmount(
        returnTokenFromKey('QUICK'),
        JSBI.BigInt(quickBalance?.result?.[0] ?? 0),
      ),
      totalQuickBalance: new TokenAmount(
        returnTokenFromKey('QUICK'),
        JSBI.BigInt(lairsQuickBalance?.result?.[0] ?? 0),
      ),
      dQuickTotalSupply: new TokenAmount(
        returnTokenFromKey('DQUICK'),
        JSBI.BigInt(_dQuickTotalSupply?.result?.[0] ?? 0),
      ),
      oneDayVol: oneDayVol,
    };
  }, [quickBalance, dQuickBalance, _dQuickTotalSupply, lairsQuickBalance]);
}
Example #6
Source File: AddLiquidity.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
AddLiquidity: React.FC<{
  currency0?: Currency;
  currency1?: Currency;
  currencyBg?: string;
}> = ({ currency0, currency1, currencyBg }) => {
  const classes = useStyles({});
  const { palette } = useTheme();
  const { t } = useTranslation();
  const [addLiquidityErrorMessage, setAddLiquidityErrorMessage] = useState<
    string | null
  >(null);

  const { account, chainId, library } = useActiveWeb3React();

  const [showConfirm, setShowConfirm] = useState(false);
  const [attemptingTxn, setAttemptingTxn] = useState(false);
  const [txPending, setTxPending] = useState(false);
  const [allowedSlippage] = useUserSlippageTolerance();
  const deadline = useTransactionDeadline();
  const [txHash, setTxHash] = useState('');
  const addTransaction = useTransactionAdder();
  const finalizedTransaction = useTransactionFinalizer();

  const { independentField, typedValue, otherTypedValue } = useMintState();
  const expertMode = useIsExpertMode();
  const {
    dependentField,
    currencies,
    pair,
    pairState,
    currencyBalances,
    parsedAmounts,
    price,
    noLiquidity,
    liquidityMinted,
    poolTokenPercentage,
    error,
  } = useDerivedMintInfo();

  const liquidityTokenData = {
    amountA: formatTokenAmount(parsedAmounts[Field.CURRENCY_A]),
    symbolA: currencies[Field.CURRENCY_A]?.symbol,
    amountB: formatTokenAmount(parsedAmounts[Field.CURRENCY_B]),
    symbolB: currencies[Field.CURRENCY_B]?.symbol,
  };

  const pendingText = t('supplyingTokens', liquidityTokenData);

  const {
    onFieldAInput,
    onFieldBInput,
    onCurrencySelection,
  } = useMintActionHandlers(noLiquidity);

  const maxAmounts: { [field in Field]?: TokenAmount } = [
    Field.CURRENCY_A,
    Field.CURRENCY_B,
  ].reduce((accumulator, field) => {
    return {
      ...accumulator,
      [field]: maxAmountSpend(currencyBalances[field]),
    };
  }, {});

  const formattedAmounts = {
    [independentField]: typedValue,
    [dependentField]: noLiquidity
      ? otherTypedValue
      : parsedAmounts[dependentField]?.toExact() ?? '',
  };

  const { ethereum } = window as any;
  const toggleWalletModal = useWalletModalToggle();
  const [approvingA, setApprovingA] = useState(false);
  const [approvingB, setApprovingB] = useState(false);
  const [approvalA, approveACallback] = useApproveCallback(
    parsedAmounts[Field.CURRENCY_A],
    chainId ? GlobalConst.addresses.ROUTER_ADDRESS[chainId] : undefined,
  );
  const [approvalB, approveBCallback] = useApproveCallback(
    parsedAmounts[Field.CURRENCY_B],
    chainId ? GlobalConst.addresses.ROUTER_ADDRESS[chainId] : undefined,
  );

  const userPoolBalance = useTokenBalance(
    account ?? undefined,
    pair?.liquidityToken,
  );

  const atMaxAmounts: { [field in Field]?: TokenAmount } = [
    Field.CURRENCY_A,
    Field.CURRENCY_B,
  ].reduce((accumulator, field) => {
    return {
      ...accumulator,
      [field]: maxAmounts[field]?.equalTo(parsedAmounts[field] ?? '0'),
    };
  }, {});

  const handleCurrencyASelect = useCallback(
    (currencyA: Currency) => {
      onCurrencySelection(Field.CURRENCY_A, currencyA);
    },
    [onCurrencySelection],
  );

  const handleCurrencyBSelect = useCallback(
    (currencyB: Currency) => {
      onCurrencySelection(Field.CURRENCY_B, currencyB);
    },
    [onCurrencySelection],
  );

  useEffect(() => {
    if (currency0) {
      onCurrencySelection(Field.CURRENCY_A, currency0);
    } else {
      onCurrencySelection(Field.CURRENCY_A, Token.ETHER);
    }
    if (currency1) {
      onCurrencySelection(Field.CURRENCY_B, currency1);
    } else {
      onCurrencySelection(Field.CURRENCY_B, returnTokenFromKey('QUICK'));
    }
  }, [onCurrencySelection, currency0, currency1]);

  const onAdd = () => {
    if (expertMode) {
      onAddLiquidity();
    } else {
      setShowConfirm(true);
    }
  };

  const router = useRouterContract();

  const onAddLiquidity = async () => {
    if (!chainId || !library || !account || !router) return;

    const {
      [Field.CURRENCY_A]: parsedAmountA,
      [Field.CURRENCY_B]: parsedAmountB,
    } = parsedAmounts;
    if (
      !parsedAmountA ||
      !parsedAmountB ||
      !currencies[Field.CURRENCY_A] ||
      !currencies[Field.CURRENCY_B] ||
      !deadline
    ) {
      return;
    }

    const amountsMin = {
      [Field.CURRENCY_A]: calculateSlippageAmount(
        parsedAmountA,
        noLiquidity ? 0 : allowedSlippage,
      )[0],
      [Field.CURRENCY_B]: calculateSlippageAmount(
        parsedAmountB,
        noLiquidity ? 0 : allowedSlippage,
      )[0],
    };

    let estimate,
      method: (...args: any) => Promise<TransactionResponse>,
      args: Array<string | string[] | number>,
      value: BigNumber | null;
    if (
      currencies[Field.CURRENCY_A] === ETHER ||
      currencies[Field.CURRENCY_B] === ETHER
    ) {
      const tokenBIsETH = currencies[Field.CURRENCY_B] === ETHER;
      estimate = router.estimateGas.addLiquidityETH;
      method = router.addLiquidityETH;
      args = [
        wrappedCurrency(
          tokenBIsETH
            ? currencies[Field.CURRENCY_A]
            : currencies[Field.CURRENCY_B],
          chainId,
        )?.address ?? '', // token
        (tokenBIsETH ? parsedAmountA : parsedAmountB).raw.toString(), // token desired
        amountsMin[
          tokenBIsETH ? Field.CURRENCY_A : Field.CURRENCY_B
        ].toString(), // token min
        amountsMin[
          tokenBIsETH ? Field.CURRENCY_B : Field.CURRENCY_A
        ].toString(), // eth min
        account,
        deadline.toHexString(),
      ];
      value = BigNumber.from(
        (tokenBIsETH ? parsedAmountB : parsedAmountA).raw.toString(),
      );
    } else {
      estimate = router.estimateGas.addLiquidity;
      method = router.addLiquidity;
      args = [
        wrappedCurrency(currencies[Field.CURRENCY_A], chainId)?.address ?? '',
        wrappedCurrency(currencies[Field.CURRENCY_B], chainId)?.address ?? '',
        parsedAmountA.raw.toString(),
        parsedAmountB.raw.toString(),
        amountsMin[Field.CURRENCY_A].toString(),
        amountsMin[Field.CURRENCY_B].toString(),
        account,
        deadline.toHexString(),
      ];
      value = null;
    }

    setAttemptingTxn(true);
    await estimate(...args, value ? { value } : {})
      .then((estimatedGasLimit) =>
        method(...args, {
          ...(value ? { value } : {}),
          gasLimit: calculateGasMargin(estimatedGasLimit),
        }).then(async (response) => {
          setAttemptingTxn(false);
          setTxPending(true);
          const summary = t('addLiquidityTokens', liquidityTokenData);

          addTransaction(response, {
            summary,
          });

          setTxHash(response.hash);

          try {
            const receipt = await response.wait();
            finalizedTransaction(receipt, {
              summary,
            });
            setTxPending(false);
          } catch (error) {
            setTxPending(false);
            setAddLiquidityErrorMessage(t('errorInTx'));
          }

          ReactGA.event({
            category: 'Liquidity',
            action: 'Add',
            label: [
              currencies[Field.CURRENCY_A]?.symbol,
              currencies[Field.CURRENCY_B]?.symbol,
            ].join('/'),
          });
        }),
      )
      .catch((error) => {
        setAttemptingTxn(false);
        setAddLiquidityErrorMessage(t('txRejected'));
        // we only care if the error is something _other_ than the user rejected the tx
        if (error?.code !== 4001) {
          console.error(error);
        }
      });
  };

  const connectWallet = () => {
    if (ethereum && !isSupportedNetwork(ethereum)) {
      addMaticToMetamask();
    } else {
      toggleWalletModal();
    }
  };

  const handleDismissConfirmation = useCallback(() => {
    setShowConfirm(false);
    // if there was a tx hash, we want to clear the input
    if (txHash) {
      onFieldAInput('');
    }
    setTxHash('');
  }, [onFieldAInput, txHash]);

  const buttonText = useMemo(() => {
    if (account) {
      return error ?? t('supply');
    } else if (ethereum && !isSupportedNetwork(ethereum)) {
      return t('switchPolygon');
    }
    return t('connectWallet');
  }, [account, ethereum, error, t]);

  const modalHeader = () => {
    return (
      <Box>
        <Box mt={10} mb={3} display='flex' justifyContent='center'>
          <DoubleCurrencyLogo
            currency0={currencies[Field.CURRENCY_A]}
            currency1={currencies[Field.CURRENCY_B]}
            size={48}
          />
        </Box>
        <Box mb={6} color={palette.text.primary} textAlign='center'>
          <Typography variant='h6'>
            {t('supplyingTokens', liquidityTokenData)}
            <br />
            {t('receiveLPTokens', {
              amount: formatTokenAmount(liquidityMinted),
              symbolA: currencies[Field.CURRENCY_A]?.symbol,
              symbolB: currencies[Field.CURRENCY_B]?.symbol,
            })}
          </Typography>
        </Box>
        <Box mb={3} color={palette.text.secondary} textAlign='center'>
          <Typography variant='body2'>
            {t('outputEstimated', { slippage: allowedSlippage / 100 })}
          </Typography>
        </Box>
        <Box className={classes.swapButtonWrapper}>
          <Button onClick={onAddLiquidity}>{t('confirmSupply')}</Button>
        </Box>
      </Box>
    );
  };

  return (
    <Box>
      {showConfirm && (
        <TransactionConfirmationModal
          isOpen={showConfirm}
          onDismiss={handleDismissConfirmation}
          attemptingTxn={attemptingTxn}
          txPending={txPending}
          hash={txHash}
          content={() =>
            addLiquidityErrorMessage ? (
              <TransactionErrorContent
                onDismiss={handleDismissConfirmation}
                message={addLiquidityErrorMessage}
              />
            ) : (
              <ConfirmationModalContent
                title={t('supplyingliquidity')}
                onDismiss={handleDismissConfirmation}
                content={modalHeader}
              />
            )
          }
          pendingText={pendingText}
          modalContent={
            txPending ? t('submittedTxLiquidity') : t('successAddedliquidity')
          }
        />
      )}
      <CurrencyInput
        id='add-liquidity-input-tokena'
        title={`${t('token')} 1:`}
        currency={currencies[Field.CURRENCY_A]}
        showHalfButton={Boolean(maxAmounts[Field.CURRENCY_A])}
        showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
        onMax={() =>
          onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
        }
        onHalf={() =>
          onFieldAInput(
            maxAmounts[Field.CURRENCY_A]
              ? (Number(maxAmounts[Field.CURRENCY_A]?.toExact()) / 2).toString()
              : '',
          )
        }
        handleCurrencySelect={handleCurrencyASelect}
        amount={formattedAmounts[Field.CURRENCY_A]}
        setAmount={onFieldAInput}
        bgColor={currencyBg}
      />
      <Box className={classes.exchangeSwap}>
        <AddLiquidityIcon />
      </Box>
      <CurrencyInput
        id='add-liquidity-input-tokenb'
        title={`${t('token')} 2:`}
        showHalfButton={Boolean(maxAmounts[Field.CURRENCY_B])}
        currency={currencies[Field.CURRENCY_B]}
        showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
        onHalf={() =>
          onFieldBInput(
            maxAmounts[Field.CURRENCY_B]
              ? (Number(maxAmounts[Field.CURRENCY_B]?.toExact()) / 2).toString()
              : '',
          )
        }
        onMax={() =>
          onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
        }
        handleCurrencySelect={handleCurrencyBSelect}
        amount={formattedAmounts[Field.CURRENCY_B]}
        setAmount={onFieldBInput}
        bgColor={currencyBg}
      />
      {currencies[Field.CURRENCY_A] &&
        currencies[Field.CURRENCY_B] &&
        pairState !== PairState.INVALID &&
        price && (
          <Box my={2}>
            <Box className={classes.swapPrice}>
              <Typography variant='body2'>
                1 {currencies[Field.CURRENCY_A]?.symbol} ={' '}
                {price.toSignificant(3)} {currencies[Field.CURRENCY_B]?.symbol}{' '}
              </Typography>
              <Typography variant='body2'>
                1 {currencies[Field.CURRENCY_B]?.symbol} ={' '}
                {price.invert().toSignificant(3)}{' '}
                {currencies[Field.CURRENCY_A]?.symbol}{' '}
              </Typography>
            </Box>
            <Box className={classes.swapPrice}>
              <Typography variant='body2'>{t('yourPoolShare')}:</Typography>
              <Typography variant='body2'>
                {poolTokenPercentage
                  ? poolTokenPercentage.toSignificant(6) + '%'
                  : '-'}
              </Typography>
            </Box>
            <Box className={classes.swapPrice}>
              <Typography variant='body2'>{t('lpTokenReceived')}:</Typography>
              <Typography variant='body2'>
                {formatTokenAmount(userPoolBalance)} {t('lpTokens')}
              </Typography>
            </Box>
          </Box>
        )}
      <Box className={classes.swapButtonWrapper}>
        {(approvalA === ApprovalState.NOT_APPROVED ||
          approvalA === ApprovalState.PENDING ||
          approvalB === ApprovalState.NOT_APPROVED ||
          approvalB === ApprovalState.PENDING) &&
          !error && (
            <Box className={classes.approveButtons}>
              {approvalA !== ApprovalState.APPROVED && (
                <Box
                  width={approvalB !== ApprovalState.APPROVED ? '48%' : '100%'}
                >
                  <Button
                    onClick={async () => {
                      setApprovingA(true);
                      try {
                        await approveACallback();
                        setApprovingA(false);
                      } catch (e) {
                        setApprovingA(false);
                      }
                    }}
                    disabled={approvingA || approvalA === ApprovalState.PENDING}
                  >
                    {approvalA === ApprovalState.PENDING
                      ? `${t('approving')} ${
                          currencies[Field.CURRENCY_A]?.symbol
                        }`
                      : `${t('approve')} ${
                          currencies[Field.CURRENCY_A]?.symbol
                        }`}
                  </Button>
                </Box>
              )}
              {approvalB !== ApprovalState.APPROVED && (
                <Box
                  width={approvalA !== ApprovalState.APPROVED ? '48%' : '100%'}
                >
                  <Button
                    onClick={async () => {
                      setApprovingB(true);
                      try {
                        await approveBCallback();
                        setApprovingB(false);
                      } catch (e) {
                        setApprovingB(false);
                      }
                    }}
                    disabled={approvingB || approvalB === ApprovalState.PENDING}
                  >
                    {approvalB === ApprovalState.PENDING
                      ? `${t('approving')} ${
                          currencies[Field.CURRENCY_B]?.symbol
                        }`
                      : `${t('approve')} ${
                          currencies[Field.CURRENCY_B]?.symbol
                        }`}
                  </Button>
                </Box>
              )}
            </Box>
          )}
        <Button
          disabled={
            Boolean(account) &&
            (Boolean(error) ||
              approvalA !== ApprovalState.APPROVED ||
              approvalB !== ApprovalState.APPROVED)
          }
          onClick={account ? onAdd : connectWallet}
        >
          {buttonText}
        </Button>
      </Box>
    </Box>
  );
}
Example #7
Source File: StakeQuickModal.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
StakeQuickModal: React.FC<StakeQuickModalProps> = ({ open, onClose }) => {
  const classes = useStyles();
  const { palette } = useTheme();
  const [attempting, setAttempting] = useState(false);
  const { account } = useActiveWeb3React();
  const addTransaction = useTransactionAdder();
  const finalizedTransaction = useTransactionFinalizer();
  const quickBalance = useCurrencyBalance(
    account ?? undefined,
    returnTokenFromKey('QUICK'),
  );
  const userLiquidityUnstaked = useTokenBalance(
    account ?? undefined,
    returnTokenFromKey('QUICK'),
  );

  const [typedValue, setTypedValue] = useState('');
  const [stakePercent, setStakePercent] = useState(0);
  const [approving, setApproving] = useState(false);
  const { parsedAmount, error } = useDerivedLairInfo(
    typedValue,
    returnTokenFromKey('QUICK'),
    userLiquidityUnstaked,
  );

  const lairContract = useLairContract();
  const [approval, approveCallback] = useApproveCallback(
    parsedAmount,
    GlobalConst.addresses.LAIR_ADDRESS,
  );

  const onAttemptToApprove = async () => {
    if (!lairContract) throw new Error('missing dependencies');
    const liquidityAmount = parsedAmount;
    if (!liquidityAmount) throw new Error('missing liquidity amount');
    return approveCallback();
  };

  const onStake = async () => {
    setAttempting(true);
    if (lairContract && parsedAmount) {
      if (approval === ApprovalState.APPROVED) {
        try {
          const response: TransactionResponse = await lairContract.enter(
            `0x${parsedAmount.raw.toString(16)}`,
            {
              gasLimit: 350000,
            },
          );
          addTransaction(response, {
            summary: `Stake QUICK`,
          });
          const receipt = await response.wait();
          finalizedTransaction(receipt, {
            summary: `Deposit dQUICK`,
          });
          setAttempting(false);
          setStakePercent(0);
          setTypedValue('');
        } catch (err) {
          setAttempting(false);
        }
      } else {
        setAttempting(false);
        throw new Error(
          'Attempting to stake without approval or a signature. Please contact support.',
        );
      }
    }
  };

  return (
    <CustomModal open={open} onClose={onClose}>
      <Box paddingX={3} paddingY={4}>
        <Box display='flex' alignItems='center' justifyContent='space-between'>
          <Typography variant='h5'>Stake QUICK</Typography>
          <CloseIcon style={{ cursor: 'pointer' }} onClick={onClose} />
        </Box>
        <Box
          mt={3}
          bgcolor={palette.background.default}
          border='1px solid rgba(105, 108, 128, 0.12)'
          borderRadius='10px'
          padding='16px'
        >
          <Box
            display='flex'
            alignItems='center'
            justifyContent='space-between'
          >
            <Typography variant='body2'>QUICK</Typography>
            <Typography variant='body2'>
              Balance: {formatTokenAmount(quickBalance)}
            </Typography>
          </Box>
          <Box mt={2} display='flex' alignItems='center'>
            <NumericalInput
              placeholder='0'
              value={typedValue}
              fontSize={28}
              onUserInput={(value) => {
                const totalBalance = quickBalance
                  ? Number(quickBalance.toExact())
                  : 0;
                setTypedValue(value);
                setStakePercent(
                  totalBalance > 0 ? (Number(value) / totalBalance) * 100 : 0,
                );
              }}
            />
            <Typography
              variant='caption'
              style={{
                color: palette.primary.main,
                fontWeight: 'bold',
                cursor: 'pointer',
              }}
              onClick={() => {
                setTypedValue(quickBalance ? quickBalance.toExact() : '0');
                setStakePercent(100);
              }}
            >
              MAX
            </Typography>
          </Box>
          <Box display='flex' alignItems='center'>
            <Box flex={1} mr={2} mt={0.5}>
              <ColoredSlider
                min={1}
                max={100}
                step={1}
                value={stakePercent}
                onChange={(evt: any, value) => {
                  setStakePercent(value as number);
                  setTypedValue(
                    quickBalance
                      ? stakePercent < 100
                        ? (
                            (Number(quickBalance.toExact()) * stakePercent) /
                            100
                          ).toString()
                        : quickBalance.toExact()
                      : '0',
                  );
                }}
              />
            </Box>
            <Typography variant='body2'>
              {Math.min(stakePercent, 100).toLocaleString()}%
            </Typography>
          </Box>
        </Box>
        <Box
          mt={3}
          display='flex'
          justifyContent='space-between'
          alignItems='center'
        >
          <Button
            className={classes.stakeButton}
            disabled={approving || approval !== ApprovalState.NOT_APPROVED}
            onClick={async () => {
              setApproving(true);
              try {
                await onAttemptToApprove();
                setApproving(false);
              } catch (e) {
                setApproving(false);
              }
            }}
          >
            {approving ? 'Approving...' : 'Approve'}
          </Button>
          <Button
            className={classes.stakeButton}
            disabled={
              !!error || attempting || approval !== ApprovalState.APPROVED
            }
            onClick={onStake}
          >
            {attempting ? 'Staking...' : 'Stake'}
          </Button>
        </Box>
      </Box>
    </CustomModal>
  );
}
Example #8
Source File: ConvertQUICKPage.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
ConvertQUICKPage: React.FC = () => {
  const classes = useStyles();
  const { t } = useTranslation();
  const { account, library } = useActiveWeb3React();
  const [quickAmount, setQUICKAmount] = useState('');
  const [quickV2Amount, setQUICKV2Amount] = useState('');
  const [approving, setApproving] = useState(false);
  const [attemptConverting, setAttemptConverting] = useState(false);
  const [showConfirm, setShowConfirm] = useState(false);
  const [txPending, setTxPending] = useState(false);
  const [txHash, setTxHash] = useState('');
  const [txError, setTxError] = useState('');

  const quickToken = returnTokenFromKey('QUICK');
  const quickBalance = useTokenBalance(account ?? undefined, quickToken);
  const quickConvertContract = useQUICKConversionContract();
  const parsedAmount = tryParseAmount(quickAmount, quickToken);
  const [approval, approveCallback] = useApproveCallback(
    parsedAmount,
    quickConvertContract?.address,
  );

  const quickConvertingText = t('convertingQUICKtoQUICKV2', {
    quickAmount,
    quickV2Amount,
  });
  const quickConvertedText = t('convertedQUICKtoQUICKV2', {
    quickAmount,
    quickV2Amount,
  });
  const txSubmittedQuickConvertText = t('submittedTxQUICKConvert', {
    quickAmount,
    quickV2Amount,
  });
  const successQuickConvertedText = t('successConvertedQUICKtoQUICKV2', {
    quickAmount,
    quickV2Amount,
  });

  const isInsufficientQUICK =
    Number(quickAmount) > Number(quickBalance?.toExact() ?? 0);
  const buttonText = useMemo(() => {
    if (!quickAmount || !Number(quickAmount)) {
      return t('enterAmount');
    } else if (approval !== ApprovalState.APPROVED) {
      return t('approve');
    } else if (isInsufficientQUICK) {
      return t('insufficientBalance');
    } else {
      return t('convert');
    }
  }, [isInsufficientQUICK, quickAmount, t, approval]);
  const addTransaction = useTransactionAdder();
  const finalizedTransaction = useTransactionFinalizer();

  const handleDismissConfirmation = () => {
    setShowConfirm(false);
  };

  const attemptToApprove = async () => {
    setApproving(true);
    try {
      await approveCallback();
      setApproving(false);
    } catch (e) {
      setApproving(false);
    }
  };

  const convertQUICK = async () => {
    if (quickConvertContract && library && parsedAmount) {
      setAttemptConverting(true);
      setShowConfirm(true);
      await quickConvertContract
        .quickToQuickX(parsedAmount.raw.toString(), {
          gasLimit: 300000,
        })
        .then(async (response: TransactionResponse) => {
          setAttemptConverting(false);
          setTxPending(true);
          setTxError('');
          setTxHash('');
          addTransaction(response, {
            summary: quickConvertingText,
          });
          try {
            const tx = await response.wait();
            finalizedTransaction(tx, {
              summary: quickConvertedText,
            });
            setTxPending(false);
            setTxHash(tx.transactionHash);
          } catch (err) {
            setTxPending(false);
            setTxError(t('errorInTx'));
          }
        })
        .catch(() => {
          setAttemptConverting(false);
          setTxPending(false);
          setTxHash('');
          setTxError(t('txRejected'));
        });
    }
  };

  return (
    <Box width='100%' maxWidth={488} id='convertQUICKPage'>
      <Typography variant='h4'>{t('convert')} QUICK</Typography>
      <Box className={classes.wrapper}>
        <Box display='flex' alignItems='center' mb={3}>
          <Box className={classes.iconWrapper}>
            <img src={QUICKIcon} alt='QUICK' />
          </Box>
          <Typography variant='h6'>QUICK(OLD)</Typography>
          <Box mx={1.5} className={classes.convertArrow}>
            <ArrowForward />
          </Box>
          <Box className={classes.iconWrapper}>
            <QUICKV2Icon />
          </Box>
          <Typography variant='h6'>QUICK(NEW)</Typography>
        </Box>
        <Typography variant='body2' color='textSecondary'>
          <Trans i18nKey='convertQuick'>
            Convert your QUICK(OLD) to QUICK(NEW). Read more about QUICK token
            split{' '}
            <a
              href='https://quickswap-layer2.medium.com/you-voted-for-a-1-1000-token-split-to-make-quick-more-appealing-9c25c2a2dd7e'
              rel='noreferrer'
              target='_blank'
            >
              here
            </a>
          </Trans>
        </Typography>
        <Box className={classes.conversionRate}>
          <Typography variant='caption'>
            {t('conversionRate')}: 1 QUICK(OLD) ={' '}
            {GlobalConst.utils.QUICK_CONVERSION_RATE} QUICK(NEW)
          </Typography>
        </Box>
        <Box mt={4} mb={2}>
          <Typography variant='body2' color='textSecondary'>
            {t('yourbalance')}: {formatTokenAmount(quickBalance)}
          </Typography>
          <Box
            className={cx(
              classes.currencyInput,
              isInsufficientQUICK && classes.errorInput,
            )}
          >
            <NumericalInput
              placeholder='0.00'
              value={quickAmount}
              fontSize={18}
              onUserInput={(value) => {
                const digits =
                  value.indexOf('.') > -1 ? value.split('.')[1].length : 0;
                let fixedVal = value;
                if (digits > quickToken.decimals) {
                  fixedVal = Number(value).toFixed(quickToken.decimals);
                }
                setQUICKAmount(fixedVal);
                setQUICKV2Amount(
                  (
                    Number(fixedVal) * GlobalConst.utils.QUICK_CONVERSION_RATE
                  ).toLocaleString('fullwide', {
                    useGrouping: false,
                    maximumFractionDigits: quickToken.decimals,
                  }),
                );
              }}
            />
            <Box
              mr={1}
              className={classes.maxButton}
              onClick={() => {
                if (quickBalance) {
                  setQUICKAmount(quickBalance.toExact());
                  setQUICKV2Amount(
                    (
                      Number(quickBalance.toExact()) *
                      GlobalConst.utils.QUICK_CONVERSION_RATE
                    ).toString(),
                  );
                }
              }}
            >
              {t('max')}
            </Box>
            <Typography variant='h6'>QUICK(OLD)</Typography>
          </Box>
          {isInsufficientQUICK && (
            <Typography variant='body2' className={classes.errorText}>
              {t('insufficientBalance', { symbol: 'QUICK' })}
            </Typography>
          )}
        </Box>
        <Box ml={2} className={classes.convertArrow}>
          <ArrowDownward />
        </Box>
        <Box mt={2} mb={4}>
          <Typography variant='body2' color='textSecondary'>
            {t('youwillreceive')}:
          </Typography>
          <Box className={classes.currencyInput}>
            <NumericalInput
              placeholder='0.00'
              value={quickV2Amount}
              fontSize={18}
              onUserInput={(value) => {
                setQUICKV2Amount(value);
                const quickAmount = (
                  Number(value) / GlobalConst.utils.QUICK_CONVERSION_RATE
                ).toLocaleString('fullwide', {
                  useGrouping: false,
                  maximumFractionDigits: quickToken.decimals,
                });
                setQUICKAmount(quickAmount);
              }}
            />
            <Typography variant='h6'>QUICK(NEW)</Typography>
          </Box>
        </Box>
        <Box display='flex' justifyContent='center'>
          <Button
            disabled={
              approving ||
              attemptConverting ||
              isInsufficientQUICK ||
              !quickAmount ||
              !Number(quickAmount)
            }
            className={classes.convertButton}
            onClick={() => {
              if (approval === ApprovalState.APPROVED) {
                convertQUICK();
              } else {
                attemptToApprove();
              }
            }}
          >
            {buttonText}
          </Button>
        </Box>
      </Box>
      {showConfirm && (
        <TransactionConfirmationModal
          isOpen={showConfirm}
          onDismiss={handleDismissConfirmation}
          attemptingTxn={attemptConverting}
          txPending={txPending}
          hash={txHash}
          content={() =>
            txError ? (
              <TransactionErrorContent
                onDismiss={handleDismissConfirmation}
                message={txError}
              />
            ) : (
              <ConfirmationModalContent
                title={t('convertingQUICK')}
                onDismiss={handleDismissConfirmation}
                content={() => (
                  <Box textAlign='center'>
                    <Box mt={6} mb={5}>
                      <CircularProgress size={80} />
                    </Box>
                    <Typography variant='body1'>
                      {quickConvertingText}
                    </Typography>
                  </Box>
                )}
              />
            )
          }
          pendingText={quickConvertingText}
          modalContent={
            txPending ? txSubmittedQuickConvertText : successQuickConvertedText
          }
        />
      )}
    </Box>
  );
}
Example #9
Source File: DragonsLair.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
DragonsLair: React.FC = () => {
  const classes = useStyles();
  const { palette } = useTheme();
  const quickPrice = useUSDCPriceToken(returnTokenFromKey('QUICK'));
  const dQUICKPrice = useUSDCPriceToken(returnTokenFromKey('DQUICK'));
  const dQUICKtoQUICK = dQUICKPrice / quickPrice;
  const QUICKtodQUICK = quickPrice / dQUICKPrice;
  const [isQUICKRate, setIsQUICKRate] = useState(false);
  const [openStakeModal, setOpenStakeModal] = useState(false);
  const [openUnstakeModal, setOpenUnstakeModal] = useState(false);
  const lairInfo = useLairInfo();
  const APY = useLairDQUICKAPY(lairInfo);

  return (
    <Box position='relative' zIndex={3}>
      {openStakeModal && (
        <StakeQuickModal
          open={openStakeModal}
          onClose={() => setOpenStakeModal(false)}
        />
      )}
      {openUnstakeModal && (
        <UnstakeQuickModal
          open={openUnstakeModal}
          onClose={() => setOpenUnstakeModal(false)}
        />
      )}
      <Box display='flex'>
        <CurrencyLogo currency={returnTokenFromKey('QUICK')} size='32px' />
        <Box ml={1.5}>
          <Typography
            variant='body2'
            style={{ color: palette.text.primary, lineHeight: 1 }}
          >
            QUICK
          </Typography>
          <Typography variant='caption' style={{ color: palette.text.hint }}>
            Single Stake — Auto compounding
          </Typography>
        </Box>
      </Box>
      <Box display='flex' justifyContent='space-between' mt={1.5}>
        <Typography variant='body2'>Total QUICK</Typography>
        <Typography variant='body2'>
          {lairInfo
            ? lairInfo.totalQuickBalance.toFixed(2, {
                groupSeparator: ',',
              })
            : 0}
        </Typography>
      </Box>
      <Box display='flex' justifyContent='space-between' mt={1.5}>
        <Typography variant='body2'>TVL:</Typography>
        <Typography variant='body2'>
          $
          {(
            Number(lairInfo.totalQuickBalance.toExact()) * quickPrice
          ).toLocaleString()}
        </Typography>
      </Box>
      <Box display='flex' justifyContent='space-between' mt={1.5}>
        <Typography variant='body2'>APY</Typography>
        <Typography variant='body2' style={{ color: palette.success.main }}>
          {APY}%
        </Typography>
      </Box>
      <Box display='flex' justifyContent='space-between' mt={1.5}>
        <Typography variant='body2'>Your Deposits</Typography>
        <Typography variant='body2'>
          {formatTokenAmount(lairInfo.QUICKBalance)}
        </Typography>
      </Box>
      <Box
        mt={2.5}
        width={1}
        height='40px'
        display='flex'
        alignItems='center'
        justifyContent='center'
        borderRadius={10}
        border={`1px solid ${palette.secondary.light}`}
      >
        <CurrencyLogo currency={returnTokenFromKey('QUICK')} />
        <Typography variant='body2' style={{ margin: '0 8px' }}>
          {isQUICKRate ? 1 : dQUICKtoQUICK.toLocaleString()} QUICK =
        </Typography>
        <CurrencyLogo currency={returnTokenFromKey('QUICK')} />
        <Typography variant='body2' style={{ margin: '0 8px' }}>
          {isQUICKRate ? QUICKtodQUICK.toLocaleString() : 1} dQUICK
        </Typography>
        <PriceExchangeIcon
          style={{ cursor: 'pointer' }}
          onClick={() => setIsQUICKRate(!isQUICKRate)}
        />
      </Box>
      <Box
        className={classes.stakeButton}
        bgcolor={palette.primary.main}
        onClick={() => setOpenStakeModal(true)}
      >
        <Typography variant='body2'>Stake</Typography>
      </Box>
      <Box
        className={classes.stakeButton}
        bgcolor='transparent'
        onClick={() => setOpenUnstakeModal(true)}
      >
        <Typography variant='body2'>Unstake</Typography>
      </Box>
      <Box mt={3} textAlign='center'>
        <Typography
          variant='caption'
          style={{ color: palette.text.secondary, fontWeight: 500 }}
        >
          ⭐️ When you unstake, the contract will automatically claim QUICK on
          your behalf.
        </Typography>
      </Box>
    </Box>
  );
}
Example #10
Source File: hooks.ts    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
// gets the dual rewards staking info from the network for the active chain id
export function useDualStakingInfo(
  pairToFilterBy?: Pair | null,
  startIndex?: number,
  endIndex?: number,
  filter?: { search: string; isStaked: boolean },
): DualStakingInfo[] {
  const { chainId, account } = useActiveWeb3React();

  const info = useMemo(
    () =>
      chainId
        ? returnDualStakingInfo()
            [chainId]?.slice(startIndex, endIndex)
            ?.filter((stakingRewardInfo) =>
              pairToFilterBy === undefined || pairToFilterBy === null
                ? getSearchFiltered(
                    stakingRewardInfo,
                    filter ? filter.search : '',
                  )
                : pairToFilterBy.involvesToken(stakingRewardInfo.tokens[0]) &&
                  pairToFilterBy.involvesToken(stakingRewardInfo.tokens[1]),
            ) ?? []
        : [],
    [chainId, pairToFilterBy, startIndex, endIndex, filter],
  );

  const uni = chainId ? GlobalValue.tokens.UNI[chainId] : undefined;

  const rewardsAddresses = useMemo(
    () => info.map(({ stakingRewardAddress }) => stakingRewardAddress),
    [info],
  );
  // const pairAddresses = useMemo(() => info.map(({ pair }) => pair), [info]);

  // useEffect(() => {
  //   getDualBulkPairData(pairAddresses);
  // }, [pairAddresses]);

  const accountArg = useMemo(() => [account ?? undefined], [account]);

  // get all the info from the staking rewards contracts
  const balances = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'balanceOf',
    accountArg,
  );
  const earnedAAmounts = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'earnedA',
    accountArg,
  );
  const earnedBAmounts = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'earnedB',
    accountArg,
  );
  const totalSupplies = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'totalSupply',
  );
  const rewardRatesA = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'rewardRateA',
    undefined,
    NEVER_RELOAD,
  );

  const rewardRatesB = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_DUAL_REWARDS_INTERFACE,
    'rewardRateB',
    undefined,
    NEVER_RELOAD,
  );

  const baseTokens = info.map((item) => {
    const unwrappedCurrency = unwrappedToken(item.baseToken);
    const empty = unwrappedToken(returnTokenFromKey('EMPTY'));
    return unwrappedCurrency === empty ? item.tokens[0] : item.baseToken;
  });

  const usdPrices = useUSDCPrices(baseTokens);
  const totalSupplys = useTotalSupplys(
    info.map((item) => getFarmLPToken(item)),
  );
  const stakingPairs = usePairs(info.map((item) => item.tokens));
  const rewardTokenAPrices = useUSDCPricesToken(
    info.map((item) => item.rewardTokenA),
  );
  const rewardTokenBPrices = useUSDCPricesToken(
    info.map((item) => item.rewardTokenB),
  );

  return useMemo(() => {
    if (!chainId || !uni) return [];

    return rewardsAddresses.reduce<DualStakingInfo[]>(
      (memo, rewardsAddress, index) => {
        // these two are dependent on account
        const balanceState = balances[index];
        const earnedAAmountState = earnedAAmounts[index];
        const earnedBAmountState = earnedBAmounts[index];

        // these get fetched regardless of account
        const totalSupplyState = totalSupplies[index];
        const rewardRateAState = rewardRatesA[index];
        const rewardRateBState = rewardRatesB[index];
        const stakingInfo = info[index];
        const rewardTokenAPrice = rewardTokenAPrices[index];
        const rewardTokenBPrice = rewardTokenBPrices[index];

        if (
          // these may be undefined if not logged in
          !balanceState?.loading &&
          !earnedAAmountState?.loading &&
          !earnedBAmountState?.loading &&
          // always need these
          totalSupplyState &&
          !totalSupplyState.loading &&
          rewardRateAState &&
          !rewardRateAState.loading &&
          rewardRateBState &&
          !rewardRateBState.loading
        ) {
          const rateA = web3.utils.toWei(stakingInfo.rateA.toString());
          const rateB = web3.utils.toWei(stakingInfo.rateB.toString());
          const stakedAmount = initTokenAmountFromCallResult(
            getFarmLPToken(stakingInfo),
            balanceState,
          );
          const totalStakedAmount = initTokenAmountFromCallResult(
            getFarmLPToken(stakingInfo),
            totalSupplyState,
          );
          const totalRewardRateA = new TokenAmount(uni, JSBI.BigInt(rateA));
          const totalRewardRateB = new TokenAmount(uni, JSBI.BigInt(rateB));
          //const pair = info[index].pair.toLowerCase();
          //const fees = (pairData && pairData[pair] ? pairData[pair].oneDayVolumeUSD * 0.0025: 0);
          const totalRewardRateA01 = initTokenAmountFromCallResult(
            uni,
            rewardRateAState,
          );
          const totalRewardRateB01 = initTokenAmountFromCallResult(
            uni,
            rewardRateBState,
          );

          const getHypotheticalRewardRate = (
            stakedAmount?: TokenAmount,
            totalStakedAmount?: TokenAmount,
            totalRewardRate?: TokenAmount,
          ): TokenAmount | undefined => {
            if (!stakedAmount || !totalStakedAmount || !totalRewardRate) return;
            return new TokenAmount(
              uni,
              JSBI.greaterThan(totalStakedAmount.raw, JSBI.BigInt(0))
                ? JSBI.divide(
                    JSBI.multiply(totalRewardRate.raw, stakedAmount.raw),
                    totalStakedAmount.raw,
                  )
                : JSBI.BigInt(0),
            );
          };

          const individualRewardRateA = getHypotheticalRewardRate(
            stakedAmount,
            totalStakedAmount,
            totalRewardRateA01,
          );
          const individualRewardRateB = getHypotheticalRewardRate(
            stakedAmount,
            totalStakedAmount,
            totalRewardRateB01,
          );

          const { oneDayFee, accountFee } = getStakingFees(
            stakingInfo,
            balanceState,
            totalSupplyState,
          );

          let valueOfTotalStakedAmountInBaseToken: TokenAmount | undefined;

          const [, stakingTokenPair] = stakingPairs[index];
          const totalSupply = totalSupplys[index];
          const usdPrice = usdPrices[index];

          if (
            totalSupply &&
            stakingTokenPair &&
            baseTokens[index] &&
            totalStakedAmount
          ) {
            // take the total amount of LP tokens staked, multiply by ETH value of all LP tokens, divide by all LP tokens
            valueOfTotalStakedAmountInBaseToken = new TokenAmount(
              baseTokens[index],
              JSBI.divide(
                JSBI.multiply(
                  JSBI.multiply(
                    totalStakedAmount.raw,
                    stakingTokenPair.reserveOf(baseTokens[index]).raw,
                  ),
                  JSBI.BigInt(2), // this is b/c the value of LP shares are ~double the value of the WETH they entitle owner to
                ),
                totalSupply.raw,
              ),
            );
          }

          const valueOfTotalStakedAmountInUSDC =
            valueOfTotalStakedAmountInBaseToken &&
            usdPrice?.quote(valueOfTotalStakedAmountInBaseToken);

          const tvl = valueOfTotalStakedAmountInUSDC
            ? valueOfTotalStakedAmountInUSDC.toExact()
            : valueOfTotalStakedAmountInBaseToken?.toExact();

          const perMonthReturnInRewards =
            ((stakingInfo.rateA * rewardTokenAPrice +
              stakingInfo.rateB * rewardTokenBPrice) *
              (getDaysCurrentYear() / 12)) /
            Number(valueOfTotalStakedAmountInUSDC?.toExact());

          memo.push({
            stakingRewardAddress: rewardsAddress,
            tokens: stakingInfo.tokens,
            ended: stakingInfo.ended,
            name: stakingInfo.name,
            lp: stakingInfo.lp,
            earnedAmountA: initTokenAmountFromCallResult(
              uni,
              earnedAAmountState,
            ),
            earnedAmountB: initTokenAmountFromCallResult(
              uni,
              earnedBAmountState,
            ),
            rewardRateA: individualRewardRateA,
            rewardRateB: individualRewardRateB,
            totalRewardRateA: totalRewardRateA,
            totalRewardRateB: totalRewardRateB,
            stakedAmount: stakedAmount,
            totalStakedAmount: totalStakedAmount,
            getHypotheticalRewardRate,
            baseToken: stakingInfo.baseToken,
            pair: stakingInfo.pair,
            rateA: stakingInfo.rateA,
            rateB: stakingInfo.rateB,
            rewardTokenA: stakingInfo.rewardTokenA,
            rewardTokenB: stakingInfo.rewardTokenB,
            rewardTokenBBase: stakingInfo.rewardTokenBBase,
            rewardTokenAPrice,
            rewardTokenBPrice,
            tvl,
            perMonthReturnInRewards,
            totalSupply,
            usdPrice,
            stakingTokenPair,
            oneDayFee,
            accountFee,
          });
        }
        return memo;
      },
      [],
    );
  }, [
    balances,
    chainId,
    earnedAAmounts,
    earnedBAmounts,
    info,
    rewardsAddresses,
    totalSupplies,
    uni,
    rewardRatesA,
    rewardRatesB,
    baseTokens,
    totalSupplys,
    usdPrices,
    stakingPairs,
    rewardTokenAPrices,
    rewardTokenBPrices,
  ]).filter((stakingInfo) =>
    filter && filter.isStaked
      ? stakingInfo.stakedAmount && stakingInfo.stakedAmount.greaterThan('0')
      : true,
  );
}
Example #11
Source File: hooks.ts    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
// gets the staking info from the network for the active chain id
export function useStakingInfo(
  pairToFilterBy?: Pair | null,
  startIndex?: number,
  endIndex?: number,
  filter?: { search: string; isStaked: boolean },
): StakingInfo[] {
  const { chainId, account } = useActiveWeb3React();

  const info = useMemo(
    () =>
      chainId
        ? returnStakingInfo()
            [chainId]?.slice(startIndex, endIndex)
            ?.filter((stakingRewardInfo) =>
              pairToFilterBy === undefined || pairToFilterBy === null
                ? getSearchFiltered(
                    stakingRewardInfo,
                    filter ? filter.search : '',
                  )
                : pairToFilterBy.involvesToken(stakingRewardInfo.tokens[0]) &&
                  pairToFilterBy.involvesToken(stakingRewardInfo.tokens[1]),
            ) ?? []
        : [],
    [chainId, pairToFilterBy, startIndex, endIndex, filter],
  );

  const uni = chainId ? GlobalValue.tokens.UNI[chainId] : undefined;

  const rewardsAddresses = useMemo(
    () => info.map(({ stakingRewardAddress }) => stakingRewardAddress),
    [info],
  );
  // const pairAddresses = useMemo(() => info.map(({ pair }) => pair), [info]);

  // useEffect(() => {
  //   getBulkPairData(allPairAddress);
  // }, [allPairAddress]);

  const accountArg = useMemo(() => [account ?? undefined], [account]);

  // get all the info from the staking rewards contracts
  const balances = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_REWARDS_INTERFACE,
    'balanceOf',
    accountArg,
  );
  const earnedAmounts = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_REWARDS_INTERFACE,
    'earned',
    accountArg,
  );
  const totalSupplies = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_REWARDS_INTERFACE,
    'totalSupply',
  );
  const rewardRates = useMultipleContractSingleData(
    rewardsAddresses,
    STAKING_REWARDS_INTERFACE,
    'rewardRate',
    undefined,
    NEVER_RELOAD,
  );

  const baseTokens = info.map((item) => {
    const unwrappedCurrency = unwrappedToken(item.baseToken);
    const empty = unwrappedToken(returnTokenFromKey('EMPTY'));
    return unwrappedCurrency === empty ? item.tokens[0] : item.baseToken;
  });
  const rewardTokens = info.map((item) => item.rewardToken);

  const usdPrices = useUSDCPrices(baseTokens);
  const usdPricesRewardTokens = useUSDCPricesToken(rewardTokens);
  const totalSupplys = useTotalSupplys(
    info.map((item) => {
      const lp = item.lp;
      const dummyPair = new Pair(
        new TokenAmount(item.tokens[0], '0'),
        new TokenAmount(item.tokens[1], '0'),
      );
      return lp && lp !== ''
        ? new Token(137, lp, 18, 'SLP', 'Staked LP')
        : dummyPair.liquidityToken;
    }),
  );
  const stakingPairs = usePairs(info.map((item) => item.tokens));

  return useMemo(() => {
    if (!chainId || !uni) return [];

    return rewardsAddresses.reduce<StakingInfo[]>(
      (memo, rewardsAddress, index) => {
        // these two are dependent on account
        const balanceState = balances[index];
        const earnedAmountState = earnedAmounts[index];

        // these get fetched regardless of account
        const totalSupplyState = totalSupplies[index];
        const rewardRateState = rewardRates[index];
        const stakingInfo = info[index];
        const rewardTokenPrice = usdPricesRewardTokens[index];

        if (
          // these may be undefined if not logged in
          !balanceState?.loading &&
          !earnedAmountState?.loading &&
          // always need these
          totalSupplyState &&
          !totalSupplyState.loading &&
          rewardRateState &&
          !rewardRateState.loading
        ) {
          // get the LP token
          const tokens = stakingInfo.tokens;
          const dummyPair = new Pair(
            new TokenAmount(tokens[0], '0'),
            new TokenAmount(tokens[1], '0'),
          );

          // check for account, if no account set to 0
          const lp = stakingInfo.lp;
          const rate = web3.utils.toWei(stakingInfo.rate.toString());
          const stakedAmount = initTokenAmountFromCallResult(
            getFarmLPToken(stakingInfo),
            balanceState,
          );
          const totalStakedAmount = initTokenAmountFromCallResult(
            getFarmLPToken(stakingInfo),
            totalSupplyState,
          );
          const totalRewardRate = new TokenAmount(uni, JSBI.BigInt(rate));
          //const pair = info[index].pair.toLowerCase();
          //const fees = (pairData && pairData[pair] ? pairData[pair].oneDayVolumeUSD * 0.0025: 0);
          const totalRewardRate01 = initTokenAmountFromCallResult(
            uni,
            rewardRateState,
          );
          const getHypotheticalRewardRate = (
            stakedAmount?: TokenAmount,
            totalStakedAmount?: TokenAmount,
            totalRewardRate?: TokenAmount,
          ): TokenAmount | undefined => {
            if (!stakedAmount || !totalStakedAmount || !totalRewardRate) return;
            return new TokenAmount(
              uni,
              JSBI.greaterThan(totalStakedAmount.raw, JSBI.BigInt(0))
                ? JSBI.divide(
                    JSBI.multiply(totalRewardRate.raw, stakedAmount.raw),
                    totalStakedAmount.raw,
                  )
                : JSBI.BigInt(0),
            );
          };

          const individualRewardRate = getHypotheticalRewardRate(
            stakedAmount,
            totalStakedAmount,
            totalRewardRate01,
          );

          const { oneYearFeeAPY, oneDayFee, accountFee } = getStakingFees(
            stakingInfo,
            balanceState,
            totalSupplyState,
          );

          let valueOfTotalStakedAmountInBaseToken: TokenAmount | undefined;

          const [, stakingTokenPair] = stakingPairs[index];
          const totalSupply = totalSupplys[index];
          const usdPrice = usdPrices[index];

          if (
            totalSupply &&
            stakingTokenPair &&
            baseTokens[index] &&
            totalStakedAmount
          ) {
            // take the total amount of LP tokens staked, multiply by ETH value of all LP tokens, divide by all LP tokens
            valueOfTotalStakedAmountInBaseToken = new TokenAmount(
              baseTokens[index],
              JSBI.divide(
                JSBI.multiply(
                  JSBI.multiply(
                    totalStakedAmount.raw,
                    stakingTokenPair.reserveOf(baseTokens[index]).raw,
                  ),
                  JSBI.BigInt(2), // this is b/c the value of LP shares are ~double the value of the WETH they entitle owner to
                ),
                totalSupply.raw,
              ),
            );
          }

          const valueOfTotalStakedAmountInUSDC =
            valueOfTotalStakedAmountInBaseToken &&
            usdPrice?.quote(valueOfTotalStakedAmountInBaseToken);

          const tvl = valueOfTotalStakedAmountInUSDC
            ? valueOfTotalStakedAmountInUSDC.toExact()
            : valueOfTotalStakedAmountInBaseToken?.toExact();

          const perMonthReturnInRewards =
            (Number(stakingInfo.rate) *
              rewardTokenPrice *
              (getDaysCurrentYear() / 12)) /
            Number(valueOfTotalStakedAmountInUSDC?.toExact());

          memo.push({
            stakingRewardAddress: rewardsAddress,
            tokens: stakingInfo.tokens,
            ended: stakingInfo.ended,
            name: stakingInfo.name,
            lp: stakingInfo.lp,
            rewardToken: stakingInfo.rewardToken,
            rewardTokenPrice,
            earnedAmount: initTokenAmountFromCallResult(uni, earnedAmountState),
            rewardRate: individualRewardRate,
            totalRewardRate: totalRewardRate,
            stakedAmount: stakedAmount,
            totalStakedAmount: totalStakedAmount,
            getHypotheticalRewardRate,
            baseToken: stakingInfo.baseToken,
            pair: stakingInfo.pair,
            rate: stakingInfo.rate,
            oneYearFeeAPY: oneYearFeeAPY,
            oneDayFee,
            accountFee,
            tvl,
            perMonthReturnInRewards,
            valueOfTotalStakedAmountInBaseToken,
            usdPrice,
            stakingTokenPair,
            totalSupply,
          });
        }
        return memo;
      },
      [],
    );
  }, [
    balances,
    chainId,
    earnedAmounts,
    info,
    rewardsAddresses,
    totalSupplies,
    uni,
    rewardRates,
    usdPricesRewardTokens,
    baseTokens,
    totalSupplys,
    usdPrices,
    stakingPairs,
  ]).filter((stakingInfo) =>
    filter && filter.isStaked
      ? stakingInfo.stakedAmount && stakingInfo.stakedAmount.greaterThan('0')
      : true,
  );
}
Example #12
Source File: useUSDCPrice.ts    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Returns the price in USDC of the input currency
 * @param currency currency to compute the USDC price of
 */
export default function useUSDCPrice(currency?: Currency): Price | undefined {
  const { chainId } = useActiveWeb3React();
  let wrapped = wrappedCurrency(currency, chainId);
  const internalWrapped = wrapped;
  if (wrapped?.equals(returnTokenFromKey('CXETH'))) {
    wrapped = wrappedCurrency(returnTokenFromKey('ETHER'), chainId);
  }

  const tokenPairs: [Currency | undefined, Currency | undefined][] = useMemo(
    () => [
      [
        chainId && wrapped && currencyEquals(WETH[chainId], wrapped)
          ? undefined
          : wrapped,
        chainId ? WETH[chainId] : undefined,
      ],
      [
        wrapped?.equals(returnTokenFromKey('QUICK')) ? undefined : wrapped,
        chainId === ChainId.MATIC ? returnTokenFromKey('QUICK') : undefined,
      ],
      [
        wrapped?.equals(returnTokenFromKey('USDC')) ? undefined : wrapped,
        chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
      ],
      [
        wrapped?.equals(returnTokenFromKey('USDT')) ? undefined : wrapped,
        chainId === ChainId.MATIC ? returnTokenFromKey('USDT') : undefined,
      ],
      [
        wrapped?.equals(returnTokenFromKey('DAI')) ? undefined : wrapped,
        chainId === ChainId.MATIC ? returnTokenFromKey('DAI') : undefined,
      ],
      [
        chainId ? WETH[chainId] : undefined,
        chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
      ],
      [
        chainId === ChainId.MATIC ? returnTokenFromKey('QUICK') : undefined,
        chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
      ],
    ],
    [chainId, wrapped],
  );
  const [
    [ethPairState, ethPair],
    [quickPairState, quickPair],
    [usdcPairState, usdcPair],
    [usdtPairState, usdtPair],
    [daiPairState, daiPair],
    [usdcEthPairState, usdcEthPair],
    [usdcQuickPairState, usdcQuickPair],
  ] = usePairs(tokenPairs);

  return useMemo(() => {
    if (!currency || !wrapped || !chainId) {
      return undefined;
    }
    // handle weth/eth
    if (wrapped.equals(WETH[chainId])) {
      if (usdcPair) {
        const price = usdcPair.priceOf(WETH[chainId]);
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          price.denominator,
          price.numerator,
        );
      } else {
        return undefined;
      }
    }
    // handle usdc
    if (wrapped.equals(returnTokenFromKey('USDC'))) {
      return new Price(
        returnTokenFromKey('USDC'),
        returnTokenFromKey('USDC'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('USDT'))) {
      return new Price(
        returnTokenFromKey('USDT'),
        returnTokenFromKey('USDT'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('DAI'))) {
      return new Price(
        returnTokenFromKey('DAI'),
        returnTokenFromKey('DAI'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('FRAX'))) {
      return new Price(
        returnTokenFromKey('FRAX'),
        returnTokenFromKey('FRAX'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('MI'))) {
      return new Price(
        returnTokenFromKey('MI'),
        returnTokenFromKey('MI'),
        '1',
        '1',
      );
    }

    const ethPairETHAmount = ethPair?.reserveOf(WETH[chainId]);
    const ethPairETHUSDCValue: JSBI =
      ethPairETHAmount && usdcEthPair
        ? usdcEthPair.priceOf(WETH[chainId]).quote(ethPairETHAmount).raw
        : JSBI.BigInt(0);

    // all other tokens
    // first try the usdc pair
    if (
      usdcPairState === PairState.EXISTS &&
      usdcPair &&
      usdcPair
        .reserveOf(returnTokenFromKey('USDC'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = usdcPair.priceOf(wrapped);

      if (internalWrapped?.equals(returnTokenFromKey('CXETH'))) {
        return new Price(
          returnTokenFromKey('CXETH'),
          returnTokenFromKey('USDC'),
          price.denominator,
          price.numerator,
        );
      }

      return new Price(
        currency,
        returnTokenFromKey('USDC'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      usdtPairState === PairState.EXISTS &&
      usdtPair &&
      usdtPair
        .reserveOf(returnTokenFromKey('USDT'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = usdtPair.priceOf(wrapped);
      return new Price(
        currency,
        returnTokenFromKey('USDT'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      daiPairState === PairState.EXISTS &&
      daiPair &&
      daiPair
        .reserveOf(returnTokenFromKey('DAI'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = daiPair.priceOf(wrapped);
      return new Price(
        currency,
        returnTokenFromKey('DAI'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      ethPairState === PairState.EXISTS &&
      ethPair &&
      usdcEthPairState === PairState.EXISTS &&
      usdcEthPair
    ) {
      if (
        usdcEthPair.reserveOf(returnTokenFromKey('USDC')).greaterThan('0') &&
        ethPair.reserveOf(WETH[chainId]).greaterThan('1')
      ) {
        const ethUsdcPrice = usdcEthPair.priceOf(returnTokenFromKey('USDC'));
        const currencyEthPrice = ethPair.priceOf(WETH[chainId]);
        const usdcPrice = ethUsdcPrice.multiply(currencyEthPrice).invert();
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          usdcPrice.denominator,
          usdcPrice.numerator,
        );
      }
    }
    if (
      quickPairState === PairState.EXISTS &&
      quickPair &&
      usdcQuickPairState === PairState.EXISTS &&
      usdcQuickPair
    ) {
      if (
        usdcQuickPair.reserveOf(returnTokenFromKey('USDC')).greaterThan('0') &&
        quickPair.reserveOf(returnTokenFromKey('QUICK')).greaterThan('5')
      ) {
        const quickUsdcPrice = usdcQuickPair.priceOf(
          returnTokenFromKey('USDC'),
        );
        const currencyQuickPrice = quickPair.priceOf(
          returnTokenFromKey('QUICK'),
        );
        const usdcPrice = quickUsdcPrice.multiply(currencyQuickPrice).invert();
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          usdcPrice.denominator,
          usdcPrice.numerator,
        );
      }
    }
    return undefined;
  }, [
    currency,
    wrapped,
    chainId,
    ethPair,
    usdcEthPair,
    usdcPairState,
    usdcPair,
    usdtPairState,
    usdtPair,
    daiPairState,
    daiPair,
    ethPairState,
    usdcEthPairState,
    quickPairState,
    quickPair,
    usdcQuickPairState,
    usdcQuickPair,
    internalWrapped,
  ]);
}
Example #13
Source File: useUSDCPrice.ts    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
export function useUSDCPrices(currencies: Currency[]): (Price | undefined)[] {
  const { chainId } = useActiveWeb3React();
  const wrappedCurrencies = currencies.map((currency) => {
    let wrapped = wrappedCurrency(currency, chainId);
    if (wrapped?.equals(returnTokenFromKey('CXETH'))) {
      wrapped = wrappedCurrency(returnTokenFromKey('ETHER'), chainId);
    }
    return wrapped;
  });
  const tokenPairs: [Currency | undefined, Currency | undefined][] = [];
  wrappedCurrencies.forEach((wrapped, ind) => {
    tokenPairs.push([
      chainId && wrapped && currencyEquals(WETH[chainId], wrapped)
        ? undefined
        : currencies[ind],
      chainId ? WETH[chainId] : undefined,
    ]);
    tokenPairs.push([
      wrapped?.equals(returnTokenFromKey('QUICK')) ? undefined : wrapped,
      chainId === ChainId.MATIC ? returnTokenFromKey('QUICK') : undefined,
    ]);
    tokenPairs.push([
      wrapped?.equals(returnTokenFromKey('USDC')) ? undefined : wrapped,
      chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
    ]);
    tokenPairs.push([
      wrapped?.equals(returnTokenFromKey('USDT')) ? undefined : wrapped,
      chainId === ChainId.MATIC ? returnTokenFromKey('USDT') : undefined,
    ]);
    tokenPairs.push([
      wrapped?.equals(returnTokenFromKey('DAI')) ? undefined : wrapped,
      chainId === ChainId.MATIC ? returnTokenFromKey('DAI') : undefined,
    ]);
    tokenPairs.push([
      chainId ? WETH[chainId] : undefined,
      chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
    ]);
    tokenPairs.push([
      chainId ? returnTokenFromKey('QUICK') : undefined,
      chainId === ChainId.MATIC ? returnTokenFromKey('USDC') : undefined,
    ]);
  });
  const pairs = usePairs(tokenPairs);
  const remainPairs = currencies.map((_, index) => {
    return pairs.slice(7 * index, 7 * (index + 1));
  });

  return currencies.map((currency, index) => {
    const [
      [ethPairState, ethPair],
      [quickPairState, quickPair],
      [usdcPairState, usdcPair],
      [usdtPairState, usdtPair],
      [daiPairState, daiPair],
      [usdcEthPairState, usdcEthPair],
      [usdcQuickPairState, usdcQuickPair],
    ] = remainPairs[index];
    const wrapped = wrappedCurrencies[index];
    const internalWrapped = wrappedCurrency(currency, chainId);
    if (!wrapped || !chainId) {
      return undefined;
    }
    if (wrapped.equals(WETH[chainId])) {
      if (usdcPair) {
        const price = usdcPair.priceOf(WETH[chainId]);
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          price.denominator,
          price.numerator,
        );
      } else {
        return undefined;
      }
    }
    // handle usdc
    if (wrapped.equals(returnTokenFromKey('USDC'))) {
      return new Price(
        returnTokenFromKey('USDC'),
        returnTokenFromKey('USDC'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('USDT'))) {
      return new Price(
        returnTokenFromKey('USDT'),
        returnTokenFromKey('USDT'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('DAI'))) {
      return new Price(
        returnTokenFromKey('DAI'),
        returnTokenFromKey('DAI'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('FRAX'))) {
      return new Price(
        returnTokenFromKey('FRAX'),
        returnTokenFromKey('FRAX'),
        '1',
        '1',
      );
    }
    if (wrapped.equals(returnTokenFromKey('MI'))) {
      return new Price(
        returnTokenFromKey('MI'),
        returnTokenFromKey('MI'),
        '1',
        '1',
      );
    }

    const ethPairETHAmount = ethPair?.reserveOf(WETH[chainId]);
    const ethPairETHUSDCValue: JSBI =
      ethPairETHAmount && usdcEthPair
        ? usdcEthPair.priceOf(WETH[chainId]).quote(ethPairETHAmount).raw
        : JSBI.BigInt(0);

    // all other tokens
    // first try the usdc pair
    if (
      usdcPairState === PairState.EXISTS &&
      usdcPair &&
      usdcPair
        .reserveOf(returnTokenFromKey('USDC'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = usdcPair.priceOf(wrapped);
      if (internalWrapped?.equals(returnTokenFromKey('CXETH'))) {
        return new Price(
          returnTokenFromKey('CXETH'),
          returnTokenFromKey('USDC'),
          price.denominator,
          price.numerator,
        );
      }
      return new Price(
        currency,
        returnTokenFromKey('USDC'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      usdtPairState === PairState.EXISTS &&
      usdtPair &&
      usdtPair
        .reserveOf(returnTokenFromKey('USDT'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = usdtPair.priceOf(wrapped);
      return new Price(
        currency,
        returnTokenFromKey('USDT'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      daiPairState === PairState.EXISTS &&
      daiPair &&
      daiPair
        .reserveOf(returnTokenFromKey('DAI'))
        .greaterThan(ethPairETHUSDCValue)
    ) {
      const price = daiPair.priceOf(wrapped);
      return new Price(
        currency,
        returnTokenFromKey('DAI'),
        price.denominator,
        price.numerator,
      );
    }
    if (
      ethPairState === PairState.EXISTS &&
      ethPair &&
      usdcEthPairState === PairState.EXISTS &&
      usdcEthPair
    ) {
      if (
        usdcEthPair.reserveOf(returnTokenFromKey('USDC')).greaterThan('0') &&
        ethPair.reserveOf(WETH[chainId]).greaterThan('1')
      ) {
        const ethUsdcPrice = usdcEthPair.priceOf(returnTokenFromKey('USDC'));
        const currencyEthPrice = ethPair.priceOf(WETH[chainId]);
        const usdcPrice = ethUsdcPrice.multiply(currencyEthPrice).invert();
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          usdcPrice.denominator,
          usdcPrice.numerator,
        );
      }
    }
    if (
      quickPairState === PairState.EXISTS &&
      quickPair &&
      usdcQuickPairState === PairState.EXISTS &&
      usdcQuickPair
    ) {
      if (
        usdcQuickPair.reserveOf(returnTokenFromKey('USDC')).greaterThan('0') &&
        quickPair.reserveOf(returnTokenFromKey('QUICK')).greaterThan('5')
      ) {
        const quickUsdcPrice = usdcQuickPair.priceOf(
          returnTokenFromKey('USDC'),
        );
        const currencyQuickPrice = quickPair.priceOf(
          returnTokenFromKey('QUICK'),
        );
        const usdcPrice = quickUsdcPrice.multiply(currencyQuickPrice).invert();
        return new Price(
          currency,
          returnTokenFromKey('USDC'),
          usdcPrice.denominator,
          usdcPrice.numerator,
        );
      }
    }
    return undefined;
  });
}