From 77d84cb2b4e99e022bea195dc64af2c5cbc086be Mon Sep 17 00:00:00 2001 From: Sam Holmes Date: Tue, 11 Nov 2025 12:19:12 -0800 Subject: [PATCH 1/5] Update the `exchangeAmount` type for clarity --- src/components/scenes/RampCreateScene.tsx | 4 +-- src/plugins/ramps/rampPluginTypes.ts | 38 +++++++++++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/components/scenes/RampCreateScene.tsx b/src/components/scenes/RampCreateScene.tsx index 997fb77a68f..59938f7644d 100644 --- a/src/components/scenes/RampCreateScene.tsx +++ b/src/components/scenes/RampCreateScene.tsx @@ -32,8 +32,8 @@ import { import { useWatch } from '../../hooks/useWatch' import { lstrings } from '../../locales/strings' import type { - RampExchangeAmount, RampPlugin, + RampQouteAmount, RampQuote, RampQuoteRequest } from '../../plugins/ramps/rampPluginTypes' @@ -108,7 +108,7 @@ export const RampCreateScene: React.FC = (props: Props) => { // State for trade form const [exchangeAmount, setExchangeAmount] = useState< - RampExchangeAmount | { empty: true } + RampQouteAmount | { empty: true } >({ empty: true }) const [lastUsedInput, setLastUsedInput] = useState<'fiat' | 'crypto' | null>( null diff --git a/src/plugins/ramps/rampPluginTypes.ts b/src/plugins/ramps/rampPluginTypes.ts index ef378c525c4..88a14de1929 100644 --- a/src/plugins/ramps/rampPluginTypes.ts +++ b/src/plugins/ramps/rampPluginTypes.ts @@ -37,24 +37,36 @@ export interface RampSupportResult { supportedAmountTypes?: Array<'fiat' | 'crypto'> } -export type RampExchangeAmount = - | { - /** - * Requests a quote for the maximum amount that the provider supports. - * If a string amount is provided (in units of the amountType), then - * the quote amount must not exceed this amount. - * If `true` is provided then the maximum is the amount that the provider - * supports. - * */ - max: string | true - } - | { amount: string } +export type RampQouteAmount = + | RampQuoteMaxAmount + | RampQuoteMaxLimitAmount + | RampQuoteExactAmount + +interface RampQuoteMaxAmount { + /** + * Requests a quote for the maximum amount that the provider supports. + * */ + max: true +} +interface RampQuoteMaxLimitAmount { + /** + * Requests a quote for the maximum amount that the provider supports up to + * a specified limit. + */ + max: string +} +interface RampQuoteExactAmount { + /** + * Requests a quote for the exact amount provided. + * */ + amount: string +} export interface RampQuoteRequest { wallet: EdgeCurrencyWallet tokenId: EdgeTokenId displayCurrencyCode: string - exchangeAmount: RampExchangeAmount + exchangeAmount: RampQouteAmount fiatCurrencyCode: string amountType: 'fiat' | 'crypto' direction: 'buy' | 'sell' From d429fc7ebfea89484ae373fc72f071845e256ab9 Mon Sep 17 00:00:00 2001 From: Sam Holmes Date: Tue, 11 Nov 2025 12:22:04 -0800 Subject: [PATCH 2/5] Rename `exchangeAmount` In RampQuoteRequest This is a more appropriate name for this field because of it's no longer simply an exchange amount. --- src/components/scenes/RampCreateScene.tsx | 86 +++++++++---------- src/plugins/ramps/banxa/banxaRampPlugin.ts | 10 +-- .../ramps/infinite/infiniteRampPlugin.ts | 8 +- .../ramps/moonpay/moonpayRampPlugin.ts | 10 +-- src/plugins/ramps/paybis/paybisRampPlugin.ts | 10 +-- src/plugins/ramps/rampPluginTypes.ts | 5 +- .../ramps/revolut/revolutRampPlugin.ts | 10 +-- .../ramps/simplex/simplexRampPlugin.ts | 10 +-- 8 files changed, 74 insertions(+), 75 deletions(-) diff --git a/src/components/scenes/RampCreateScene.tsx b/src/components/scenes/RampCreateScene.tsx index 59938f7644d..b16ce185950 100644 --- a/src/components/scenes/RampCreateScene.tsx +++ b/src/components/scenes/RampCreateScene.tsx @@ -107,7 +107,7 @@ export const RampCreateScene: React.FC = (props: Props) => { ) // State for trade form - const [exchangeAmount, setExchangeAmount] = useState< + const [amountQuery, setAmountQuery] = useState< RampQouteAmount | { empty: true } >({ empty: true }) const [lastUsedInput, setLastUsedInput] = useState<'fiat' | 'crypto' | null>( @@ -251,7 +251,7 @@ export const RampCreateScene: React.FC = (props: Props) => { if ( hasAppliedInitialAmount.current || amountTypeSupport.onlyCrypto || - !('empty' in exchangeAmount) || + !('empty' in amountQuery) || lastUsedInput != null || shouldShowRegionSelect ) { @@ -270,7 +270,7 @@ export const RampCreateScene: React.FC = (props: Props) => { ) hasAppliedInitialAmount.current = true - setExchangeAmount({ amount: initialFiat }) + setAmountQuery({ amount: initialFiat }) setLastUsedInput('fiat') } @@ -287,7 +287,7 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedFiatCurrencyCode, shouldShowRegionSelect, fiatUsdRate, - exchangeAmount, + amountQuery, direction ]) @@ -297,7 +297,7 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedWallet == null || selectedCryptoCurrencyCode == null || lastUsedInput == null || - 'empty' in exchangeAmount || + 'empty' in amountQuery || countryCode === '' ) { return null @@ -316,14 +316,14 @@ export const RampCreateScene: React.FC = (props: Props) => { direction === 'sell' && lastUsedInput === 'crypto' && denomination != null && - !('max' in exchangeAmount) + !('max' in amountQuery) ) { const tokenId: EdgeTokenId = selectedCrypto?.tokenId ?? null const nativeBalance = selectedWallet.balanceMap.get(tokenId) ?? '0' const walletCryptoAmount = convertNativeToDenomination( denomination.multiplier )(nativeBalance) - if (gt(exchangeAmount.amount, walletCryptoAmount)) return null + if (gt(amountQuery.amount, walletCryptoAmount)) return null } return { @@ -331,7 +331,7 @@ export const RampCreateScene: React.FC = (props: Props) => { pluginId: selectedWallet.currencyInfo.pluginId, tokenId: selectedCrypto?.tokenId ?? null, displayCurrencyCode: selectedCryptoCurrencyCode, - exchangeAmount, + amountQuery, fiatCurrencyCode: selectedFiatCurrencyCode, amountType: lastUsedInput, direction, @@ -344,7 +344,7 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedWallet, selectedCryptoCurrencyCode, selectedCrypto, - exchangeAmount, + amountQuery, selectedFiatCurrencyCode, lastUsedInput, countryCode, @@ -373,7 +373,7 @@ export const RampCreateScene: React.FC = (props: Props) => { // For Max flow, select the quote with the largest supported amount const maxQuoteForMaxFlow = React.useMemo(() => { - if (!('max' in exchangeAmount) || allQuotes.length === 0) return null + if (!('max' in amountQuery) || allQuotes.length === 0) return null const quotesWithAmounts = allQuotes.filter(rampQuoteHasAmounts) if (quotesWithAmounts.length === 0) return null @@ -384,7 +384,7 @@ export const RampCreateScene: React.FC = (props: Props) => { return gt(bAmount, aAmount) ? b : a }) return picked - }, [exchangeAmount, allQuotes, lastUsedInput]) + }, [amountQuery, allQuotes, lastUsedInput]) // Calculate exchange rate from best quote const quoteExchangeRate = React.useMemo(() => { @@ -415,18 +415,18 @@ export const RampCreateScene: React.FC = (props: Props) => { if (selectedWallet == null) return null if (selectedCrypto == null) return null if (denomination == null) return null - if ('empty' in exchangeAmount) return null - if ('max' in exchangeAmount) return null + if ('empty' in amountQuery) return null + if ('max' in amountQuery) return null if (lastUsedInput == null) return null // Determine requested crypto amount let requestedCryptoAmount: string | null = null if (lastUsedInput === 'crypto') { - requestedCryptoAmount = exchangeAmount.amount + requestedCryptoAmount = amountQuery.amount } else if (lastUsedInput === 'fiat') { if (quoteExchangeRate === 0) return null requestedCryptoAmount = div( - exchangeAmount.amount, + amountQuery.amount, quoteExchangeRate.toString(), DECIMAL_PRECISION ) @@ -451,7 +451,7 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedWallet, selectedCrypto, denomination, - exchangeAmount, + amountQuery, lastUsedInput, quoteExchangeRate ]) @@ -460,31 +460,27 @@ export const RampCreateScene: React.FC = (props: Props) => { const displayFiatAmount = React.useMemo(() => { // Don't show any value if fiat input is disabled if (amountTypeSupport.onlyCrypto) return '' - if ('empty' in exchangeAmount) return '' + if ('empty' in amountQuery) return '' - if ('max' in exchangeAmount) { + if ('max' in amountQuery) { return maxQuoteForMaxFlow?.fiatAmount ?? '' } if (lastUsedInput === 'fiat') { // User entered fiat, show raw value (FilledTextInput will format it) - return exchangeAmount.amount + return amountQuery.amount } else if (lastUsedInput === 'crypto') { // Avoid division by zero if (quoteExchangeRate === 0) return '' // User entered crypto, convert to fiat only if we have a quote - return div( - mul(exchangeAmount.amount, quoteExchangeRate.toString()), - '1', - 2 - ) + return div(mul(amountQuery.amount, quoteExchangeRate.toString()), '1', 2) } else { return '' } }, [ amountTypeSupport.onlyCrypto, maxQuoteForMaxFlow, - exchangeAmount, + amountQuery, lastUsedInput, quoteExchangeRate ]) @@ -492,18 +488,18 @@ export const RampCreateScene: React.FC = (props: Props) => { const displayCryptoAmount = React.useMemo(() => { // Don't show any value if crypto input is disabled if (amountTypeSupport.onlyFiat) return '' - if ('empty' in exchangeAmount || lastUsedInput === null) return '' + if ('empty' in amountQuery || lastUsedInput === null) return '' - if ('max' in exchangeAmount) { + if ('max' in amountQuery) { return ( maxQuoteForMaxFlow?.cryptoAmount ?? - (typeof exchangeAmount.max === 'string' ? exchangeAmount.max : '') + (typeof amountQuery.max === 'string' ? amountQuery.max : '') ) } if (lastUsedInput === 'crypto') { // User entered crypto, show raw value (FilledTextInput will format it) - return exchangeAmount.amount + return amountQuery.amount } else if (lastUsedInput === 'fiat') { // Avoid division by zero if (quoteExchangeRate === 0) return '' @@ -512,14 +508,14 @@ export const RampCreateScene: React.FC = (props: Props) => { ? mulToPrecision(denomination.multiplier) : DECIMAL_PRECISION // User entered fiat, convert to crypto only if we have a quote - return div(exchangeAmount.amount, quoteExchangeRate.toString(), decimals) + return div(amountQuery.amount, quoteExchangeRate.toString(), decimals) } else { return '' } }, [ amountTypeSupport.onlyFiat, maxQuoteForMaxFlow, - exchangeAmount, + amountQuery, lastUsedInput, quoteExchangeRate, denomination @@ -567,7 +563,7 @@ export const RampCreateScene: React.FC = (props: Props) => { // Clear amount and max state when switching crypto assets in sell mode setPendingMaxNav(false) if (direction === 'sell') { - setExchangeAmount({ empty: true }) + setAmountQuery({ empty: true }) setLastUsedInput(null) } @@ -599,7 +595,7 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedWallet == null || selectedCryptoCurrencyCode == null || lastUsedInput == null || - 'empty' in exchangeAmount || + 'empty' in amountQuery || rampQuoteRequest == null ) { return @@ -636,12 +632,12 @@ export const RampCreateScene: React.FC = (props: Props) => { }, [bestQuote, selectedFiatCurrencyCode]) const handleFiatChangeText = useHandler((amount: string) => { - setExchangeAmount(amount === '' ? { empty: true } : { amount }) + setAmountQuery(amount === '' ? { empty: true } : { amount }) setLastUsedInput('fiat') }) const handleCryptoChangeText = useHandler((amount: string) => { - setExchangeAmount(amount === '' ? { empty: true } : { amount }) + setAmountQuery(amount === '' ? { empty: true } : { amount }) setLastUsedInput('crypto') }) @@ -667,11 +663,11 @@ export const RampCreateScene: React.FC = (props: Props) => { selectedCrypto.tokenId, denomination ) - setExchangeAmount({ + setAmountQuery({ max: maxSpendExchangeAmount }) } else { - setExchangeAmount({ + setAmountQuery({ max: true }) } @@ -680,10 +676,10 @@ export const RampCreateScene: React.FC = (props: Props) => { // Auto-navigate once a best quote arrives for the transient max flow React.useEffect(() => { const isMaxRequest = - rampQuoteRequest != null && 'max' in rampQuoteRequest.exchangeAmount + rampQuoteRequest != null && 'max' in rampQuoteRequest.amountQuery if ( pendingMaxNav && - 'max' in exchangeAmount && + 'max' in amountQuery && isMaxRequest && maxQuoteForMaxFlow != null && !isLoadingQuotes @@ -702,7 +698,7 @@ export const RampCreateScene: React.FC = (props: Props) => { navigation, amountTypeSupport.onlyCrypto, amountTypeSupport.onlyFiat, - exchangeAmount, + amountQuery, selectedWallet, selectedCrypto ]) @@ -722,7 +718,7 @@ export const RampCreateScene: React.FC = (props: Props) => { isResultLoading || allQuotes.length !== 0 || supportedPlugins.length === 0 || - 'empty' in exchangeAmount + 'empty' in amountQuery ) { return null } @@ -747,7 +743,7 @@ export const RampCreateScene: React.FC = (props: Props) => { isResultLoading, allQuotes.length, supportedPlugins.length, - exchangeAmount, + amountQuery, supportedPluginsError, quoteErrors, lastUsedInput, @@ -902,7 +898,7 @@ export const RampCreateScene: React.FC = (props: Props) => { {selectedCrypto == null || selectedWallet == null || denomination == null || - 'empty' in exchangeAmount || + 'empty' in amountQuery || lastUsedInput == null || (!isLoadingQuotes && !isFetchingQuotes && @@ -932,7 +928,7 @@ export const RampCreateScene: React.FC = (props: Props) => { // No other error to show (e.g., insufficient funds) errorForDisplay == null && // User has queried - !('empty' in exchangeAmount) && + !('empty' in amountQuery) && lastUsedInput != null && selectedWallet != null && selectedCryptoCurrencyCode != null ? ( @@ -968,7 +964,7 @@ export const RampCreateScene: React.FC = (props: Props) => { isResultLoading || selectedWallet == null || selectedCryptoCurrencyCode == null || - 'empty' in exchangeAmount || + 'empty' in amountQuery || lastUsedInput === null || supportedPlugins.length === 0 || allQuotes.length === 0 || diff --git a/src/plugins/ramps/banxa/banxaRampPlugin.ts b/src/plugins/ramps/banxa/banxaRampPlugin.ts index 713c4b393bf..b713f012b30 100644 --- a/src/plugins/ramps/banxa/banxaRampPlugin.ts +++ b/src/plugins/ramps/banxa/banxaRampPlugin.ts @@ -890,13 +890,13 @@ export const banxaRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.exchangeAmount + const isMaxAmount = 'max' in request.amountQuery const exchangeAmount = - 'amount' in request.exchangeAmount ? request.exchangeAmount.amount : '' + 'amount' in request.amountQuery ? request.amountQuery.amount : '' const maxAmountLimit = - 'max' in request.exchangeAmount && - typeof request.exchangeAmount.max === 'string' - ? request.exchangeAmount.max + 'max' in request.amountQuery && + typeof request.amountQuery.max === 'string' + ? request.amountQuery.max : undefined // Fetch provider configuration (cached or fresh) diff --git a/src/plugins/ramps/infinite/infiniteRampPlugin.ts b/src/plugins/ramps/infinite/infiniteRampPlugin.ts index 16927ee954f..2d3114ff21d 100644 --- a/src/plugins/ramps/infinite/infiniteRampPlugin.ts +++ b/src/plugins/ramps/infinite/infiniteRampPlugin.ts @@ -319,12 +319,12 @@ export const infiniteRampPlugin: RampPluginFactory = ( } // Check if max amount requested - if ('max' in request.exchangeAmount) { + if ('max' in request.amountQuery) { // TODO: Implement max amount logic when API supports it return [] } - const fiatAmount = parseFloat(request.exchangeAmount.amount) + const fiatAmount = parseFloat(request.amountQuery.amount) if (isNaN(fiatAmount) || fiatAmount <= 0) { return [] } @@ -543,8 +543,8 @@ export const infiniteRampPlugin: RampPluginFactory = ( // DEV ONLY: Clear auth key if amount is exactly 404 if ( ENABLE_DEV_TESTING_CAPABILITIES && - 'amount' in request.exchangeAmount && - request.exchangeAmount.amount === '404' + 'amount' in request.amountQuery && + request.amountQuery.amount === '404' ) { await _devOnlyClearAuthKey(account, pluginId) } diff --git a/src/plugins/ramps/moonpay/moonpayRampPlugin.ts b/src/plugins/ramps/moonpay/moonpayRampPlugin.ts index 7d41c61c49d..510ca45b232 100644 --- a/src/plugins/ramps/moonpay/moonpayRampPlugin.ts +++ b/src/plugins/ramps/moonpay/moonpayRampPlugin.ts @@ -517,13 +517,13 @@ export const moonpayRampPlugin: RampPluginFactory = ( const { direction, regionCode, displayCurrencyCode, tokenId } = request const fiatCurrencyCode = ensureIsoPrefix(request.fiatCurrencyCode) - const isMaxAmount = 'max' in request.exchangeAmount + const isMaxAmount = 'max' in request.amountQuery const exchangeAmountString = - 'amount' in request.exchangeAmount ? request.exchangeAmount.amount : '' + 'amount' in request.amountQuery ? request.amountQuery.amount : '' const maxAmountLimitString = - 'max' in request.exchangeAmount && - typeof request.exchangeAmount.max === 'string' - ? request.exchangeAmount.max + 'max' in request.amountQuery && + typeof request.amountQuery.max === 'string' + ? request.amountQuery.max : undefined // Fetch provider configuration (with caching) diff --git a/src/plugins/ramps/paybis/paybisRampPlugin.ts b/src/plugins/ramps/paybis/paybisRampPlugin.ts index bf5aadef0b7..a64dcdb7ab1 100644 --- a/src/plugins/ramps/paybis/paybisRampPlugin.ts +++ b/src/plugins/ramps/paybis/paybisRampPlugin.ts @@ -747,13 +747,13 @@ export const paybisRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.exchangeAmount + const isMaxAmount = 'max' in request.amountQuery const exchangeAmount = - 'amount' in request.exchangeAmount ? request.exchangeAmount.amount : '' + 'amount' in request.amountQuery ? request.amountQuery.amount : '' const maxAmountLimit = - 'max' in request.exchangeAmount && - typeof request.exchangeAmount.max === 'string' - ? request.exchangeAmount.max + 'max' in request.amountQuery && + typeof request.amountQuery.max === 'string' + ? request.amountQuery.max : undefined // Validate region restrictions diff --git a/src/plugins/ramps/rampPluginTypes.ts b/src/plugins/ramps/rampPluginTypes.ts index 88a14de1929..87cbbba19de 100644 --- a/src/plugins/ramps/rampPluginTypes.ts +++ b/src/plugins/ramps/rampPluginTypes.ts @@ -66,7 +66,10 @@ export interface RampQuoteRequest { wallet: EdgeCurrencyWallet tokenId: EdgeTokenId displayCurrencyCode: string - exchangeAmount: RampQouteAmount + /** + * The amount parameter apart of the request query. + */ + amountQuery: RampQouteAmount fiatCurrencyCode: string amountType: 'fiat' | 'crypto' direction: 'buy' | 'sell' diff --git a/src/plugins/ramps/revolut/revolutRampPlugin.ts b/src/plugins/ramps/revolut/revolutRampPlugin.ts index a63acbc7239..e4bea58d4e6 100644 --- a/src/plugins/ramps/revolut/revolutRampPlugin.ts +++ b/src/plugins/ramps/revolut/revolutRampPlugin.ts @@ -191,13 +191,13 @@ export const revolutRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.exchangeAmount + const isMaxAmount = 'max' in request.amountQuery const exchangeAmount = - 'amount' in request.exchangeAmount ? request.exchangeAmount.amount : '' + 'amount' in request.amountQuery ? request.amountQuery.amount : '' const maxAmountLimit = - 'max' in request.exchangeAmount && - typeof request.exchangeAmount.max === 'string' - ? request.exchangeAmount.max + 'max' in request.amountQuery && + typeof request.amountQuery.max === 'string' + ? request.amountQuery.max : undefined // Constraints per request diff --git a/src/plugins/ramps/simplex/simplexRampPlugin.ts b/src/plugins/ramps/simplex/simplexRampPlugin.ts index b6f23806d1c..2019ba422f1 100644 --- a/src/plugins/ramps/simplex/simplexRampPlugin.ts +++ b/src/plugins/ramps/simplex/simplexRampPlugin.ts @@ -480,13 +480,13 @@ export const simplexRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.exchangeAmount + const isMaxAmount = 'max' in request.amountQuery const exchangeAmount = - 'amount' in request.exchangeAmount ? request.exchangeAmount.amount : '' + 'amount' in request.amountQuery ? request.amountQuery.amount : '' const maxAmountLimit = - 'max' in request.exchangeAmount && - typeof request.exchangeAmount.max === 'string' - ? request.exchangeAmount.max + 'max' in request.amountQuery && + typeof request.amountQuery.max === 'string' + ? request.amountQuery.max : undefined // Validate direction From c00e2d2d88711b290fde3ffaed883c824a8c8ea7 Mon Sep 17 00:00:00 2001 From: Sam Holmes Date: Tue, 11 Nov 2025 13:02:51 -0800 Subject: [PATCH 3/5] Include "exchange" in `RampQuoteAmount` field names This makes it clear what the expected units are. --- src/components/scenes/RampCreateScene.tsx | 54 ++++++++++++------- src/plugins/ramps/banxa/banxaRampPlugin.ts | 13 +++-- .../ramps/infinite/infiniteRampPlugin.ts | 11 ++-- .../ramps/moonpay/moonpayRampPlugin.ts | 13 +++-- src/plugins/ramps/paybis/paybisRampPlugin.ts | 13 +++-- src/plugins/ramps/rampPluginTypes.ts | 4 +- .../ramps/revolut/revolutRampPlugin.ts | 13 +++-- .../ramps/simplex/simplexRampPlugin.ts | 13 +++-- 8 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/components/scenes/RampCreateScene.tsx b/src/components/scenes/RampCreateScene.tsx index b16ce185950..e281096c0ee 100644 --- a/src/components/scenes/RampCreateScene.tsx +++ b/src/components/scenes/RampCreateScene.tsx @@ -270,7 +270,7 @@ export const RampCreateScene: React.FC = (props: Props) => { ) hasAppliedInitialAmount.current = true - setAmountQuery({ amount: initialFiat }) + setAmountQuery({ exchangeAmount: initialFiat }) setLastUsedInput('fiat') } @@ -316,14 +316,14 @@ export const RampCreateScene: React.FC = (props: Props) => { direction === 'sell' && lastUsedInput === 'crypto' && denomination != null && - !('max' in amountQuery) + !('max' in amountQuery || 'maxExchangeAmount' in amountQuery) ) { const tokenId: EdgeTokenId = selectedCrypto?.tokenId ?? null const nativeBalance = selectedWallet.balanceMap.get(tokenId) ?? '0' const walletCryptoAmount = convertNativeToDenomination( denomination.multiplier )(nativeBalance) - if (gt(amountQuery.amount, walletCryptoAmount)) return null + if (gt(amountQuery.exchangeAmount, walletCryptoAmount)) return null } return { @@ -373,7 +373,11 @@ export const RampCreateScene: React.FC = (props: Props) => { // For Max flow, select the quote with the largest supported amount const maxQuoteForMaxFlow = React.useMemo(() => { - if (!('max' in amountQuery) || allQuotes.length === 0) return null + if ( + !('max' in amountQuery || 'maxExchangeAmount' in amountQuery) || + allQuotes.length === 0 + ) + return null const quotesWithAmounts = allQuotes.filter(rampQuoteHasAmounts) if (quotesWithAmounts.length === 0) return null @@ -417,16 +421,17 @@ export const RampCreateScene: React.FC = (props: Props) => { if (denomination == null) return null if ('empty' in amountQuery) return null if ('max' in amountQuery) return null + if ('maxExchangeAmount' in amountQuery) return null if (lastUsedInput == null) return null // Determine requested crypto amount let requestedCryptoAmount: string | null = null if (lastUsedInput === 'crypto') { - requestedCryptoAmount = amountQuery.amount + requestedCryptoAmount = amountQuery.exchangeAmount } else if (lastUsedInput === 'fiat') { if (quoteExchangeRate === 0) return null requestedCryptoAmount = div( - amountQuery.amount, + amountQuery.exchangeAmount, quoteExchangeRate.toString(), DECIMAL_PRECISION ) @@ -462,18 +467,22 @@ export const RampCreateScene: React.FC = (props: Props) => { if (amountTypeSupport.onlyCrypto) return '' if ('empty' in amountQuery) return '' - if ('max' in amountQuery) { + if ('max' in amountQuery || 'maxExchangeAmount' in amountQuery) { return maxQuoteForMaxFlow?.fiatAmount ?? '' } if (lastUsedInput === 'fiat') { // User entered fiat, show raw value (FilledTextInput will format it) - return amountQuery.amount + return amountQuery.exchangeAmount } else if (lastUsedInput === 'crypto') { // Avoid division by zero if (quoteExchangeRate === 0) return '' // User entered crypto, convert to fiat only if we have a quote - return div(mul(amountQuery.amount, quoteExchangeRate.toString()), '1', 2) + return div( + mul(amountQuery.exchangeAmount, quoteExchangeRate.toString()), + '1', + 2 + ) } else { return '' } @@ -491,15 +500,15 @@ export const RampCreateScene: React.FC = (props: Props) => { if ('empty' in amountQuery || lastUsedInput === null) return '' if ('max' in amountQuery) { - return ( - maxQuoteForMaxFlow?.cryptoAmount ?? - (typeof amountQuery.max === 'string' ? amountQuery.max : '') - ) + return maxQuoteForMaxFlow?.cryptoAmount ?? '' + } + if ('maxExchangeAmount' in amountQuery) { + return maxQuoteForMaxFlow?.cryptoAmount ?? amountQuery.maxExchangeAmount } if (lastUsedInput === 'crypto') { // User entered crypto, show raw value (FilledTextInput will format it) - return amountQuery.amount + return amountQuery.exchangeAmount } else if (lastUsedInput === 'fiat') { // Avoid division by zero if (quoteExchangeRate === 0) return '' @@ -508,7 +517,11 @@ export const RampCreateScene: React.FC = (props: Props) => { ? mulToPrecision(denomination.multiplier) : DECIMAL_PRECISION // User entered fiat, convert to crypto only if we have a quote - return div(amountQuery.amount, quoteExchangeRate.toString(), decimals) + return div( + amountQuery.exchangeAmount, + quoteExchangeRate.toString(), + decimals + ) } else { return '' } @@ -632,12 +645,12 @@ export const RampCreateScene: React.FC = (props: Props) => { }, [bestQuote, selectedFiatCurrencyCode]) const handleFiatChangeText = useHandler((amount: string) => { - setAmountQuery(amount === '' ? { empty: true } : { amount }) + setAmountQuery(amount === '' ? { empty: true } : { exchangeAmount: amount }) setLastUsedInput('fiat') }) const handleCryptoChangeText = useHandler((amount: string) => { - setAmountQuery(amount === '' ? { empty: true } : { amount }) + setAmountQuery(amount === '' ? { empty: true } : { exchangeAmount: amount }) setLastUsedInput('crypto') }) @@ -664,7 +677,7 @@ export const RampCreateScene: React.FC = (props: Props) => { denomination ) setAmountQuery({ - max: maxSpendExchangeAmount + maxExchangeAmount: maxSpendExchangeAmount }) } else { setAmountQuery({ @@ -676,10 +689,11 @@ export const RampCreateScene: React.FC = (props: Props) => { // Auto-navigate once a best quote arrives for the transient max flow React.useEffect(() => { const isMaxRequest = - rampQuoteRequest != null && 'max' in rampQuoteRequest.amountQuery + rampQuoteRequest != null && + ('max' in rampQuoteRequest.amountQuery || + 'maxExchangeAmount' in rampQuoteRequest.amountQuery) if ( pendingMaxNav && - 'max' in amountQuery && isMaxRequest && maxQuoteForMaxFlow != null && !isLoadingQuotes diff --git a/src/plugins/ramps/banxa/banxaRampPlugin.ts b/src/plugins/ramps/banxa/banxaRampPlugin.ts index b713f012b30..82217eeacd4 100644 --- a/src/plugins/ramps/banxa/banxaRampPlugin.ts +++ b/src/plugins/ramps/banxa/banxaRampPlugin.ts @@ -890,13 +890,16 @@ export const banxaRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.amountQuery + const isMaxAmount = + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery const exchangeAmount = - 'amount' in request.amountQuery ? request.amountQuery.amount : '' + 'exchangeAmount' in request.amountQuery + ? request.amountQuery.exchangeAmount + : '' const maxAmountLimit = - 'max' in request.amountQuery && - typeof request.amountQuery.max === 'string' - ? request.amountQuery.max + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount : undefined // Fetch provider configuration (cached or fresh) diff --git a/src/plugins/ramps/infinite/infiniteRampPlugin.ts b/src/plugins/ramps/infinite/infiniteRampPlugin.ts index 2d3114ff21d..d391fda1293 100644 --- a/src/plugins/ramps/infinite/infiniteRampPlugin.ts +++ b/src/plugins/ramps/infinite/infiniteRampPlugin.ts @@ -319,12 +319,15 @@ export const infiniteRampPlugin: RampPluginFactory = ( } // Check if max amount requested - if ('max' in request.amountQuery) { + if ( + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery + ) { // TODO: Implement max amount logic when API supports it return [] } - const fiatAmount = parseFloat(request.amountQuery.amount) + const fiatAmount = parseFloat(request.amountQuery.exchangeAmount) if (isNaN(fiatAmount) || fiatAmount <= 0) { return [] } @@ -543,8 +546,8 @@ export const infiniteRampPlugin: RampPluginFactory = ( // DEV ONLY: Clear auth key if amount is exactly 404 if ( ENABLE_DEV_TESTING_CAPABILITIES && - 'amount' in request.amountQuery && - request.amountQuery.amount === '404' + `exchangeAmount` in request.amountQuery && + request.amountQuery.exchangeAmount === '404' ) { await _devOnlyClearAuthKey(account, pluginId) } diff --git a/src/plugins/ramps/moonpay/moonpayRampPlugin.ts b/src/plugins/ramps/moonpay/moonpayRampPlugin.ts index 510ca45b232..bf72dc8f165 100644 --- a/src/plugins/ramps/moonpay/moonpayRampPlugin.ts +++ b/src/plugins/ramps/moonpay/moonpayRampPlugin.ts @@ -517,13 +517,16 @@ export const moonpayRampPlugin: RampPluginFactory = ( const { direction, regionCode, displayCurrencyCode, tokenId } = request const fiatCurrencyCode = ensureIsoPrefix(request.fiatCurrencyCode) - const isMaxAmount = 'max' in request.amountQuery + const isMaxAmount = + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery const exchangeAmountString = - 'amount' in request.amountQuery ? request.amountQuery.amount : '' + `exchangeAmount` in request.amountQuery + ? request.amountQuery.exchangeAmount + : '' const maxAmountLimitString = - 'max' in request.amountQuery && - typeof request.amountQuery.max === 'string' - ? request.amountQuery.max + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount : undefined // Fetch provider configuration (with caching) diff --git a/src/plugins/ramps/paybis/paybisRampPlugin.ts b/src/plugins/ramps/paybis/paybisRampPlugin.ts index a64dcdb7ab1..feafc97390c 100644 --- a/src/plugins/ramps/paybis/paybisRampPlugin.ts +++ b/src/plugins/ramps/paybis/paybisRampPlugin.ts @@ -747,13 +747,16 @@ export const paybisRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.amountQuery + const isMaxAmount = + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery const exchangeAmount = - 'amount' in request.amountQuery ? request.amountQuery.amount : '' + `exchangeAmount` in request.amountQuery + ? request.amountQuery.exchangeAmount + : '' const maxAmountLimit = - 'max' in request.amountQuery && - typeof request.amountQuery.max === 'string' - ? request.amountQuery.max + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount : undefined // Validate region restrictions diff --git a/src/plugins/ramps/rampPluginTypes.ts b/src/plugins/ramps/rampPluginTypes.ts index 87cbbba19de..259b3568766 100644 --- a/src/plugins/ramps/rampPluginTypes.ts +++ b/src/plugins/ramps/rampPluginTypes.ts @@ -53,13 +53,13 @@ interface RampQuoteMaxLimitAmount { * Requests a quote for the maximum amount that the provider supports up to * a specified limit. */ - max: string + maxExchangeAmount: string } interface RampQuoteExactAmount { /** * Requests a quote for the exact amount provided. * */ - amount: string + exchangeAmount: string } export interface RampQuoteRequest { diff --git a/src/plugins/ramps/revolut/revolutRampPlugin.ts b/src/plugins/ramps/revolut/revolutRampPlugin.ts index e4bea58d4e6..27bbdcd11a9 100644 --- a/src/plugins/ramps/revolut/revolutRampPlugin.ts +++ b/src/plugins/ramps/revolut/revolutRampPlugin.ts @@ -191,13 +191,16 @@ export const revolutRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.amountQuery + const isMaxAmount = + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery const exchangeAmount = - 'amount' in request.amountQuery ? request.amountQuery.amount : '' + `exchangeAmount` in request.amountQuery + ? request.amountQuery.exchangeAmount + : '' const maxAmountLimit = - 'max' in request.amountQuery && - typeof request.amountQuery.max === 'string' - ? request.amountQuery.max + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount : undefined // Constraints per request diff --git a/src/plugins/ramps/simplex/simplexRampPlugin.ts b/src/plugins/ramps/simplex/simplexRampPlugin.ts index 2019ba422f1..b9136c60458 100644 --- a/src/plugins/ramps/simplex/simplexRampPlugin.ts +++ b/src/plugins/ramps/simplex/simplexRampPlugin.ts @@ -480,13 +480,16 @@ export const simplexRampPlugin: RampPluginFactory = ( } = request const currencyPluginId = request.wallet.currencyInfo.pluginId - const isMaxAmount = 'max' in request.amountQuery + const isMaxAmount = + 'max' in request.amountQuery || + 'maxExchangeAmount' in request.amountQuery const exchangeAmount = - 'amount' in request.amountQuery ? request.amountQuery.amount : '' + `exchangeAmount` in request.amountQuery + ? request.amountQuery.exchangeAmount + : '' const maxAmountLimit = - 'max' in request.amountQuery && - typeof request.amountQuery.max === 'string' - ? request.amountQuery.max + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount : undefined // Validate direction From b373e427710289ce6b51b783ab6c6704c6fbc53b Mon Sep 17 00:00:00 2001 From: Sam Holmes Date: Tue, 11 Nov 2025 12:59:17 -0800 Subject: [PATCH 4/5] Add support for max amount quote request for Infinite ramp plugin --- .../ramps/infinite/infiniteRampPlugin.ts | 105 ++++++++++++++---- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/src/plugins/ramps/infinite/infiniteRampPlugin.ts b/src/plugins/ramps/infinite/infiniteRampPlugin.ts index d391fda1293..95b9cb7fccf 100644 --- a/src/plugins/ramps/infinite/infiniteRampPlugin.ts +++ b/src/plugins/ramps/infinite/infiniteRampPlugin.ts @@ -318,18 +318,30 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } - // Check if max amount requested - if ( + // Extract max amount flags + const isMaxAmount = 'max' in request.amountQuery || 'maxExchangeAmount' in request.amountQuery - ) { - // TODO: Implement max amount logic when API supports it - return [] - } - - const fiatAmount = parseFloat(request.amountQuery.exchangeAmount) - if (isNaN(fiatAmount) || fiatAmount <= 0) { - return [] + const maxAmountLimit = + 'maxExchangeAmount' in request.amountQuery + ? request.amountQuery.maxExchangeAmount + : undefined + + // Get exchange amount if not a max request + const exchangeAmount = + 'exchangeAmount' in request.amountQuery + ? request.amountQuery.exchangeAmount + : undefined + + // Validate exchange amount for non-max requests + if (!isMaxAmount) { + if (exchangeAmount == null) { + return [] + } + const fiatAmount = parseFloat(exchangeAmount) + if (isNaN(fiatAmount) || fiatAmount <= 0) { + return [] + } } // Get the Infinite network name @@ -448,14 +460,61 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } - // Check amount limits based on direction and amount type - if (request.direction === 'buy') { - // For buy, we have fiat amount and need to check fiat limits - const fiatCurrency = currencies.currencies.find( - c => c.code === cleanFiatCode && c.type === 'fiat' - ) + // Get fiat currency for limit checking and max amount determination + const fiatCurrency = currencies.currencies.find( + c => c.code === cleanFiatCode && c.type === 'fiat' + ) + + if (fiatCurrency == null) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'fiatUnsupported', + fiatCurrencyCode: cleanFiatCode, + paymentMethod: 'bank', + pluginDisplayName + }) + } + + // Determine the fiat amount to use + let fiatAmount: number + if (isMaxAmount) { + // Use max amount from fiat currency config + const maxFiatAmount = parseFloat(fiatCurrency.maxAmount) + + // Apply maxExchangeAmount limit if provided + if (maxAmountLimit != null) { + const maxLimitValue = parseFloat(maxAmountLimit) + if (!isNaN(maxLimitValue) && isFinite(maxLimitValue)) { + fiatAmount = Math.min(maxFiatAmount, maxLimitValue) + } else { + fiatAmount = maxFiatAmount + } + } else { + fiatAmount = maxFiatAmount + } - if (fiatCurrency != null) { + // Validate max amount is >= min amount + const minFiatAmount = parseFloat(fiatCurrency.minAmount) + if (fiatAmount < minFiatAmount) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'underLimit', + errorAmount: minFiatAmount, + displayCurrencyCode: request.fiatCurrencyCode + }) + } + } else { + // Use provided exchange amount + if (exchangeAmount == null) { + return [] + } + fiatAmount = parseFloat(exchangeAmount) + if (isNaN(fiatAmount) || fiatAmount <= 0) { + return [] + } + + // Check amount limits based on direction + if (request.direction === 'buy') { const minFiatAmount = parseFloat(fiatCurrency.minAmount) const maxFiatAmount = parseFloat(fiatCurrency.maxAmount) @@ -476,13 +535,13 @@ export const infiniteRampPlugin: RampPluginFactory = ( displayCurrencyCode: request.fiatCurrencyCode }) } + } else { + // For sell, we need to check crypto limits + // Since amountType is 'fiat', we don't have the crypto amount yet + // We'll need to fetch a quote first to know the crypto amount + // For now, skip the pre-check and let the API handle limit validation + // The API will return an error if the resulting crypto amount is out of bounds } - } else { - // For sell, we need to check crypto limits - // Since amountType is 'fiat', we don't have the crypto amount yet - // We'll need to fetch a quote first to know the crypto amount - // For now, skip the pre-check and let the API handle limit validation - // The API will return an error if the resulting crypto amount is out of bounds } // Fetch quote from API From 1f7fb6f9e863b8ea9ec4af791b4cd6fd6885252b Mon Sep 17 00:00:00 2001 From: Sam Holmes Date: Tue, 11 Nov 2025 15:23:29 -0800 Subject: [PATCH 5/5] Add support for crypto amount quote requests for Infinite ramp plugin --- .../ramps/infinite/infiniteRampPlugin.ts | 206 +++++++++++------- 1 file changed, 124 insertions(+), 82 deletions(-) diff --git a/src/plugins/ramps/infinite/infiniteRampPlugin.ts b/src/plugins/ramps/infinite/infiniteRampPlugin.ts index 95b9cb7fccf..54442d7f954 100644 --- a/src/plugins/ramps/infinite/infiniteRampPlugin.ts +++ b/src/plugins/ramps/infinite/infiniteRampPlugin.ts @@ -291,7 +291,7 @@ export const infiniteRampPlugin: RampPluginFactory = ( return { supported: true, - supportedAmountTypes: ['fiat'] + supportedAmountTypes: ['fiat', 'crypto'] } } catch (error) { console.error('Infinite: Error in checkSupport:', error) @@ -310,14 +310,6 @@ export const infiniteRampPlugin: RampPluginFactory = ( const currencyPluginId = request.wallet.currencyInfo.pluginId - // Only support fiat amounts for now - if (request.amountType !== 'fiat') { - throw new FiatProviderError({ - providerId: pluginId, - errorType: 'amountTypeUnsupported' - }) - } - // Extract max amount flags const isMaxAmount = 'max' in request.amountQuery || @@ -327,23 +319,6 @@ export const infiniteRampPlugin: RampPluginFactory = ( ? request.amountQuery.maxExchangeAmount : undefined - // Get exchange amount if not a max request - const exchangeAmount = - 'exchangeAmount' in request.amountQuery - ? request.amountQuery.exchangeAmount - : undefined - - // Validate exchange amount for non-max requests - if (!isMaxAmount) { - if (exchangeAmount == null) { - return [] - } - const fiatAmount = parseFloat(exchangeAmount) - if (isNaN(fiatAmount) || fiatAmount <= 0) { - return [] - } - } - // Get the Infinite network name const infiniteNetwork = getInfiniteNetwork(currencyPluginId) if (infiniteNetwork == null) { @@ -460,6 +435,10 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } + const amountType = request.amountType + const isFiatAmountType = amountType === 'fiat' + const isCryptoAmountType = !isFiatAmountType + // Get fiat currency for limit checking and max amount determination const fiatCurrency = currencies.currencies.find( c => c.code === cleanFiatCode && c.type === 'fiat' @@ -475,50 +454,76 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } - // Determine the fiat amount to use - let fiatAmount: number + const parseAmountString = (value?: string): number | undefined => { + if (value == null) return undefined + const parsed = parseFloat(value) + return Number.isFinite(parsed) ? parsed : undefined + } + + const maxAmountLimitValue = parseAmountString(maxAmountLimit) + const minFiatAmount = parseAmountString(fiatCurrency.minAmount) + const maxFiatAmount = parseAmountString(fiatCurrency.maxAmount) + const minCryptoAmount = parseAmountString(targetCurrency.minAmount) + const maxCryptoAmount = parseAmountString(targetCurrency.maxAmount) + + let fiatAmount: number | undefined + let cryptoAmount: number | undefined + + const amountString = + 'exchangeAmount' in request.amountQuery + ? request.amountQuery.exchangeAmount + : undefined + + const assertNumber = (value: number | undefined): value is number => + value != null && Number.isFinite(value) + if (isMaxAmount) { - // Use max amount from fiat currency config - const maxFiatAmount = parseFloat(fiatCurrency.maxAmount) - - // Apply maxExchangeAmount limit if provided - if (maxAmountLimit != null) { - const maxLimitValue = parseFloat(maxAmountLimit) - if (!isNaN(maxLimitValue) && isFinite(maxLimitValue)) { - fiatAmount = Math.min(maxFiatAmount, maxLimitValue) + if (isFiatAmountType) { + if (!assertNumber(maxFiatAmount)) return [] + if (assertNumber(maxAmountLimitValue)) { + fiatAmount = Math.min(maxFiatAmount, maxAmountLimitValue) + + if (assertNumber(minFiatAmount) && fiatAmount < minFiatAmount) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'underLimit', + errorAmount: minFiatAmount, + displayCurrencyCode: request.fiatCurrencyCode + }) + } } else { fiatAmount = maxFiatAmount } } else { - fiatAmount = maxFiatAmount - } + if (!assertNumber(maxCryptoAmount)) return [] + let amountToUse = maxCryptoAmount + if (assertNumber(maxAmountLimitValue)) { + amountToUse = Math.min(amountToUse, maxAmountLimitValue) + } + cryptoAmount = amountToUse - // Validate max amount is >= min amount - const minFiatAmount = parseFloat(fiatCurrency.minAmount) - if (fiatAmount < minFiatAmount) { - throw new FiatProviderError({ - providerId: pluginId, - errorType: 'underLimit', - errorAmount: minFiatAmount, - displayCurrencyCode: request.fiatCurrencyCode - }) + if (assertNumber(minCryptoAmount) && cryptoAmount < minCryptoAmount) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'underLimit', + errorAmount: minCryptoAmount, + displayCurrencyCode: request.displayCurrencyCode + }) + } } } else { - // Use provided exchange amount - if (exchangeAmount == null) { + if (amountString == null) { return [] } - fiatAmount = parseFloat(exchangeAmount) - if (isNaN(fiatAmount) || fiatAmount <= 0) { + const parsedAmount = parseFloat(amountString) + if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) { return [] } - // Check amount limits based on direction - if (request.direction === 'buy') { - const minFiatAmount = parseFloat(fiatCurrency.minAmount) - const maxFiatAmount = parseFloat(fiatCurrency.maxAmount) + if (isFiatAmountType) { + fiatAmount = parsedAmount - if (fiatAmount < minFiatAmount) { + if (assertNumber(minFiatAmount) && fiatAmount < minFiatAmount) { throw new FiatProviderError({ providerId: pluginId, errorType: 'underLimit', @@ -527,7 +532,7 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } - if (fiatAmount > maxFiatAmount) { + if (assertNumber(maxFiatAmount) && fiatAmount > maxFiatAmount) { throw new FiatProviderError({ providerId: pluginId, errorType: 'overLimit', @@ -536,52 +541,89 @@ export const infiniteRampPlugin: RampPluginFactory = ( }) } } else { - // For sell, we need to check crypto limits - // Since amountType is 'fiat', we don't have the crypto amount yet - // We'll need to fetch a quote first to know the crypto amount - // For now, skip the pre-check and let the API handle limit validation - // The API will return an error if the resulting crypto amount is out of bounds + cryptoAmount = parsedAmount + + if (assertNumber(minCryptoAmount) && cryptoAmount < minCryptoAmount) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'underLimit', + errorAmount: minCryptoAmount, + displayCurrencyCode: request.displayCurrencyCode + }) + } + + if (assertNumber(maxCryptoAmount) && cryptoAmount > maxCryptoAmount) { + throw new FiatProviderError({ + providerId: pluginId, + errorType: 'overLimit', + errorAmount: maxCryptoAmount, + displayCurrencyCode: request.displayCurrencyCode + }) + } } } + if (isFiatAmountType && fiatAmount == null) return [] + if (isCryptoAmountType && cryptoAmount == null) return [] + // Fetch quote from API const flow: InfiniteQuoteFlow = request.direction === 'buy' ? 'ONRAMP' : 'OFFRAMP' + const sourceParams = + request.direction === 'buy' + ? isFiatAmountType + ? { asset: cleanFiatCode, amount: fiatAmount! } + : { asset: cleanFiatCode } + : isCryptoAmountType + ? { + asset: targetCurrency.currencyCode, + network: infiniteNetwork, + amount: cryptoAmount! + } + : { + asset: targetCurrency.currencyCode, + network: infiniteNetwork + } + + const targetParams = + request.direction === 'buy' + ? { + asset: targetCurrency.currencyCode, + network: infiniteNetwork, + ...(isCryptoAmountType ? { amount: cryptoAmount! } : {}) + } + : isFiatAmountType + ? { asset: cleanFiatCode, amount: fiatAmount! } + : { asset: cleanFiatCode } + const quoteParams = { flow, - source: - request.direction === 'buy' - ? { asset: cleanFiatCode, amount: fiatAmount } - : { - asset: targetCurrency.currencyCode, - network: infiniteNetwork - // Don't provide amount for sell when we have fiat amount - }, - target: - request.direction === 'buy' - ? { asset: targetCurrency.currencyCode, network: infiniteNetwork } - : { asset: cleanFiatCode, amount: fiatAmount } // Provide target amount for sell + source: sourceParams, + target: targetParams } const quoteResponse = await infiniteApi.createQuote(quoteParams) + const responseCryptoAmount = + request.direction === 'buy' + ? quoteResponse.target.amount + : quoteResponse.source.amount + const responseFiatAmount = + request.direction === 'buy' + ? quoteResponse.source.amount + : quoteResponse.target.amount + // Convert to RampQuoteResult - map based on direction const quote: RampQuote = { pluginId, partnerIcon, pluginDisplayName, displayCurrencyCode: request.displayCurrencyCode, - cryptoAmount: - request.direction === 'buy' - ? quoteResponse.target.amount.toString() - : quoteResponse.source.amount.toString(), + cryptoAmount: (responseCryptoAmount ?? 0).toString(), isEstimate: false, fiatCurrencyCode: request.fiatCurrencyCode, - fiatAmount: - request.direction === 'buy' - ? quoteResponse.source.amount.toString() - : quoteResponse.target.amount.toString(), + fiatAmount: (responseFiatAmount ?? 0).toString(), direction: request.direction, regionCode: request.regionCode, paymentType: 'wire', // Infinite uses wire bank transfers