From fe367f7e748945ac4997a7be62b7012e49d3b6b5 Mon Sep 17 00:00:00 2001 From: Michal Vanek Date: Mon, 9 Sep 2024 15:12:38 +0200 Subject: [PATCH] fix(coinmarket): testnets support for trading --- .../form/common/useCoinmarketAccount.ts | 5 ++++- .../useCoinmarketBuyFormDefaultValues.tsx | 6 +++--- .../wallet/coinmarket/useCoinmarketInfo.ts | 10 ++++++---- .../suite/src/types/coinmarket/coinmarket.ts | 2 +- .../__tests__/coinmarketUtils.test.ts | 20 +++++++++++++++++++ .../wallet/coinmarket/coinmarketUtils.ts | 14 +++++++++++-- .../common/CoinmarketAddressOptions.tsx | 7 +++++-- .../coinmarket/common/CoinmarketBalance.tsx | 9 ++++++++- .../coinmarket/common/CoinmarketCoinLogo.tsx | 2 +- .../wallet-config/src/networksConfig.ts | 4 ++-- 10 files changed, 62 insertions(+), 17 deletions(-) diff --git a/packages/suite/src/hooks/wallet/coinmarket/form/common/useCoinmarketAccount.ts b/packages/suite/src/hooks/wallet/coinmarket/form/common/useCoinmarketAccount.ts index edfc955b3da..1bbf57cc19c 100644 --- a/packages/suite/src/hooks/wallet/coinmarket/form/common/useCoinmarketAccount.ts +++ b/packages/suite/src/hooks/wallet/coinmarket/form/common/useCoinmarketAccount.ts @@ -30,7 +30,10 @@ export const useCoinmarketAccount = ({ return coinmarketAccount; } - if (isTestnet(selectedAccount.account.symbol)) { + if ( + isTestnet(selectedAccount.account.symbol) && + !selectedAccount.network.coingeckoNativeId + ) { const defaultSymbol = mapTestnetSymbol(selectedAccount.account.symbol); const accountsSorted = coinmarketGetSortedAccounts({ accounts, diff --git a/packages/suite/src/hooks/wallet/coinmarket/form/useCoinmarketBuyFormDefaultValues.tsx b/packages/suite/src/hooks/wallet/coinmarket/form/useCoinmarketBuyFormDefaultValues.tsx index 91991273bb9..7fc190bf0d4 100644 --- a/packages/suite/src/hooks/wallet/coinmarket/form/useCoinmarketBuyFormDefaultValues.tsx +++ b/packages/suite/src/hooks/wallet/coinmarket/form/useCoinmarketBuyFormDefaultValues.tsx @@ -10,19 +10,19 @@ import { } from 'src/constants/wallet/coinmarket/form'; import { FiatCurrencyCode, CryptoId } from 'invity-api'; import { useCoinmarketInfo } from 'src/hooks/wallet/coinmarket/useCoinmarketInfo'; -import { getCoingeckoId } from '@suite-common/wallet-config'; +import { networks } from '@suite-common/wallet-config'; export const useCoinmarketBuyFormDefaultValues = ( accountSymbol: Account['symbol'], buyInfo: BuyInfo | undefined, ): CoinmarketBuyFormDefaultValuesProps => { const { buildDefaultCryptoOption } = useCoinmarketInfo(); - const cryptoId = getCoingeckoId(accountSymbol) as CryptoId; + const cryptoId = networks[accountSymbol]?.coingeckoNativeId; const country = buyInfo?.buyInfo?.country; const defaultCountry = useMemo(() => getDefaultCountry(country), [country]); const defaultCrypto = useMemo( - () => buildDefaultCryptoOption(cryptoId), + () => buildDefaultCryptoOption(cryptoId as CryptoId | undefined), [buildDefaultCryptoOption, cryptoId], ); const defaultPaymentMethod: CoinmarketPaymentMethodListProps = useMemo( diff --git a/packages/suite/src/hooks/wallet/coinmarket/useCoinmarketInfo.ts b/packages/suite/src/hooks/wallet/coinmarket/useCoinmarketInfo.ts index 1741ab0c651..35e57561b13 100644 --- a/packages/suite/src/hooks/wallet/coinmarket/useCoinmarketInfo.ts +++ b/packages/suite/src/hooks/wallet/coinmarket/useCoinmarketInfo.ts @@ -8,7 +8,7 @@ import { CoinmarketInfoProps, CoinmarketOptionsGroupProps, } from 'src/types/coinmarket/coinmarket'; -import { parseCryptoId } from 'src/utils/wallet/coinmarket/coinmarketUtils'; +import { parseCryptoId, testnetToProdCryptoId } from 'src/utils/wallet/coinmarket/coinmarketUtils'; const supportedAddressValidatorSymbols = new Set( addressValidator.getCurrencies().map(c => c.symbol), @@ -65,7 +65,9 @@ export const useCoinmarketInfo = (): CoinmarketInfoProps => { return; } - const nativeCoinSymbol = cryptoIdToNativeCoinSymbol(cryptoId); + const nativeCoinSymbol = cryptoIdToNativeCoinSymbol( + testnetToProdCryptoId(cryptoId), + ); if (!nativeCoinSymbol || !supportedAddressValidatorSymbols.has(nativeCoinSymbol)) { return; } @@ -102,8 +104,8 @@ export const useCoinmarketInfo = (): CoinmarketInfoProps => { ); const buildDefaultCryptoOption = useCallback( - (cryptoId: CryptoId) => { - const coinInfo = coins[cryptoId]; + (cryptoId: CryptoId | undefined) => { + const coinInfo = cryptoId && coins[cryptoId]; if (coinInfo) { return toCryptoOption(cryptoId, coinInfo); } diff --git a/packages/suite/src/types/coinmarket/coinmarket.ts b/packages/suite/src/types/coinmarket/coinmarket.ts index ccef80c5ea2..3c07b8b5a88 100644 --- a/packages/suite/src/types/coinmarket/coinmarket.ts +++ b/packages/suite/src/types/coinmarket/coinmarket.ts @@ -161,7 +161,7 @@ export interface CoinmarketInfoProps { cryptoIds: Set, excludedCryptoIds?: Set, ) => CoinmarketOptionsGroupProps[]; - buildDefaultCryptoOption: (cryptoId: CryptoId) => CoinmarketCryptoListProps; + buildDefaultCryptoOption: (cryptoId: CryptoId | undefined) => CoinmarketCryptoListProps; } export interface CoinmarketCoinLogoProps { diff --git a/packages/suite/src/utils/wallet/coinmarket/__tests__/coinmarketUtils.test.ts b/packages/suite/src/utils/wallet/coinmarket/__tests__/coinmarketUtils.test.ts index 11028d3edc3..39e017498a8 100644 --- a/packages/suite/src/utils/wallet/coinmarket/__tests__/coinmarketUtils.test.ts +++ b/packages/suite/src/utils/wallet/coinmarket/__tests__/coinmarketUtils.test.ts @@ -13,6 +13,7 @@ import { coinmarketGetRoundedFiatAmount, coinmarketGetAmountLabels, coinmarketGetAccountLabel, + testnetToProdCryptoId, } from '../coinmarketUtils'; import { FIXTURE_ACCOUNTS, @@ -302,4 +303,23 @@ describe('coinmarket utils', () => { expect(coinmarketGetAccountLabel('USDT', true)).toBe('USDT'); expect(coinmarketGetAccountLabel('USDT', false)).toBe('USDT'); }); + + it('testnetToProdCryptoId', () => { + expect(testnetToProdCryptoId('test-bitcoin' as CryptoId)).toEqual('bitcoin'); + expect(testnetToProdCryptoId('bitcoin' as CryptoId)).toEqual('bitcoin'); + + expect(testnetToProdCryptoId('test-ripple' as CryptoId)).toEqual('ripple'); + expect(testnetToProdCryptoId('ripple' as CryptoId)).toEqual('ripple'); + + expect( + testnetToProdCryptoId( + 'test-ethereum--0x1234123412341234123412341234123412341236' as CryptoId, + ), + ).toEqual('ethereum--0x1234123412341234123412341234123412341236'); + expect( + testnetToProdCryptoId( + 'ethereum--0x1234123412341234123412341234123412341236' as CryptoId, + ), + ).toEqual('ethereum--0x1234123412341234123412341234123412341236'); + }); }); diff --git a/packages/suite/src/utils/wallet/coinmarket/coinmarketUtils.ts b/packages/suite/src/utils/wallet/coinmarket/coinmarketUtils.ts index aea79dfbf47..8da17e00c40 100644 --- a/packages/suite/src/utils/wallet/coinmarket/coinmarketUtils.ts +++ b/packages/suite/src/utils/wallet/coinmarket/coinmarketUtils.ts @@ -32,7 +32,7 @@ import { } from 'src/types/coinmarket/coinmarket'; import { v4 as uuidv4 } from 'uuid'; import { BigNumber } from '@trezor/utils'; -import { isTestnet, sortByCoin } from '@suite-common/wallet-utils'; +import { sortByCoin } from '@suite-common/wallet-utils'; export const cryptoPlatformSeparator = '--'; @@ -63,6 +63,14 @@ export function toTokenCryptoId(networkId: NetworkSymbol, contractAddress: strin return `${getCoingeckoId(networkId)}${cryptoPlatformSeparator}${contractAddress}` as CryptoId; } +/** Convert testnet cryptoId to prod cryptoId (test-bitcoin -> bitcoin) */ +export function testnetToProdCryptoId(cryptoId: CryptoId): CryptoId { + const { networkId, contractAddress } = parseCryptoId(cryptoId); + + return ((networkId.split('test-')?.[1] ?? networkId) + + (contractAddress ? `${cryptoPlatformSeparator}${contractAddress}` : '')) as CryptoId; +} + export const getNetworkName = (networkSymbol: NetworkSymbol) => { return networks[networkSymbol].name; }; @@ -320,7 +328,9 @@ export const coinmarketBuildAccountOptions = ({ accountType, } = account; - if (isTestnet(accountSymbol)) return; + if (!networks[accountSymbol].coingeckoNativeId) { + return; + } const groupLabel = accountLabels[account.key] ?? diff --git a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketAddressOptions.tsx b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketAddressOptions.tsx index 24d762b9a35..e1f91b4b154 100644 --- a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketAddressOptions.tsx +++ b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketAddressOptions.tsx @@ -16,6 +16,8 @@ import { spacingsPx, typography } from '@trezor/theme'; import { formatAmount } from '@suite-common/wallet-utils'; import { getNetworkDecimals } from 'src/utils/wallet/coinmarket/coinmarketUtils'; import { networks } from '@suite-common/wallet-config'; +import { useCoinmarketInfo } from 'src/hooks/wallet/coinmarket/useCoinmarketInfo'; +import { CryptoId } from 'invity-api'; const AddressWrapper = styled.div` display: flex; @@ -63,7 +65,7 @@ const buildOptions = (addresses: Account['addresses']) => { interface CoinmarketAddressOptionsProps extends Pick, 'setValue'> { control: Control; - receiveSymbol?: string; + receiveSymbol?: CryptoId; account?: Account; address?: string; menuPlacement?: MenuPlacement; @@ -86,6 +88,7 @@ export const CoinmarketAddressOptions = selectLabelingDataForAccount(state, account?.key || ''), ); + const { cryptoIdToCoinSymbol } = useCoinmarketInfo(); useEffect(() => { if (!address && addresses) { @@ -125,7 +128,7 @@ export const CoinmarketAddressOptions = diff --git a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketBalance.tsx b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketBalance.tsx index cedc9c5460f..b19dfea91ef 100644 --- a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketBalance.tsx +++ b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketBalance.tsx @@ -3,6 +3,7 @@ import { TokenAddress } from '@suite-common/wallet-types'; import { amountToSatoshi } from '@suite-common/wallet-utils'; import { typography } from '@trezor/theme'; import { FiatValue, HiddenPlaceholder, Translation } from 'src/components/suite'; +import { useFiatFromCryptoValue } from 'src/hooks/suite/useFiatFromCryptoValue'; import { useBitcoinAmountUnit } from 'src/hooks/wallet/useBitcoinAmountUnit'; import { coinmarketGetAccountLabel, @@ -41,6 +42,11 @@ export const CoinmarketBalance = ({ ? amountToSatoshi(stringBalance, networkDecimals) : stringBalance; + const { fiatAmount } = useFiatFromCryptoValue({ + amount: stringBalance || '', + symbol: networkSymbol || '', + }); + if (showOnlyAmount) { if (!balance ?? isNaN(Number(balance))) return null; @@ -53,6 +59,7 @@ export const CoinmarketBalance = ({ ) : ( stringBalance && + fiatAmount && networkSymbol && stringBalance !== '0' && ( {formattedBalance} {balanceCurrency} - {stringBalance && networkSymbol && stringBalance !== '0' && ( + {stringBalance && fiatAmount && networkSymbol && stringBalance !== '0' && ( <> {' '} ( diff --git a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketCoinLogo.tsx b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketCoinLogo.tsx index 02de056f157..4002397acf7 100644 --- a/packages/suite/src/views/wallet/coinmarket/common/CoinmarketCoinLogo.tsx +++ b/packages/suite/src/views/wallet/coinmarket/common/CoinmarketCoinLogo.tsx @@ -19,7 +19,7 @@ export const CoinmarketCoinLogo = ({ coingeckoId={networkId} contractAddress={contractAddress} size={size} - placeholder={networkId} + placeholder={networkId.toUpperCase()} margin={margin} /> diff --git a/suite-common/wallet-config/src/networksConfig.ts b/suite-common/wallet-config/src/networksConfig.ts index 0d7af8fdade..7df6c772ef3 100644 --- a/suite-common/wallet-config/src/networksConfig.ts +++ b/suite-common/wallet-config/src/networksConfig.ts @@ -471,7 +471,7 @@ export const networks = { }, }, coingeckoId: undefined, - coingeckoNativeId: undefined, + coingeckoNativeId: 'test-bitcoin', // fake, coingecko does not have testnets }, regtest: { symbol: 'regtest', @@ -568,7 +568,7 @@ export const networks = { customBackends: [], accountTypes: {}, coingeckoId: undefined, - coingeckoNativeId: undefined, + coingeckoNativeId: 'test-ripple', // fake, coingecko does not have testnets }, tada: { // icarus derivation