From 92e774321e7f0912f693a14b57c1ee7521d2a791 Mon Sep 17 00:00:00 2001 From: male-gal Date: Wed, 25 Oct 2023 17:33:28 +0200 Subject: [PATCH] fix(LLD/LLM CounterValues): Changed supported CounterValues source to API Feedbacks Removed overprotection on settings reducer to allow not to impact the init of the app --- .changeset/neat-mirrors-joke.md | 7 ++ .../src/renderer/actions/settings.ts | 6 ++ .../ledger-live-desktop/src/renderer/init.tsx | 1 + .../src/renderer/reducers/settings.ts | 46 +++++++----- .../screens/market/CountervalueSelect.tsx | 11 ++- .../src/renderer/screens/market/index.tsx | 3 + .../sections/General/CounterValueSelect.tsx | 12 ++-- .../settings/sections/General/index.tsx | 13 ++++ .../tests/specs/market/market.spec.ts | 69 ++++++++++++++++++ .../src/actions/settings.ts | 5 ++ apps/ledger-live-mobile/src/actions/types.ts | 5 +- .../src/context/LedgerStore.tsx | 25 ++++++- .../src/reducers/settings.ts | 17 ++--- apps/ledger-live-mobile/src/reducers/types.ts | 8 +++ .../screens/Market/MarketCurrencySelect.tsx | 7 +- .../Settings/General/CountervalueSettings.tsx | 11 ++- libs/coin-framework/src/currencies/support.ts | 70 +++++++++++++++---- 17 files changed, 258 insertions(+), 58 deletions(-) create mode 100644 .changeset/neat-mirrors-joke.md diff --git a/.changeset/neat-mirrors-joke.md b/.changeset/neat-mirrors-joke.md new file mode 100644 index 000000000000..9d3ad0c78d78 --- /dev/null +++ b/.changeset/neat-mirrors-joke.md @@ -0,0 +1,7 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +"@ledgerhq/coin-framework": patch +--- + +New supported countervalues source from API. diff --git a/apps/ledger-live-desktop/src/renderer/actions/settings.ts b/apps/ledger-live-desktop/src/renderer/actions/settings.ts index 59f70f27d2be..946031df3ae8 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/settings.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/settings.ts @@ -19,6 +19,7 @@ import { selectedTimeRangeSelector, SettingsState, VaultSigner, + SupportedCountervaluesData, } from "~/renderer/reducers/settings"; import { useRefreshAccountsOrdering } from "~/renderer/actions/general"; import { Language, Locale } from "~/config/languages"; @@ -344,3 +345,8 @@ export const setVaultSigner = (payload: VaultSigner) => ({ type: "SET_VAULT_SIGNER", payload, }); + +export const setSupportedCounterValues = (payload: SupportedCountervaluesData[]) => ({ + type: "SET_SUPPORTED_COUNTER_VALUES", + payload, +}); diff --git a/apps/ledger-live-desktop/src/renderer/init.tsx b/apps/ledger-live-desktop/src/renderer/init.tsx index 9966d0af1701..3fbd11b37989 100644 --- a/apps/ledger-live-desktop/src/renderer/init.tsx +++ b/apps/ledger-live-desktop/src/renderer/init.tsx @@ -126,6 +126,7 @@ async function init() { deepLinkUrl = url; }); const initialSettings = (await getKey("app", "settings")) || {}; + fetchSettings( deepLinkUrl ? { diff --git a/apps/ledger-live-desktop/src/renderer/reducers/settings.ts b/apps/ledger-live-desktop/src/renderer/reducers/settings.ts index 70ab938dc6c8..70a6c1673792 100644 --- a/apps/ledger-live-desktop/src/renderer/reducers/settings.ts +++ b/apps/ledger-live-desktop/src/renderer/reducers/settings.ts @@ -105,6 +105,7 @@ export type SettingsState = { }; featureFlagsButtonVisible: boolean; vaultSigner: VaultSigner; + supportedCounterValues: SupportedCountervaluesData[]; }; export const getInitialLanguageAndLocale = (): { language: Language; locale: Locale } => { @@ -189,6 +190,7 @@ const INITIAL_STATE: SettingsState = { // Vault vaultSigner: { enabled: false, host: "", token: "", workspace: "" }, + supportedCounterValues: [], }; /* Handlers */ @@ -237,6 +239,7 @@ type HandlersPayloads = { featureFlagsButtonVisible: boolean; }; SET_VAULT_SIGNER: VaultSigner; + SET_SUPPORTED_COUNTER_VALUES: SupportedCountervaluesData[]; }; type SettingsHandlers = Handlers; @@ -265,12 +268,6 @@ const handlers: SettingsHandlers = { }; }, FETCH_SETTINGS: (state, { payload: settings }) => { - if ( - settings.counterValue && - !supportedCountervalues.find(({ currency }) => currency.ticker === settings.counterValue) - ) { - settings.counterValue = INITIAL_STATE.counterValue; - } return { ...state, ...settings, @@ -396,6 +393,20 @@ const handlers: SettingsHandlers = { ...state, vaultSigner: payload, }), + SET_SUPPORTED_COUNTER_VALUES: (state: SettingsState, { payload }) => { + let activeCounterValue = state.counterValue; + if ( + activeCounterValue && + !payload.find(({ currency }) => currency.ticker === activeCounterValue) + ) { + activeCounterValue = INITIAL_STATE.counterValue; + } + return { + ...state, + supportedCounterValues: payload, + counterValue: activeCounterValue, + }; + }, }; export default handleActions( handlers as unknown as SettingsHandlers, @@ -465,17 +476,18 @@ export type SupportedCountervaluesData = { label: string; currency: Currency; }; -export const supportedCountervalues: SupportedCountervaluesData[] = [ - ...listSupportedFiats(), - ...possibleIntermediaries, -] - .map(currency => ({ - value: currency.ticker, - label: `${currency.name} - ${currency.ticker}`, - currency, - })) - .sort((a, b) => (a.currency.name < b.currency.name ? -1 : 1)); +export const getsupportedCountervalues = async (): Promise => { + const supportedFiats = await listSupportedFiats(); + const data = [...supportedFiats, ...possibleIntermediaries] + .map(currency => ({ + value: currency.ticker, + label: `${currency.name} - ${currency.ticker}`, + currency, + })) + .sort((a, b) => (a.currency.name < b.currency.name ? -1 : 1)); + return data; +}; // TODO refactor selectors to *Selector naming convention export const storeSelector = (state: State): SettingsState => state.settings; @@ -691,3 +703,5 @@ export const overriddenFeatureFlagsSelector = (state: State) => export const featureFlagsButtonVisibleSelector = (state: State) => state.settings.featureFlagsButtonVisible; export const vaultSignerSelector = (state: State) => state.settings.vaultSigner; +export const supportedCounterValuesSelector = (state: State) => + state.settings.supportedCounterValues; diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx index 29c3951a5a24..8a6bc33e5b27 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx @@ -1,9 +1,13 @@ import React, { useCallback, useMemo, memo } from "react"; -import { supportedCountervalues, SupportedCountervaluesData } from "~/renderer/reducers/settings"; +import { + supportedCounterValuesSelector, + SupportedCountervaluesData, +} from "~/renderer/reducers/settings"; import Dropdown from "./DropDown"; import Track from "~/renderer/analytics/Track"; import { useTranslation } from "react-i18next"; import { Currency } from "@ledgerhq/types-cryptoassets"; +import { useSelector } from "react-redux"; type Props = { counterCurrency?: string; @@ -17,6 +21,7 @@ function CounterValueSelect({ supportedCounterCurrencies, }: Props) { const { t } = useTranslation(); + const supportedCountervalues = useSelector(supportedCounterValuesSelector); const handleChangeCounterValue = useCallback( (item: { currency: Currency } | null) => { @@ -32,7 +37,7 @@ function CounterValueSelect({ supportedCountervalues.filter(({ value }: SupportedCountervaluesData) => supportedCounterCurrencies.includes(value?.toLowerCase()), ), - [supportedCounterCurrencies], + [supportedCounterCurrencies, supportedCountervalues], ); const cvOption = useMemo( @@ -41,7 +46,7 @@ function CounterValueSelect({ (f: SupportedCountervaluesData) => f?.value?.toLowerCase() === counterCurrency?.toLowerCase(), ), - [counterCurrency], + [counterCurrency, supportedCountervalues], ); return ( diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx index c0e90240fc99..2235536d5b7c 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx @@ -10,6 +10,7 @@ import MarketList from "./MarketList"; import SideDrawerFilter from "./SideDrawerFilter"; import { rangeDataTable } from "@ledgerhq/live-common/market/utils/rangeDataTable"; import TrackPage from "~/renderer/analytics/TrackPage"; +import { useInitSupportedCounterValues } from '../settings/sections/General/index' const Container = styled(Flex).attrs({ flex: "1", @@ -71,6 +72,8 @@ export default function Market() { const starredMarketCoins: string[] = useSelector(starredMarketCoinsSelector); const starFilterOn = starred.length > 0; + useInitSupportedCounterValues() + const updateSearch = useCallback( (value: string) => { refresh({ search: value, starred: [], liveCompatible: false }); diff --git a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/CounterValueSelect.tsx b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/CounterValueSelect.tsx index 55beb0c8a46f..f6845fd3201a 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/CounterValueSelect.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/CounterValueSelect.tsx @@ -4,13 +4,17 @@ import { setCounterValue } from "~/renderer/actions/settings"; import { SupportedCountervaluesData, counterValueCurrencySelector, - supportedCountervalues, + supportedCounterValuesSelector, } from "~/renderer/reducers/settings"; import Select from "~/renderer/components/Select"; import Track from "~/renderer/analytics/Track"; + const CounterValueSelect = React.memo<{}>(function CounterValueSelect() { const counterValueCurrency = useSelector(counterValueCurrencySelector); + const supportedCounterValues = useSelector(supportedCounterValuesSelector); + const dispatch = useDispatch(); + const handleChangeCounterValue = useCallback( (item?: SupportedCountervaluesData | null) => { if (!item) return; @@ -19,8 +23,8 @@ const CounterValueSelect = React.memo<{}>(function CounterValueSelect() { [dispatch], ); const cvOption = useMemo( - () => supportedCountervalues.find(f => f.value === counterValueCurrency.ticker), - [counterValueCurrency], + () => supportedCounterValues.find(f => f.value === counterValueCurrency.ticker), + [counterValueCurrency, supportedCounterValues], ); return ( <> @@ -31,7 +35,7 @@ const CounterValueSelect = React.memo<{}>(function CounterValueSelect() { onChange={handleChangeCounterValue} itemToString={(item: { name: string }) => item.name} renderSelected={(item: { name: string }) => item && item.name} - options={supportedCountervalues} + options={supportedCounterValues} value={cvOption} /> diff --git a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx index e5eb8eca2633..ad9bfeecce9c 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx @@ -13,9 +13,22 @@ import SentryLogsButton from "./SentryLogsButton"; import ShareAnalyticsButton from "./ShareAnalyticsButton"; import CarouselVisibility from "./CarouselVisibility"; import { hasPasswordSelector } from "~/renderer/reducers/application"; +import { setSupportedCounterValues } from "~/renderer/actions/settings"; +import { getsupportedCountervalues } from "~/renderer/reducers/settings"; +import { useDispatch } from "react-redux"; + +export const useInitSupportedCounterValues = async () => { + const dispatch = useDispatch(); + + const supportedCounterValues = await getsupportedCountervalues(); + dispatch(setSupportedCounterValues(supportedCounterValues)); +}; + const SectionGeneral = () => { const hasPassword = useSelector(hasPasswordSelector); const { t } = useTranslation(); + useInitSupportedCounterValues(); + return ( <> diff --git a/apps/ledger-live-desktop/tests/specs/market/market.spec.ts b/apps/ledger-live-desktop/tests/specs/market/market.spec.ts index f04ca5d4e498..dd3d8285ba87 100644 --- a/apps/ledger-live-desktop/tests/specs/market/market.spec.ts +++ b/apps/ledger-live-desktop/tests/specs/market/market.spec.ts @@ -41,6 +41,75 @@ test("Market", async ({ page }) => { await expect.soft(page).toHaveScreenshot("market-page-no-scrollbar.png"); }); + await page.route("https://countervalues.live.ledger.com/v2/supported-to", async route => { + route.fulfill({ + headers: { teststatus: "mocked" }, + body: JSON.stringify([ + "aed", + "ars", + "aud", + "bch", + "bdt", + "bhd", + "bits", + "bmd", + "bnb", + "brl", + "btc", + "cad", + "chf", + "clp", + "cny", + "czk", + "dkk", + "dot", + "eos", + "eth", + "eur", + "gbp", + "hkd", + "huf", + "idr", + "ils", + "inr", + "jpy", + "krw", + "kwd", + "link", + "lkr", + "ltc", + "mmk", + "mxn", + "myr", + "ngn", + "nok", + "nzd", + "php", + "pkr", + "pln", + "rub", + "sar", + "sats", + "sek", + "sgd", + "thb", + "try", + "twd", + "uah", + "usd", + "vef", + "vnd", + "xag", + "xau", + "xdr", + "xlm", + "xrp", + "yfi", + "zar", + ]), + }); + }); + await test.step("change countervalue", async () => { await marketPage.switchCountervalue("THB"); await marketPage.waitForLoading(); diff --git a/apps/ledger-live-mobile/src/actions/settings.ts b/apps/ledger-live-mobile/src/actions/settings.ts index 0ce451daf7b7..2a60a6bbcf3b 100755 --- a/apps/ledger-live-mobile/src/actions/settings.ts +++ b/apps/ledger-live-mobile/src/actions/settings.ts @@ -66,6 +66,7 @@ import { SettingsSetClosedNetworkBannerPayload, SettingsSetClosedWithdrawBannerPayload, SettingsSetUserNps, + SettingsSetSupportedCounterValues, } from "./types"; import { ImageType } from "../components/CustomImage/types"; @@ -274,6 +275,10 @@ export const setGeneralTermsVersionAccepted = createAction(SettingsActionTypes.SET_USER_NPS); +export const setSupportedCounterValues = createAction( + SettingsActionTypes.SET_SUPPORTED_COUNTER_VALUES, +); + type PortfolioRangeOption = { key: PortfolioRange; value: string; diff --git a/apps/ledger-live-mobile/src/actions/types.ts b/apps/ledger-live-mobile/src/actions/types.ts index a0065f8a8c84..3b461ad7ed53 100644 --- a/apps/ledger-live-mobile/src/actions/types.ts +++ b/apps/ledger-live-mobile/src/actions/types.ts @@ -278,6 +278,7 @@ export enum SettingsActionTypes { SET_CLOSED_NETWORK_BANNER = "SET_CLOSED_NETWORK_BANNER", SET_CLOSED_WITHDRAW_BANNER = "SET_CLOSED_WITHDRAW_BANNER", SET_USER_NPS = "SET_USER_NPS", + SET_SUPPORTED_COUNTER_VALUES = "SET_SUPPORTED_COUNTER_VALUES", } export type SettingsImportPayload = Partial; @@ -375,6 +376,7 @@ export type SettingsSetHasBeenUpsoldProtectPayload = SettingsState["hasBeenUpsol export type SettingsCompleteOnboardingPayload = void | SettingsState["hasCompletedOnboarding"]; export type SettingsSetGeneralTermsVersionAccepted = SettingsState["generalTermsVersionAccepted"]; export type SettingsSetUserNps = number; +export type SettingsSetSupportedCounterValues = SettingsState["supportedCounterValues"]; export type SettingsPayload = | SettingsImportPayload @@ -429,7 +431,8 @@ export type SettingsPayload = | SettingsSetHasBeenUpsoldProtectPayload | SettingsSetOnboardingTypePayload | SettingsSetClosedNetworkBannerPayload - | SettingsSetUserNps; + | SettingsSetUserNps + | SettingsSetSupportedCounterValues; // === WALLET CONNECT ACTIONS === export enum WalletConnectActionTypes { diff --git a/apps/ledger-live-mobile/src/context/LedgerStore.tsx b/apps/ledger-live-mobile/src/context/LedgerStore.tsx index 06ca43882e11..149ef768b4b4 100644 --- a/apps/ledger-live-mobile/src/context/LedgerStore.tsx +++ b/apps/ledger-live-mobile/src/context/LedgerStore.tsx @@ -15,12 +15,13 @@ import { getProtect, } from "../db"; import reducers from "../reducers"; -import { importSettings } from "../actions/settings"; +import { importSettings, setSupportedCounterValues } from "../actions/settings"; import { importStore as importAccounts } from "../actions/accounts"; import { importBle } from "../actions/ble"; import { updateProtectData, updateProtectStatus } from "../actions/protect"; -import { INITIAL_STATE as settingsState, supportedCountervalues } from "../reducers/settings"; +import { INITIAL_STATE as settingsState } from "../reducers/settings"; import { listCachedCurrencyIds, hydrateCurrency } from "../bridge/cache"; +import { getCryptoCurrencyById, listSupportedFiats } from "@ledgerhq/live-common/currencies/index"; const middlewares: [Middleware] = [thunk]; @@ -78,11 +79,29 @@ export default class LedgerStoreProvider extends Component< .catch((reason: unknown) => ({ status: "rejected", reason })), ), ); + const bitcoin = getCryptoCurrencyById("bitcoin"); + const ethereum = getCryptoCurrencyById("ethereum"); + const possibleIntermediaries = [bitcoin, ethereum]; + + const getsupportedCountervalues = async () => { + const supportedFiats = await listSupportedFiats(); + const supportedCounterValues = [...supportedFiats, ...possibleIntermediaries] + .map(currency => ({ + value: currency.ticker, + ticker: currency.ticker, + label: `${currency.name} - ${currency.ticker}`, + currency, + })) + .sort((a, b) => (a.currency.name < b.currency.name ? -1 : 1)); + return supportedCounterValues; + }; + const supportedCounterValues = await getsupportedCountervalues(); + store.dispatch(setSupportedCounterValues(supportedCounterValues)); if ( settingsData && settingsData.counterValue && - !supportedCountervalues.find(({ ticker }) => ticker === settingsData.counterValue) + !supportedCounterValues.find(({ ticker }) => ticker === settingsData.counterValue) ) { settingsData.counterValue = settingsState.counterValue; } diff --git a/apps/ledger-live-mobile/src/reducers/settings.ts b/apps/ledger-live-mobile/src/reducers/settings.ts index bf9d08eba8e8..f392331322e5 100644 --- a/apps/ledger-live-mobile/src/reducers/settings.ts +++ b/apps/ledger-live-mobile/src/reducers/settings.ts @@ -3,9 +3,7 @@ import type { Action } from "redux-actions"; import merge from "lodash/merge"; import { findCurrencyByTicker, - getCryptoCurrencyById, getFiatCurrencyByTicker, - listSupportedFiats, } from "@ledgerhq/live-common/currencies/index"; import { getEnv, setEnvUnsafe } from "@ledgerhq/live-env"; import { createSelector } from "reselect"; @@ -77,6 +75,7 @@ import type { SettingsSetClosedNetworkBannerPayload, SettingsSetClosedWithdrawBannerPayload, SettingsSetUserNps, + SettingsSetSupportedCounterValues, } from "../actions/types"; import { SettingsActionTypes, @@ -84,14 +83,6 @@ import { } from "../actions/types"; import { ScreenName } from "../const"; -const bitcoin = getCryptoCurrencyById("bitcoin"); -const ethereum = getCryptoCurrencyById("ethereum"); -export const possibleIntermediaries = [bitcoin, ethereum]; -export const supportedCountervalues = [...listSupportedFiats(), ...possibleIntermediaries]; -export const intermediaryCurrency = (from: Currency, _to: Currency) => { - if (from === ethereum || from.type === "TokenCurrency") return ethereum; - return bitcoin; -}; export const timeRangeDaysByKey = { day: 1, week: 7, @@ -184,6 +175,7 @@ export const INITIAL_STATE: SettingsState = { hasClosedWithdrawBanner: false, }, userNps: null, + supportedCounterValues: [], }; const pairHash = (from: { ticker: string }, to: { ticker: string }) => @@ -625,6 +617,10 @@ const handlers: ReducerMap = { ...state, userNps: (action as Action).payload, }), + [SettingsActionTypes.SET_SUPPORTED_COUNTER_VALUES]: (state, action) => ({ + ...state, + supportedCounterValues: (action as Action).payload, + }), }; export default handleActions(handlers, INITIAL_STATE); @@ -813,3 +809,4 @@ export const hasBeenUpsoldProtectSelector = (state: State) => state.settings.has export const generalTermsVersionAcceptedSelector = (state: State) => state.settings.generalTermsVersionAccepted; export const userNpsSelector = (state: State) => state.settings.userNps; +export const getSupportedCounterValues = (state: State) => state.settings.supportedCounterValues; diff --git a/apps/ledger-live-mobile/src/reducers/types.ts b/apps/ledger-live-mobile/src/reducers/types.ts index 20d007135854..c035aba650de 100644 --- a/apps/ledger-live-mobile/src/reducers/types.ts +++ b/apps/ledger-live-mobile/src/reducers/types.ts @@ -171,6 +171,13 @@ export type Pair = { export type Theme = "system" | "light" | "dark"; +export type supportedCountervaluesData = { + value: string; + ticker: string; + label: string; + currency: Currency; +}; + export type SettingsState = { counterValue: string; counterValueExchange: string | null | undefined; @@ -237,6 +244,7 @@ export type SettingsState = { hasClosedWithdrawBanner: boolean; }; userNps: number | null; + supportedCounterValues: supportedCountervaluesData[]; }; export type NotificationsSettings = { diff --git a/apps/ledger-live-mobile/src/screens/Market/MarketCurrencySelect.tsx b/apps/ledger-live-mobile/src/screens/Market/MarketCurrencySelect.tsx index 59c06bf6bab3..7d3982bd989c 100644 --- a/apps/ledger-live-mobile/src/screens/Market/MarketCurrencySelect.tsx +++ b/apps/ledger-live-mobile/src/screens/Market/MarketCurrencySelect.tsx @@ -4,9 +4,9 @@ import React, { useCallback, memo, useState, useRef, useEffect } from "react"; import { Trans, useTranslation } from "react-i18next"; import { FlatList, TouchableOpacity, Image, TextInput } from "react-native"; import styled, { useTheme } from "styled-components/native"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import Search from "../../components/Search"; -import { supportedCountervalues } from "../../reducers/settings"; +import { getSupportedCounterValues } from "../../reducers/settings"; import { setMarketCounterCurrency } from "../../actions/settings"; import type { StackNavigatorProps } from "../../components/RootNavigator/types/helpers"; import type { BaseNavigatorStackParamList } from "../../components/RootNavigator/types/BaseNavigator"; @@ -52,6 +52,7 @@ type Props = StackNavigatorProps supportedCounterCurrencies.includes(ticker.toLowerCase())) .map(cur => ({ value: cur.ticker.toLowerCase(), - label: cur.name, + label: cur.label, })) .sort(a => (a.value === counterCurrency ? -1 : 0)); diff --git a/apps/ledger-live-mobile/src/screens/Settings/General/CountervalueSettings.tsx b/apps/ledger-live-mobile/src/screens/Settings/General/CountervalueSettings.tsx index edeb6f5a6a7e..8fb6f350a4ef 100644 --- a/apps/ledger-live-mobile/src/screens/Settings/General/CountervalueSettings.tsx +++ b/apps/ledger-live-mobile/src/screens/Settings/General/CountervalueSettings.tsx @@ -3,17 +3,16 @@ import React from "react"; import { connect } from "react-redux"; import { Text } from "@ledgerhq/native-ui"; import { setCountervalue } from "../../../actions/settings"; -import { counterValueCurrencySelector, supportedCountervalues } from "../../../reducers/settings"; +import { + counterValueCurrencySelector, + getSupportedCounterValues, +} from "../../../reducers/settings"; import { State } from "../../../reducers/types"; import makeGenericSelectScreen from "../../makeGenericSelectScreen"; -const items = supportedCountervalues - .map(cur => ({ value: cur.ticker, label: cur.name })) - .sort((a, b) => a.label.localeCompare(b.label)); - const mapStateToProps = (state: State) => ({ selectedKey: counterValueCurrencySelector(state).ticker, - items, + items: getSupportedCounterValues(state), }); const mapDispatchToProps = { diff --git a/libs/coin-framework/src/currencies/support.ts b/libs/coin-framework/src/currencies/support.ts index e9de34465dde..2599cfb34c5f 100644 --- a/libs/coin-framework/src/currencies/support.ts +++ b/libs/coin-framework/src/currencies/support.ts @@ -5,15 +5,14 @@ import { } from "@ledgerhq/cryptoassets"; import { CryptoCurrency, CryptoCurrencyId, FiatCurrency } from "@ledgerhq/types-cryptoassets"; import { getEnv } from "@ledgerhq/live-env"; +import { log } from "@ledgerhq/logs"; // set by user side effect to precise which currencies are considered supported (typically by live) let userSupportedCurrencies: CryptoCurrency[] = []; -let userSupportedFiats: FiatCurrency[] = []; -// Current list was established with what our API really supports -// to update the list, -// 1. $ ledger-live countervalues --format supportedFiats --fiats -// 2. copy & paste the output -setSupportedFiats([ +let userSupportedFiats: FiatCurrency[] | null = null; + +// The API returns Coingeko countervalues tickers, but getFiatCurrencyByTicker might not support each of those. +const locallySupportedFiats = [ "AED", "AUD", "BGN", @@ -63,15 +62,62 @@ setSupportedFiats([ "VND", "VUV", "ZAR", -]); +]; -export function isFiatSupported(fiat: FiatCurrency) { - return userSupportedFiats.includes(fiat); +async function initializeUserSupportedFiats() { + try { + const ids = await fetchSupportedFiatsTokens(); + const idsToUpper = ids.map(id => id.toUpperCase()); + + // This makes sure we only keep the elements supported in our API and that are available for getFiatCurrencyByTicker + const supportedTokens = idsToUpper.filter(token => locallySupportedFiats.includes(token)); + userSupportedFiats = supportedTokens.map(id => { + return getFiatCurrencyByTicker(id); + }); + } catch (error) { + log("debug", `Failed to get supported Fiats. Error Message: ${error}`); + } +} + +export async function fetchSupportedFiatsTokens(): Promise { + try { + const response = await fetch("https://countervalues.live.ledger.com/v2/supported-to", { + method: "GET", + headers: { + accept: "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`Request failed with status ${response.status}`); + } + + const data: string[] = await response.json(); + return data; + } catch (error) { + // Handle any network or parsing errors here + console.error("Error:", error); + throw error; + } } -export function setSupportedFiats(ids: string[]) { - userSupportedFiats = ids.map(getFiatCurrencyByTicker); + +// Usage of isFiatSupported and listSupportedFiats should check if userSupportedFiats is populated +export function isFiatSupported(fiat: FiatCurrency) { + return userSupportedFiats?.includes(fiat); } -export function listSupportedFiats(): FiatCurrency[] { + +export async function listSupportedFiats(): Promise { + if (userSupportedFiats === null) { + // Handle case where userSupportedFiats is not yet populated (e.g., by calling initializeUserSupportedFiats) + try { + await initializeUserSupportedFiats(); + } catch (error) { + // Handle initialization error + log("debug", `Failed to initialize userSupportedFiats. Error Message: ${error}`); + return []; + } + return userSupportedFiats || []; + } return userSupportedFiats; }