diff --git a/.changeset/erc20-max-full-balance.md b/.changeset/erc20-max-full-balance.md new file mode 100644 index 00000000..07043456 --- /dev/null +++ b/.changeset/erc20-max-full-balance.md @@ -0,0 +1,5 @@ +--- +'@relayprotocol/relay-kit-ui': patch +--- + +MAX now uses the full balance for non-native tokens. The execution and gas buffers only apply to native tokens. diff --git a/packages/ui/src/components/common/PercentageButtons.tsx b/packages/ui/src/components/common/PercentageButtons.tsx index 6c589cf5..30b4a86d 100644 --- a/packages/ui/src/components/common/PercentageButtons.tsx +++ b/packages/ui/src/components/common/PercentageButtons.tsx @@ -2,10 +2,7 @@ import { type FC } from 'react' import { Button, Flex } from '../primitives/index.js' import type { ChainVM, RelayChain } from '@relayprotocol/relay-sdk' import type { PublicClient } from 'viem' -import { - MAX_INPUT_BUFFER_BPS, - MIN_INPUT_BUFFER_UNITS -} from '../../constants/maxAmountBuffer.js' +import { getMaxAmount } from '../../utils/maxAmount.js' import { cn } from '../../utils/cn.js' type PercentageButtonsProps = { @@ -36,16 +33,6 @@ export const PercentageButtons: FC = ({ percentages = [20, 50], buttonClassName: customButtonClassName }) => { - const getExecutionBuffer = (amount: bigint) => { - if (amount <= 0n) return 0n - - const bpsBuffer = (amount * MAX_INPUT_BUFFER_BPS) / 10000n - const minimumBuffer = - amount > MIN_INPUT_BUFFER_UNITS ? MIN_INPUT_BUFFER_UNITS : amount - - return bpsBuffer > minimumBuffer ? bpsBuffer : minimumBuffer - } - const isMobile = variant === 'mobile' const defaultButtonClassName = cn( @@ -70,7 +57,6 @@ export const PercentageButtons: FC = ({ const handleMaxClick = async () => { if (!balance || !fromChain) return - const executionBufferAmount = getExecutionBuffer(balance) const supportsNativeGasBuffer = fromChain.vmType === 'evm' || fromChain.vmType === 'svm' @@ -84,9 +70,11 @@ export const PercentageButtons: FC = ({ ) } - const totalBufferAmount = executionBufferAmount + feeBufferAmount - const finalMaxAmount = - balance > totalBufferAmount ? balance - totalBufferAmount : 0n + const finalMaxAmount = getMaxAmount( + balance, + !!isFromNative, + feeBufferAmount + ) onPercentageClick( finalMaxAmount, diff --git a/packages/ui/src/components/widgets/SwapWidgetRenderer.tsx b/packages/ui/src/components/widgets/SwapWidgetRenderer.tsx index 9cbf612b..714c8d2f 100644 --- a/packages/ui/src/components/widgets/SwapWidgetRenderer.tsx +++ b/packages/ui/src/components/widgets/SwapWidgetRenderer.tsx @@ -470,7 +470,11 @@ const SwapWidgetRenderer: FC = ({ } ) - const isFromNative = fromToken?.address === fromChain?.currency?.address + const isFromNative = addressesEqual( + fromChain?.vmType ?? 'evm', + fromToken?.address, + fromChain?.currency?.address + ) const explicitDeposit = useExplicitDeposit( wallet, diff --git a/packages/ui/src/utils/maxAmount.ts b/packages/ui/src/utils/maxAmount.ts new file mode 100644 index 00000000..e654bcbb --- /dev/null +++ b/packages/ui/src/utils/maxAmount.ts @@ -0,0 +1,35 @@ +import { + MAX_INPUT_BUFFER_BPS, + MIN_INPUT_BUFFER_UNITS +} from '../constants/maxAmountBuffer.js' + +/** + * Headroom subtracted from a native balance on MAX to avoid exact-balance + * execution edge cases. + */ +export const getExecutionBuffer = (amount: bigint): bigint => { + if (amount <= 0n) return 0n + + const bpsBuffer = (amount * MAX_INPUT_BUFFER_BPS) / 10000n + const minimumBuffer = + amount > MIN_INPUT_BUFFER_UNITS ? MIN_INPUT_BUFFER_UNITS : amount + + return bpsBuffer > minimumBuffer ? bpsBuffer : minimumBuffer +} + +/** + * Returns the amount to populate when MAX is clicked. Native tokens keep an + * execution buffer plus the gas fee buffer; other tokens use the full balance + * since gas is paid in the native token. + */ +export const getMaxAmount = ( + balance: bigint, + isFromNative: boolean, + feeBufferAmount: bigint = 0n +): bigint => { + if (balance <= 0n) return 0n + if (!isFromNative) return balance + + const totalBufferAmount = getExecutionBuffer(balance) + feeBufferAmount + return balance > totalBufferAmount ? balance - totalBufferAmount : 0n +}