diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bcee395c4e..b6f4f3996ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ - fixed: Round Kado-provided amounts during sell - fixed: "Contacts Access" setting could be out of sync with the OS-level contacts access setting +## 4.14.1 + +- changed: More informative buy amount limit errors for light accounts +- fixed: Default buy amounts for light accounts can potentially be over limit for non-USD currencies + ## 4.14.0 - added: `ExpandableList` component, replacing the address hint dropdown in `AddressFormScene` diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 801b4ed855f..3c271e54212 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1458,7 +1458,7 @@ const strings = { fiat_plugin_sell_failed_try_again: 'Sell order failed. Please try again.', fiat_plugin_sell_failed_to_send_try_again: 'Failed to send funds for sell transaction. Please try again.', fiat_plugin_cannot_continue_camera_permission: 'Cannot continue. Camera permission needed for ID verifications', - fiat_plugin_purchase_limit_error: 'Please create a full account to increase the purchase limit', + fiat_plugin_purchase_limit_error_2s: 'Please create a full account to increase the purchase limit above %1$s %2$s', fiat_plugin_max_buy_quote_error: 'Provider cannot create max buy quote', fiat_plugin_max_sell_quote_error: 'Provider cannot create max sell quote', fiat_plugin_max_sell_quote_error_1s: 'Cannot create max sell quote for %1$s', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 179e01e50d0..9dd418b8c0a 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1289,7 +1289,7 @@ "fiat_plugin_sell_failed_try_again": "Sell order failed. Please try again.", "fiat_plugin_sell_failed_to_send_try_again": "Failed to send funds for sell transaction. Please try again.", "fiat_plugin_cannot_continue_camera_permission": "Cannot continue. Camera permission needed for ID verifications", - "fiat_plugin_purchase_limit_error": "Please create a full account to increase the purchase limit", + "fiat_plugin_purchase_limit_error_2s": "Please create a full account to increase the purchase limit above %1$s %2$s", "fiat_plugin_max_buy_quote_error": "Provider cannot create max buy quote", "fiat_plugin_max_sell_quote_error": "Provider cannot create max sell quote", "fiat_plugin_max_sell_quote_error_1s": "Cannot create max sell quote for %1$s", diff --git a/src/plugins/gui/amountQuotePlugin.ts b/src/plugins/gui/amountQuotePlugin.ts index 2af2aebe394..6524b2ad677 100644 --- a/src/plugins/gui/amountQuotePlugin.ts +++ b/src/plugins/gui/amountQuotePlugin.ts @@ -1,4 +1,4 @@ -import { div, eq, gt, mul, round, toFixed } from 'biggystring' +import { div, eq, gt, round, toFixed } from 'biggystring' import { asNumber, asObject } from 'cleaners' import { sprintf } from 'sprintf-js' @@ -61,6 +61,28 @@ const MAX_QUOTE_VALUE = '10000000000' const NO_PROVIDER_TOAST_DURATION_MS = 10000 +/** Pick a default fiat amount in the foreign fiat amount that is roughly equal + to the default USD fiat amount. Prioritizes rounding up/down to a nice looking + whole number. */ +async function getInitialFiatValue(startingFiatAmount: string, isoFiatCurrencyCode: string) { + let initialValue1: string | undefined + if (isoFiatCurrencyCode !== 'iso:USD') { + const isoNow = new Date().toISOString() + const ratePair = `${isoFiatCurrencyCode}_iso:USD` + const rate = await getHistoricalRate(ratePair, isoNow) + initialValue1 = div(startingFiatAmount, String(rate), DECIMAL_PRECISION) + + // Round out all decimals + initialValue1 = round(initialValue1, 0) + + // Keep only the first decimal place + initialValue1 = round(initialValue1, initialValue1.length - 1) + } else { + initialValue1 = startingFiatAmount + } + return initialValue1 +} + export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPluginFactoryArgs) => { const { account, guiPlugin, longPress = false, pluginUtils, showUi } = params const { pluginId } = guiPlugin @@ -225,31 +247,15 @@ export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPlugi let goodQuotes: FiatProviderQuote[] = [] let lastSourceFieldNum: number - const fiatCurrencyCode = forceFiatCurrencyCode ?? defaultIsoFiat - const displayFiatCurrencyCode = removeIsoPrefix(fiatCurrencyCode) + const isoFiatCurrencyCode = forceFiatCurrencyCode ?? defaultIsoFiat + const displayFiatCurrencyCode = removeIsoPrefix(isoFiatCurrencyCode) const isBuy = direction === 'buy' const disableInput = requireCrypto ? 1 : requireFiat ? 2 : undefined logEvent(isBuy ? 'Buy_Quote' : 'Sell_Quote') - // Pick a default fiat amount in the foreign fiat amount that is roughly - // equal to the default USD fiat amount - let initialValue1: string | undefined const startingFiatAmount = isLightAccount ? DEFAULT_FIAT_AMOUNT_LIGHT_ACCOUNT : defaultFiatAmount ?? DEFAULT_FIAT_AMOUNT - if (displayFiatCurrencyCode !== 'USD' && defaultFiatAmount == null) { - const isoFiatCurrencyCode = `iso:${displayFiatCurrencyCode}` - const isoNow = new Date().toISOString() - const ratePair = `${isoFiatCurrencyCode}_iso:USD` - const rate = await getHistoricalRate(ratePair, isoNow) - initialValue1 = div(startingFiatAmount, String(rate), DECIMAL_PRECISION) - // Round out a decimals - initialValue1 = round(initialValue1, 0) - - // Only leave the first decimal - initialValue1 = round(initialValue1, initialValue1.length - 1) - } else { - initialValue1 = requireCrypto ? undefined : startingFiatAmount - } + const initialValue1 = requireCrypto ? undefined : await getInitialFiatValue(startingFiatAmount, isoFiatCurrencyCode) // Navigate to scene to have user enter amount const enterAmount: InternalFiatPluginEnterAmountParams = { @@ -382,7 +388,7 @@ export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPlugi pluginUtils, tokenId, exchangeAmount: value, - fiatCurrencyCode, + fiatCurrencyCode: isoFiatCurrencyCode, amountType: 'fiat', direction, paymentTypes, @@ -398,7 +404,7 @@ export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPlugi pluginUtils, tokenId, exchangeAmount: value, - fiatCurrencyCode, + fiatCurrencyCode: isoFiatCurrencyCode, amountType: 'crypto', direction, paymentTypes, @@ -513,12 +519,15 @@ export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPlugi // Restrict light accounts from buying more than $50 at a time if (isLightAccount && isBuy) { const quoteFiatCurrencyCode = bestQuote.fiatCurrencyCode - const quoteFiatRate = - quoteFiatCurrencyCode === 'iso:USD' ? '1' : (await getHistoricalRate(`${quoteFiatCurrencyCode}_iso:USD`, new Date().toISOString())).toString() - const quoteDollarValue = mul(bestQuote.fiatAmount, quoteFiatRate) + const maxAmount = await getInitialFiatValue(startingFiatAmount, isoFiatCurrencyCode) - if (gt(quoteDollarValue, '50')) { - stateManager.update({ statusText: { content: lstrings.fiat_plugin_purchase_limit_error, textType: 'error' } }) + if (gt(bestQuote.fiatAmount, maxAmount)) { + stateManager.update({ + statusText: { + content: sprintf(lstrings.fiat_plugin_purchase_limit_error_2s, maxAmount, removeIsoPrefix(quoteFiatCurrencyCode)), + textType: 'error' + } + }) return } }