UNPKG

@reservoir0x/relay-kit-ui

Version:

Relay is the Fastest and Cheapest Way to Bridge and Transact Across Chains.

643 lines (642 loc) 76.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const index_js_1 = require("../../primitives/index.js"); const react_1 = require("react"); const index_js_2 = require("../../../hooks/index.js"); const viem_1 = require("viem"); const wagmi_1 = require("wagmi"); const numbers_js_1 = require("../../../utils/numbers.js"); const AmountInput_js_1 = tslib_1.__importDefault(require("../../common/AmountInput.js")); const react_fontawesome_1 = require("@fortawesome/react-fontawesome"); const index_js_3 = require("../../../icons/index.js"); const nativeMaxAmount_js_1 = require("../../../utils/nativeMaxAmount.js"); const WidgetErrorWell_js_1 = require("../WidgetErrorWell.js"); const BalanceDisplay_js_1 = require("../../common/BalanceDisplay.js"); const events_js_1 = require("../../../constants/events.js"); const SwapWidgetRenderer_js_1 = tslib_1.__importDefault(require("../SwapWidgetRenderer.js")); const WidgetContainer_js_1 = tslib_1.__importDefault(require("../WidgetContainer.js")); const SwapButton_js_1 = tslib_1.__importDefault(require("../SwapButton.js")); const TokenSelectorContainer_js_1 = tslib_1.__importDefault(require("../TokenSelectorContainer.js")); const FeeBreakdown_js_1 = tslib_1.__importDefault(require("../FeeBreakdown.js")); const free_solid_svg_icons_1 = require("@fortawesome/free-solid-svg-icons"); const TokenTrigger_js_1 = require("../../common/TokenSelector/triggers/TokenTrigger.js"); const MultiWalletDropdown_js_1 = require("../../common/MultiWalletDropdown.js"); const address_js_1 = require("../../../utils/address.js"); const relay_sdk_1 = require("@reservoir0x/relay-sdk"); const SwapRouteSelector_js_1 = tslib_1.__importDefault(require("../SwapRouteSelector.js")); const RelayKitProvider_js_1 = require("../../../providers/RelayKitProvider.js"); const tokens_js_1 = require("../../../utils/tokens.js"); const tokenSelector_js_1 = require("../../../utils/tokenSelector.js"); const TokenSelector_js_1 = tslib_1.__importDefault(require("../../common/TokenSelector/TokenSelector.js")); const UnverifiedTokenModal_js_1 = require("../../common/UnverifiedTokenModal.js"); const localStorage_js_1 = require("../../../utils/localStorage.js"); const GasTopUpSection_js_1 = tslib_1.__importDefault(require("./GasTopUpSection.js")); const quote_js_1 = require("../../../utils/quote.js"); const SwapWidget = ({ fromToken, setFromToken, toToken, setToToken, defaultToAddress, defaultAmount, defaultTradeType, slippageTolerance, lockToToken = false, lockFromToken = false, lockChainId, singleChainMode = false, wallet, multiWalletSupportEnabled = false, linkedWallets, supportedWalletVMs, disableInputAutoFocus = false, popularChainIds, disablePasteWalletAddressOption, onSetPrimaryWallet, onLinkNewWallet, onFromTokenChange, onToTokenChange, onConnectWallet, onAnalyticEvent: _onAnalyticEvent, onSwapSuccess, onSwapValidating, onSwapError }) => { const onAnalyticEvent = (0, react_1.useCallback)((eventName, data) => { try { _onAnalyticEvent?.(eventName, data); } catch (e) { console.error('Error in onAnalyticEvent', eventName, data, e); } }, [_onAnalyticEvent]); const relayClient = (0, index_js_2.useRelayClient)(); const providerOptionsContext = (0, react_1.useContext)(RelayKitProvider_js_1.ProviderOptionsContext); const connectorKeyOverrides = providerOptionsContext.vmConnectorKeyOverrides; const [transactionModalOpen, setTransactionModalOpen] = (0, react_1.useState)(false); const [depositAddressModalOpen, setDepositAddressModalOpen] = (0, react_1.useState)(false); const [addressModalOpen, setAddressModalOpen] = (0, react_1.useState)(false); const [pendingSuccessFlush, setPendingSuccessFlush] = (0, react_1.useState)(false); const [unverifiedTokens, setUnverifiedTokens] = (0, react_1.useState)([]); const [isUsdInputMode, setIsUsdInputMode] = (0, react_1.useState)(false); const [usdInputValue, setUsdInputValue] = (0, react_1.useState)(''); const [usdOutputValue, setUsdOutputValue] = (0, react_1.useState)(''); const [tokenInputCache, setTokenInputCache] = (0, react_1.useState)(''); const hasLockedToken = lockFromToken || lockToToken; const isSingleChainLocked = singleChainMode && lockChainId !== undefined; (0, react_1.useEffect)(() => { if (fromToken && 'verified' in fromToken && !fromToken.verified) { const isAlreadyAccepted = (0, localStorage_js_1.alreadyAcceptedToken)(fromToken); if (!isAlreadyAccepted) { unverifiedTokens.push({ token: fromToken, context: 'from' }); setFromToken?.(undefined); } } if (toToken && 'verified' in toToken && !toToken.verified) { const isAlreadyAccepted = (0, localStorage_js_1.alreadyAcceptedToken)(toToken); if (!isAlreadyAccepted) { unverifiedTokens.push({ token: toToken, context: 'to' }); setToToken?.(undefined); } } }, [fromToken, toToken]); return ((0, jsx_runtime_1.jsx)(SwapWidgetRenderer_js_1.default, { context: "Swap", transactionModalOpen: transactionModalOpen, setTransactionModalOpen: setTransactionModalOpen, depositAddressModalOpen: depositAddressModalOpen, defaultAmount: defaultAmount, defaultToAddress: defaultToAddress, defaultTradeType: defaultTradeType, toToken: toToken, setToToken: setToToken, fromToken: fromToken, setFromToken: setFromToken, slippageTolerance: slippageTolerance, wallet: wallet, linkedWallets: linkedWallets, multiWalletSupportEnabled: multiWalletSupportEnabled, onSwapError: onSwapError, onAnalyticEvent: onAnalyticEvent, supportedWalletVMs: supportedWalletVMs, children: ({ quote, steps, swap, setSteps, feeBreakdown, fromToken, setFromToken, toToken, setToToken, error, toDisplayName, address, recipient, customToAddress, setCustomToAddress, tradeType, setTradeType, isSameCurrencySameRecipientSwap, debouncedInputAmountValue, debouncedAmountInputControls, setAmountInputValue, amountInputValue, amountOutputValue, debouncedOutputAmountValue, debouncedAmountOutputControls, setAmountOutputValue, toBalance, toBalancePending, isLoadingToBalance, isFetchingQuote, isLoadingFromBalance, fromBalance, fromBalancePending, highRelayerServiceFee, relayerFeeProportion, hasInsufficientBalance, isInsufficientLiquidityError, isCapacityExceededError, isCouldNotExecuteError, ctaCopy, isFromNative, timeEstimate, isSvmSwap, isBvmSwap, isValidFromAddress, isValidToAddress, supportsExternalLiquidity, useExternalLiquidity, slippageTolerance, canonicalTimeEstimate, fromChainWalletVMSupported, toChainWalletVMSupported, isRecipientLinked, swapError, recipientWalletSupportsChain, gasTopUpEnabled, setGasTopUpEnabled, gasTopUpRequired, gasTopUpAmount, gasTopUpAmountUsd, linkedWallet, quoteParameters, setSwapError, setUseExternalLiquidity, invalidateBalanceQueries, invalidateQuoteQuery, quoteInProgress, setQuoteInProgress, abortController, fromTokenPriceData, toTokenPriceData, isLoadingFromTokenPrice, isLoadingToTokenPrice }) => { const inputAmountUsd = (0, react_1.useMemo)(() => { return (0, quote_js_1.calculateUsdValue)(fromTokenPriceData?.price, amountInputValue); }, [fromTokenPriceData, amountInputValue]); const outputAmountUsd = (0, react_1.useMemo)(() => { return (0, quote_js_1.calculateUsdValue)(toTokenPriceData?.price, amountOutputValue); }, [toTokenPriceData, amountOutputValue]); const handleMaxAmountClicked = async (amount, percent, bufferAmount) => { if (fromToken) { const formattedAmount = (0, viem_1.formatUnits)(amount, fromToken?.decimals); setAmountInputValue(formattedAmount); setTradeType('EXACT_INPUT'); debouncedAmountOutputControls.cancel(); debouncedAmountInputControls.flush(); onAnalyticEvent?.(events_js_1.EventNames.MAX_AMOUNT_CLICKED, { percent: percent, bufferAmount: bufferAmount ? bufferAmount.toString() : '0', chainType: fromChain?.vmType }); if (isUsdInputMode && conversionRate) { const numericTokenAmount = Number(formattedAmount); if (!isNaN(numericTokenAmount)) { const usdEquivalent = numericTokenAmount * conversionRate; setUsdInputValue(usdEquivalent.toFixed(2)); } } } }; const handleSetFromToken = (token) => { if (!token) { setFromToken(undefined); onFromTokenChange?.(undefined); return; } let _token = token; const newFromChain = relayClient?.chains.find((chain) => token?.chainId == chain.id); if (newFromChain?.vmType && !supportedWalletVMs.includes(newFromChain?.vmType)) { setTradeType('EXACT_INPUT'); const _toToken = (0, tokens_js_1.findBridgableToken)(toChain, toToken); if (_toToken && _toToken?.address != toToken?.address) { handleSetToToken(_toToken); } const _fromToken = (0, tokens_js_1.findBridgableToken)(newFromChain, _token); if (_fromToken && _fromToken.address != _token?.address) { _token = _fromToken; } } setFromToken(_token); onFromTokenChange?.(_token); }; const handleSetToToken = (token) => { if (!token) { setToToken(undefined); onToTokenChange?.(undefined); return; } let _token = token; if (!fromChainWalletVMSupported) { const newToChain = relayClient?.chains.find((chain) => token?.chainId == chain.id); if (newToChain) { const _toToken = (0, tokens_js_1.findBridgableToken)(newToChain, _token); if (_toToken && _toToken.address != _token?.address) { _token = _toToken; } } } setToToken(_token); onToTokenChange?.(_token); }; const fromChain = relayClient?.chains?.find((chain) => chain.id === fromToken?.chainId); const toChain = relayClient?.chains?.find((chain) => chain.id === toToken?.chainId); const publicClient = (0, wagmi_1.usePublicClient)({ chainId: fromChain?.id }); (0, react_1.useEffect)(() => { if (multiWalletSupportEnabled && fromChain && address && linkedWallets && !isValidFromAddress) { const supportedAddress = (0, address_js_1.findSupportedWallet)(fromChain, address, linkedWallets, connectorKeyOverrides); if (supportedAddress) { onSetPrimaryWallet?.(supportedAddress); } } if (multiWalletSupportEnabled && toChain && recipient && linkedWallets && !isValidToAddress) { const supportedAddress = (0, address_js_1.findSupportedWallet)(toChain, recipient, linkedWallets, connectorKeyOverrides); if (supportedAddress) { setCustomToAddress(supportedAddress); } else { setCustomToAddress(undefined); } } }, [ multiWalletSupportEnabled, fromChain?.id, toChain?.id, address, linkedWallets, onSetPrimaryWallet, isValidFromAddress, isValidToAddress, connectorKeyOverrides ]); (0, react_1.useEffect)(() => { if (disablePasteWalletAddressOption && customToAddress) { setCustomToAddress(undefined); } }, [disablePasteWalletAddressOption]); const promptSwitchRoute = (isCapacityExceededError || isCouldNotExecuteError) && supportsExternalLiquidity && !isSingleChainLocked; const isAutoSlippage = slippageTolerance === undefined; const isHighPriceImpact = Number(quote?.details?.totalImpact?.percent) < -3.5; const totalImpactUsd = quote?.details?.totalImpact?.usd; const showHighPriceImpactWarning = Boolean(isHighPriceImpact && totalImpactUsd && Number(totalImpactUsd) <= -10); const conversionRate = (0, react_1.useMemo)(() => { if (isUsdInputMode) { if (fromTokenPriceData?.price && fromTokenPriceData.price > 0) { return fromTokenPriceData.price; } else { return null; } } else { if (amountInputValue && Number(amountInputValue) > 0 && quote?.details?.currencyIn?.amountUsd) { const tokenVal = Number(amountInputValue); const usdVal = Number(quote.details.currencyIn.amountUsd); if (tokenVal > 0 && usdVal > 0) { const rate = usdVal / tokenVal; return rate; } else { return null; } } else { return null; } } }, [ isUsdInputMode, fromTokenPriceData?.price, quote?.details?.currencyIn?.amountUsd, amountInputValue ]); const toggleInputMode = () => { if (!isUsdInputMode) { let newUsdInputValue = ''; let newUsdOutputValue = ''; if (quote?.details?.currencyIn?.amountUsd && Number(quote.details.currencyIn.amountUsd) > 0) { newUsdInputValue = String(Number(quote.details.currencyIn.amountUsd)); } else if (inputAmountUsd && inputAmountUsd > 0) { newUsdInputValue = inputAmountUsd.toFixed(2); } else if (amountInputValue && Number(amountInputValue) > 0 && conversionRate && conversionRate > 0) { newUsdInputValue = (Number(amountInputValue) * conversionRate).toFixed(2); } if (quote?.details?.currencyOut?.amountUsd && Number(quote.details.currencyOut.amountUsd) > 0) { newUsdOutputValue = String(Number(quote.details.currencyOut.amountUsd)); } else if (outputAmountUsd && outputAmountUsd > 0) { newUsdOutputValue = outputAmountUsd.toFixed(2); } else if (amountOutputValue && Number(amountOutputValue) > 0 && toTokenPriceData?.price && toTokenPriceData.price > 0) { newUsdOutputValue = (Number(amountOutputValue) * toTokenPriceData.price).toFixed(2); } setTokenInputCache(amountInputValue); setUsdInputValue(newUsdInputValue); setUsdOutputValue(newUsdOutputValue); setIsUsdInputMode(true); if (tradeType !== 'EXPECTED_OUTPUT' || !newUsdOutputValue) { setTradeType('EXACT_INPUT'); } } else { if (!usdInputValue && tokenInputCache) { setAmountInputValue(tokenInputCache); } setUsdInputValue(''); setUsdOutputValue(''); setIsUsdInputMode(false); } }; (0, react_1.useEffect)(() => { if (isUsdInputMode) { if (conversionRate && conversionRate > 0 && usdInputValue) { const usdValue = Number(usdInputValue); if (!isNaN(usdValue) && usdValue > 0) { const tokenEquivalent = (usdValue / conversionRate).toFixed(fromToken?.decimals ?? 8); setAmountInputValue(tokenEquivalent); } } else if (usdInputValue === '' || Number(usdInputValue) === 0) { setAmountInputValue(''); } } }, [ isUsdInputMode, usdInputValue, conversionRate, setAmountInputValue, fromToken?.decimals ]); (0, react_1.useEffect)(() => { if (isUsdInputMode && tradeType === 'EXPECTED_OUTPUT') { if (toTokenPriceData?.price && toTokenPriceData.price > 0 && usdOutputValue) { const usdValue = Number(usdOutputValue); if (!isNaN(usdValue) && usdValue > 0) { const tokenEquivalent = (usdValue / toTokenPriceData.price).toFixed(toToken?.decimals ?? 8); setAmountOutputValue(tokenEquivalent); } } else if (usdOutputValue === '' || Number(usdOutputValue) === 0) { setAmountOutputValue(''); } } }, [ isUsdInputMode, tradeType, usdOutputValue, toTokenPriceData?.price, setAmountOutputValue, toToken?.decimals ]); (0, react_1.useEffect)(() => { if (isUsdInputMode) { if (tradeType === 'EXPECTED_OUTPUT') { return; } if (quote?.details?.currencyOut?.amountUsd && !isFetchingQuote) { const quoteUsdValue = Number(quote.details.currencyOut.amountUsd); if (!isNaN(quoteUsdValue) && quoteUsdValue >= 0) { setUsdOutputValue(quoteUsdValue.toFixed(2)); } } else if (toTokenPriceData?.price && toTokenPriceData.price > 0 && amountOutputValue && Number(amountOutputValue) > 0) { const tokenAmount = Number(amountOutputValue); const usdEquivalent = tokenAmount * toTokenPriceData.price; if (!isNaN(usdEquivalent) && usdEquivalent >= 0) { setUsdOutputValue(usdEquivalent.toFixed(2)); } } else if (!amountOutputValue || Number(amountOutputValue) === 0) { setUsdOutputValue(''); } } }, [ isUsdInputMode, tradeType, quote?.details?.currencyOut?.amountUsd, isFetchingQuote, toTokenPriceData?.price, amountOutputValue ]); (0, react_1.useEffect)(() => { if (isUsdInputMode && tradeType === 'EXPECTED_OUTPUT') { if (quote?.details?.currencyIn?.amountUsd && !isFetchingQuote) { const quoteUsdValue = Number(quote.details.currencyIn.amountUsd); if (!isNaN(quoteUsdValue) && quoteUsdValue >= 0) { setUsdInputValue(quoteUsdValue.toFixed(2)); } } else if (!amountInputValue || Number(amountInputValue) === 0) { setUsdInputValue(''); } } }, [ isUsdInputMode, tradeType, quote?.details?.currencyIn?.amountUsd, isFetchingQuote, amountInputValue ]); const recipientLinkedWallet = linkedWallets?.find((wallet) => wallet.address === recipient); return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(WidgetContainer_js_1.default, { steps: steps, setSteps: setSteps, quoteInProgress: quoteInProgress, setQuoteInProgress: setQuoteInProgress, transactionModalOpen: transactionModalOpen, setTransactionModalOpen: setTransactionModalOpen, depositAddressModalOpen: depositAddressModalOpen, setDepositAddressModalOpen: setDepositAddressModalOpen, addressModalOpen: addressModalOpen, setAddressModalOpen: setAddressModalOpen, fromToken: fromToken, fromChain: fromChain, toToken: toToken, toChain: toChain, address: address, recipient: recipient, amountInputValue: amountInputValue, amountOutputValue: amountOutputValue, debouncedInputAmountValue: debouncedInputAmountValue, debouncedOutputAmountValue: debouncedOutputAmountValue, tradeType: tradeType, onTransactionModalOpenChange: (open) => { if (!open) { if (pendingSuccessFlush) { setPendingSuccessFlush(false); } else if (steps) { invalidateQuoteQuery(); } if (abortController) { abortController.abort(); } setSwapError(null); setSteps(null); setQuoteInProgress(null); } else if (pendingSuccessFlush) { setPendingSuccessFlush(false); } }, onDepositAddressModalOpenChange: (open) => { if (!open) { setSwapError(null); if (pendingSuccessFlush) { setPendingSuccessFlush(false); } else { invalidateQuoteQuery(); } } else if (pendingSuccessFlush) { setPendingSuccessFlush(false); } }, useExternalLiquidity: useExternalLiquidity, slippageTolerance: slippageTolerance, swapError: swapError, setSwapError: setSwapError, onSwapSuccess: (data) => { setPendingSuccessFlush(true); setGasTopUpEnabled(true); setAmountInputValue(''); setAmountOutputValue(''); onSwapSuccess?.(data); }, onSwapValidating: onSwapValidating, onAnalyticEvent: onAnalyticEvent, invalidateBalanceQueries: invalidateBalanceQueries, invalidateQuoteQuery: invalidateQuoteQuery, customToAddress: customToAddress, setCustomToAddress: setCustomToAddress, timeEstimate: timeEstimate, wallet: wallet, linkedWallets: linkedWallets, multiWalletSupportEnabled: multiWalletSupportEnabled, children: () => { return ((0, jsx_runtime_1.jsxs)(index_js_1.Flex, { direction: "column", css: { width: '100%', overflow: 'hidden', border: 'widget-border', minWidth: 300, maxWidth: 408 }, children: [(0, jsx_runtime_1.jsxs)(TokenSelectorContainer_js_1.default, { css: { backgroundColor: 'widget-background' }, id: 'from-token-section', children: [(0, jsx_runtime_1.jsxs)(index_js_1.Flex, { align: "center", justify: "between", css: { gap: '2', width: '100%' }, children: [(0, jsx_runtime_1.jsx)(index_js_1.Text, { style: "subtitle2", color: "subtle", children: "Sell" }), multiWalletSupportEnabled === true && fromChainWalletVMSupported ? ((0, jsx_runtime_1.jsx)(MultiWalletDropdown_js_1.MultiWalletDropdown, { context: "origin", selectedWalletAddress: address, disablePasteWalletAddressOption: disablePasteWalletAddressOption, onSelect: (wallet) => onSetPrimaryWallet?.(wallet.address), chain: fromChain, onLinkNewWallet: () => { if (!address && fromChainWalletVMSupported) { onConnectWallet?.(); } else { onLinkNewWallet?.({ chain: fromChain, direction: 'from' })?.then((wallet) => { onSetPrimaryWallet?.(wallet.address); }); } }, setAddressModalOpen: setAddressModalOpen, wallets: linkedWallets, onAnalyticEvent: onAnalyticEvent })) : null] }), (0, jsx_runtime_1.jsxs)(index_js_1.Flex, { align: "center", justify: "between", css: { gap: '4', width: '100%' }, children: [(0, jsx_runtime_1.jsx)(AmountInput_js_1.default, { autoFocus: !disableInputAutoFocus, prefixSymbol: isUsdInputMode ? '$' : undefined, value: isUsdInputMode ? usdInputValue : tradeType === 'EXACT_INPUT' ? amountInputValue : amountInputValue ? (0, numbers_js_1.formatFixedLength)(amountInputValue, 8) : amountInputValue, setValue: (e) => { if (isUsdInputMode) { setUsdInputValue(e); setTradeType('EXACT_INPUT'); setTokenInputCache(''); if (Number(e) === 0) { setAmountOutputValue(''); setUsdOutputValue(''); debouncedAmountInputControls.flush(); } } else { setAmountInputValue(e); setTradeType('EXACT_INPUT'); if (Number(e) === 0) { setAmountOutputValue(''); debouncedAmountInputControls.flush(); } } }, onFocus: () => { onAnalyticEvent?.(events_js_1.EventNames.SWAP_INPUT_FOCUSED); }, css: { fontWeight: '700', fontSize: 32, lineHeight: '36px', py: 0, color: isFetchingQuote && tradeType === 'EXPECTED_OUTPUT' ? 'text-subtle' : 'input-color', _placeholder: { color: isFetchingQuote && tradeType === 'EXPECTED_OUTPUT' ? 'text-subtle' : 'input-color' } } }), (0, jsx_runtime_1.jsx)(TokenSelector_js_1.default, { address: address, isValidAddress: isValidFromAddress, token: fromToken, onAnalyticEvent: onAnalyticEvent, fromChainWalletVMSupported: fromChainWalletVMSupported, supportedWalletVMs: supportedWalletVMs, setToken: (token) => { if (token.address === toToken?.address && token.chainId === toToken?.chainId && address === recipient && (!lockToToken || !fromToken)) { handleSetFromToken(toToken); handleSetToToken(fromToken); } else { handleSetFromToken(token); } }, context: "from", multiWalletSupportEnabled: multiWalletSupportEnabled, lockedChainIds: isSingleChainLocked ? [lockChainId] : (0, tokenSelector_js_1.isChainLocked)(fromToken?.chainId, lockChainId, toToken?.chainId, lockFromToken) && fromToken?.chainId ? [fromToken.chainId] : undefined, chainIdsFilter: !fromChainWalletVMSupported && toToken ? [toToken.chainId] : undefined, popularChainIds: popularChainIds, trigger: (0, jsx_runtime_1.jsx)("div", { style: { width: 'max-content' }, children: (0, jsx_runtime_1.jsx)(TokenTrigger_js_1.TokenTrigger, { token: fromToken, locked: lockFromToken, isSingleChainLocked: isSingleChainLocked, address: address }) }) })] }), (0, jsx_runtime_1.jsxs)(index_js_1.Flex, { align: "center", justify: "between", css: { gap: '3', width: '100%' }, children: [(0, jsx_runtime_1.jsxs)(index_js_1.Flex, { align: "center", css: { gap: '4px', _hover: { cursor: 'pointer' } }, onClick: () => { toggleInputMode(); }, children: [(0, jsx_runtime_1.jsx)(index_js_1.Text, { style: "subtitle3", color: "subtleSecondary", css: { minHeight: 18, display: 'flex', alignItems: 'center' }, children: isUsdInputMode ? (fromToken ? (usdInputValue && Number(usdInputValue) > 0 ? (amountInputValue && conversionRate && !isLoadingFromTokenPrice ? (`${(0, numbers_js_1.formatNumber)(amountInputValue, 4, false)} ${fromToken.symbol}`) : ((0, jsx_runtime_1.jsx)(index_js_1.Box, { css: { width: 45, height: 12, backgroundColor: 'gray7', borderRadius: 'widget-border-radius' } }))) : (`0 ${fromToken.symbol}`)) : null) : quote?.details?.currencyIn?.amountUsd && !isFetchingQuote ? ((0, numbers_js_1.formatDollar)(Number(quote.details.currencyIn.amountUsd))) : isLoadingFromTokenPrice && amountInputValue && Number(amountInputValue) > 0 ? ((0, jsx_runtime_1.jsx)(index_js_1.Box, { css: { width: 45, height: 12, backgroundColor: 'gray7', borderRadius: 'widget-border-radius' } })) : inputAmountUsd && inputAmountUsd > 0 && fromTokenPriceData?.price && fromTokenPriceData.price > 0 ? ((0, numbers_js_1.formatDollar)(inputAmountUsd)) : ('$0.00') }), (0, jsx_runtime_1.jsx)(index_js_1.Button, { "aria-label": "Switch Input Mode", size: "none", color: "ghost", css: { color: 'gray11', alignSelf: 'center', justifyContent: 'center', width: '20px', height: '20px', borderRadius: '100px', padding: '4px', backgroundColor: 'gray3' }, onClick: toggleInputMode, children: (0, jsx_runtime_1.jsx)(index_js_3.SwitchIcon, { width: 16, height: 10 }) })] }), (0, jsx_runtime_1.jsxs)(index_js_1.Flex, { align: "center", css: { gap: '3', marginLeft: 'auto', height: 23 }, children: [fromToken ? ((0, jsx_runtime_1.jsx)(BalanceDisplay_js_1.BalanceDisplay, { isLoading: isLoadingFromBalance, balance: fromBalance, decimals: fromToken?.decimals, symbol: fromToken?.symbol, hasInsufficientBalance: hasInsufficientBalance, displaySymbol: false, isConnected: !(0, relay_sdk_1.isDeadAddress)(address) && address !== relay_sdk_1.tronDeadAddress && address !== undefined, pending: fromBalancePending })) : ((0, jsx_runtime_1.jsx)(index_js_1.Flex, { css: { height: 18 } })), fromBalance && (fromChain?.vmType === 'evm' || fromChain?.vmType === 'svm') ? ((0, jsx_runtime_1.jsxs)(index_js_1.Flex, { css: { gap: '1' }, children: [(0, jsx_runtime_1.jsx)(index_js_1.Button, { "aria-label": "20%", css: { fontSize: 12, fontWeight: '500', px: '1', py: '1', minHeight: '23px', lineHeight: '100%', backgroundColor: 'widget-selector-background', border: 'none', _hover: { backgroundColor: 'widget-selector-hover-background' } }, color: "white", onClick: () => { const percentageBuffer = (fromBalance * 20n) / 100n; handleMaxAmountClicked(percentageBuffer, '20%'); }, children: "20%" }), (0, jsx_runtime_1.jsx)(index_js_1.Button, { "aria-label": "50%", css: { fontSize: 12, fontWeight: '500', px: '1', py: '1', minHeight: '23px', lineHeight: '100%', backgroundColor: 'widget-selector-background', border: 'none', _hover: { backgroundColor: 'widget-selector-hover-background' } }, color: "white", onClick: () => { const percentageBuffer = (fromBalance * 50n) / 100n; handleMaxAmountClicked(percentageBuffer, '50%'); }, children: "50%" }), (0, jsx_runtime_1.jsx)(index_js_1.Button, { "aria-label": "MAX", css: { fontSize: 12, fontWeight: '500', px: '1', py: '1', minHeight: '23px', lineHeight: '100%', backgroundColor: 'widget-selector-background', border: 'none', _hover: { backgroundColor: 'widget-selector-hover-background' } }, color: "white", onMouseEnter: () => { if (fromChain?.vmType === 'evm' && publicClient && fromBalance) { (0, nativeMaxAmount_js_1.getFeeBufferAmount)(fromChain.vmType, fromChain.id, fromBalance, publicClient); } else if (fromChain?.vmType === 'svm' && fromChain.id) { (0, nativeMaxAmount_js_1.getFeeBufferAmount)(fromChain.vmType, fromChain.id, 0n, null); } }, onClick: async () => { if (!fromBalance || !fromToken || !fromChain) return; let feeBufferAmount = 0n; if (isFromNative) { feeBufferAmount = await (0, nativeMaxAmount_js_1.getFeeBufferAmount)(fromChain.vmType, fromChain.id, fromBalance, publicClient ?? null); } const finalMaxAmount = isFromNative && feeBufferAmount > 0n ? fromBalance > feeBufferAmount ? fromBalance - feeBufferAmount : 0n : fromBalance; handleMaxAmountClicked(finalMaxAmount, 'max', isFromNative ? feeBufferAmount : 0n); }, children: "MAX" })] })) : null] })] })] }), (0, jsx_runtime_1.jsx)(index_js_1.Box, { css: { position: 'relative', my: -13, mx: 'auto', height: 32, width: 32 }, children: hasLockedToken || ((isSvmSwap || isBvmSwap) && !multiWalletSupportEnabled) ? null : ((0, jsx_runtime_1.jsx)(index_js_1.Button, { "aria-label": "Swap Tokens Direction", size: "none", color: "white", css: { mt: '4px', color: 'gray9', alignSelf: 'center', justifyContent: 'center', width: '100%', height: '100%', '--borderWidth': 'borders.widget-swap-currency-button-border-width', '--borderColor': 'colors.widget-swap-currency-button-border-color', border: `var(--borderWidth) solid var(--borderColor)`, zIndex: 10, borderRadius: 'widget-swap-currency-button-border-radius' }, onClick: () => { if (fromToken || toToken) { if (isUsdInputMode) { handleSetFromToken(toToken); handleSetToToken(fromToken); const tempUsdInput = usdInputValue; setUsdInputValue(usdOutputValue); setUsdOutputValue(tempUsdInput); setTradeType('EXACT_INPUT'); debouncedAmountInputControls.flush(); debouncedAmountOutputControls.flush(); } else { if (tradeType === 'EXACT_INPUT') { setTradeType('EXPECTED_OUTPUT'); setAmountInputValue(''); setAmountOutputValue(amountInputValue); } else { setTradeType('EXACT_INPUT'); setAmountOutputValue(''); setAmountInputValue(amountOutputValue); } handleSetFromToken(toToken); handleSetToToken(fromToken); debouncedAmountInputControls.flush(); debouncedAmountOutputControls.flush(); } } }, children: (0, jsx_runtime_1.jsx)(react_fontawesome_1.FontAwesomeIcon, { icon: free_solid_svg_icons_1.faArrowDown, width: 16, height: 16 }) })) }), (0, jsx_runtime_1.jsxs)(TokenSelectorContainer_js_1.default, { css: { backgroundColor: 'widget-background', mb: 'widget-card-section-gutter' }, id: 'to-token-section', children: [(0, jsx_runtime_1.jsxs)(index_js_1.Flex, { css: { width: '100%' }, align: "center", justify: "between", children: [(0, jsx_runtime_1.jsx)(index_js_1.Text, { style: "subtitle2", color: "subtle", children: "Buy" }), multiWalletSupportEnabled && toChainWalletVMSupported ? ((0, jsx_runtime_1.jsx)(MultiWalletDropdown_js_1.MultiWalletDropdown, { context: "destination", disablePasteWalletAddressOption: disablePasteWalletAddressOption, selectedWalletAddress: recipient, onSelect: (wallet) => {