import { formatUnits } from '@lifi/sdk' import { useAccount } from '@lifi/wallet-management' import { type JSX, memo } from 'react' import { useTranslation } from 'react-i18next' import { useAvailableChains } from '../../hooks/useAvailableChains.js' import { useGasRecommendation } from '../../hooks/useGasRecommendation.js' import { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js' import { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js' import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js' import type { FormTypeProps } from '../../stores/form/types.js' import { FormKeyHelper } from '../../stores/form/types.js' import { useFieldActions } from '../../stores/form/useFieldActions.js' import { useFieldValues } from '../../stores/form/useFieldValues.js' import type { DisabledUIConfig } from '../../types/widget.js' import { Chip, ChipContainer } from './PercentageChips.style.js' export const PercentageChips: React.NamedExoticComponent = memo( ({ formType }: FormTypeProps): JSX.Element | null => { const { t } = useTranslation() const { getChainById } = useAvailableChains() const { setFieldValue } = useFieldActions() const { disabledUI, mode } = useWidgetConfig() const { setSendAmount } = useLinkedLimitFields() const amountKey = FormKeyHelper.getAmountKey(formType) const isDisabled = !!disabledUI?.[amountKey as keyof DisabledUIConfig] const [chainId, tokenAddress] = useFieldValues( FormKeyHelper.getChainKey(formType), FormKeyHelper.getTokenKey(formType) ) const chain = getChainById(chainId) const { account } = useAccount({ chainType: chain?.chainType }) const { data } = useGasRecommendation(chainId) const { token } = useTokenAddressBalance(chainId, tokenAddress) const getMaxAmount = (): bigint => { if (!token?.amount) { return 0n } let maxAmount = token.amount if (chain?.nativeToken.address === tokenAddress && data?.recommended) { const recommendedAmount = BigInt(data.recommended.amount) if (token.amount > recommendedAmount) { maxAmount = token.amount - recommendedAmount } } return maxAmount } // In limit mode the send amount must flow through the linked-field // derivation so the receive amount recomputes; otherwise it is a plain // form-field write. const applyAmount = (value: string): void => { if (mode === 'limit') { setSendAmount(value) } else { setFieldValue(amountKey, value, { isTouched: true }) } } const handlePercentage = (percentage: number): void => { const maxAmount = getMaxAmount() if (maxAmount && token?.decimals) { const percentageAmount = (maxAmount * BigInt(percentage)) / 100n applyAmount(formatUnits(percentageAmount, token.decimals)) } } const handleMax = (): void => { const maxAmount = getMaxAmount() if (maxAmount && token?.decimals) { applyAmount(formatUnits(maxAmount, token.decimals)) } } if (formType !== 'from' || isDisabled || !token || !account?.isConnected) { return null } return ( handlePercentage(25)}> 25% handlePercentage(50)}> 50% handlePercentage(75)}> 75% {t('button.max')} ) } )