synapsecns/sanguine

View on GitHub
packages/synapse-interface/components/StateManagedSwap/SwapExchangeRateInfo.tsx

Summary

Maintainability
A
1 hr
Test Coverage
import { useMemo } from 'react'
import Image from 'next/image'
import { useTranslations } from 'next-intl'

import { CHAINS_BY_ID } from '@constants/chains'
import { Token } from '@/utils/types'
import {
  formatBigIntToPercentString,
  formatBigIntToString,
} from '@/utils/bigint/format'

const SwapExchangeRateInfo = ({
  fromAmount,
  toToken,
  exchangeRate,
  toChainId,
}: {
  fromAmount: bigint
  toToken: Token
  exchangeRate: bigint
  toChainId: number
}) => {
  const safeExchangeRate = useMemo(() => exchangeRate ?? 0n, [exchangeRate]) // todo clean
  const safeFromAmount = useMemo(() => fromAmount ?? 0n, [fromAmount]) // todo clean
  const formattedExchangeRate = formatBigIntToString(safeExchangeRate, 18, 5)
  const numExchangeRate = Number(formattedExchangeRate)
  const slippage = safeExchangeRate - 1000000000000000000n
  const formattedPercentSlippage = formatBigIntToPercentString(slippage, 18)
  const underFee = safeExchangeRate === 0n && safeFromAmount != 0n

  const textColor: string = useMemo(() => {
    if (numExchangeRate >= 1) {
      return 'text-green-500'
    } else if (numExchangeRate > 0.975) {
      return 'text-amber-500'
    } else {
      return 'text-red-500'
    }
  }, [numExchangeRate])

  const expectedToChain = useMemo(() => {
    return toChainId && <ChainInfoLabel chainId={toChainId} />
  }, [toChainId])

  return (
    <div className="mt-1 mb-2 text-sm">
      <div className="block p-2 leading-relaxed border rounded border-zinc-300 dark:border-separator">
        <ExpectedPrice
          expectedToChain={expectedToChain}
          safeFromAmount={safeFromAmount}
          formattedExchangeRate={formattedExchangeRate}
          toToken={toToken}
        />
        <Slippage
          safeFromAmount={safeFromAmount}
          underFee={underFee}
          textColor={textColor}
          formattedPercentSlippage={formattedPercentSlippage}
        />
      </div>
    </div>
  )
}

const ExpectedPrice = ({
  expectedToChain,
  safeFromAmount,
  formattedExchangeRate,
  toToken,
}) => {
  const t = useTranslations('Swap')

  return (
    <div className="flex justify-between">
      <div className="flex space-x-2 text-[#88818C]">
        <p>{t('Expected price on')}</p> {expectedToChain}
      </div>
      <span className="text-[#88818C]">
        {safeFromAmount != 0n ? (
          <>
            {formattedExchangeRate}{' '}
            <span className="text-white">{toToken?.symbol}</span>
          </>
        ) : (
          '—'
        )}
      </span>
    </div>
  )
}

const Slippage = ({
  safeFromAmount,
  underFee,
  textColor,
  formattedPercentSlippage,
}) => {
  const t = useTranslations('Swap')
  return (
    <div className="flex justify-between">
      <p className="text-[#88818C] ">{t('Slippage')}</p>
      {safeFromAmount != 0n && !underFee ? (
        <span className={` ${textColor}`}>{formattedPercentSlippage}</span>
      ) : (
        <span className="text-[#88818C]">—</span>
      )}
    </div>
  )
}

const ChainInfoLabel = ({ chainId }: { chainId: number }) => {
  const chain = CHAINS_BY_ID[chainId]

  return chain ? (
    <span className="flex items-center space-x-1">
      <Image
        alt="chain image"
        src={chain.chainImg}
        className="w-4 h-4 rounded-full"
      />
      <span className="text-white">
        {chain.name.length > 10 ? chain.chainSymbol : chain.name}
      </span>
    </span>
  ) : null
}

export default SwapExchangeRateInfo