diff --git a/apps/browser-extension-wallet/src/hooks/useWalletActivities.ts b/apps/browser-extension-wallet/src/hooks/useWalletActivities.ts index 1c7820a732..366b5d7327 100644 --- a/apps/browser-extension-wallet/src/hooks/useWalletActivities.ts +++ b/apps/browser-extension-wallet/src/hooks/useWalletActivities.ts @@ -29,7 +29,6 @@ export const useWalletActivities = ({ const fetchWalletActivities = useCallback(async () => { fiatCurrency && - cardanoFiatPrice && getWalletActivities({ fiatCurrency, cardanoFiatPrice, @@ -141,7 +140,7 @@ export const useWalletActivitiesPaginated = ({ useEffect(() => { (async () => { - if (loadedHistory?.transactions === undefined || !fiatCurrency || !cardanoFiatPrice) return; + if (loadedHistory?.transactions === undefined || !fiatCurrency) return; handleUpdateWalletActivities(loadedHistory.transactions.slice(0, currentPage * pageSize)); })(); diff --git a/apps/browser-extension-wallet/src/lib/scripts/background/services/utilityServices.ts b/apps/browser-extension-wallet/src/lib/scripts/background/services/utilityServices.ts index 167378c322..af0977c1cd 100644 --- a/apps/browser-extension-wallet/src/lib/scripts/background/services/utilityServices.ts +++ b/apps/browser-extension-wallet/src/lib/scripts/background/services/utilityServices.ts @@ -180,7 +180,19 @@ const fetchAdaPrice = (coinPrices: CoinPrices) => { `https://coingecko.live-mainnet.eks.lw.iog.io/api/v3/simple/price?ids=cardano&vs_currencies=${vsCurrencies}&include_24hr_change=true` ) .then(async (response) => { - const { cardano: prices } = await response.json(); + // Check if the response is successful + if (!response.ok) { + throw new Error(`Failed to fetch ADA price: HTTP ${response.status}`); + } + + const responseData = await response.json(); + + // Check if we have valid cardano price data + if (!responseData.cardano) { + throw new Error('Invalid ADA price response: missing cardano data'); + } + + const { cardano: prices } = responseData; // save the last fetched ada price in background storage await setBackgroundStorage({ fiatPrices: { @@ -222,8 +234,20 @@ const fetchBitcoinPrice = (coinPrices: CoinPrices) => { `https://coingecko.live-mainnet.eks.lw.iog.io/api/v3/simple/price?ids=bitcoin&vs_currencies=${vsCurrencies}&include_24hr_change=true` ) .then(async (response) => { - const { bitcoin: prices } = await response.json(); - // save the last fetched ada price in background storage + // Check if the response is successful + if (!response.ok) { + throw new Error(`Failed to fetch Bitcoin price: HTTP ${response.status}`); + } + + const responseData = await response.json(); + + // Check if we have valid bitcoin price data + if (!responseData.bitcoin) { + throw new Error('Invalid Bitcoin price response: missing bitcoin data'); + } + + const { bitcoin: prices } = responseData; + // save the last fetched bitcoin price in background storage await setBackgroundStorage({ fiatBitcoinPrices: { prices, diff --git a/apps/browser-extension-wallet/src/utils/__tests__/assets-transformers.test.ts b/apps/browser-extension-wallet/src/utils/__tests__/assets-transformers.test.ts index bd48c4c8d7..cb480e6989 100644 --- a/apps/browser-extension-wallet/src/utils/__tests__/assets-transformers.test.ts +++ b/apps/browser-extension-wallet/src/utils/__tests__/assets-transformers.test.ts @@ -131,7 +131,7 @@ describe('Testing assets transformers', () => { balance: 'balance', price: 'formattedPrice', variation: 'variationParserResult', - fiatBalance: `- ${params.fiatCode}` + fiatBalance: '-' }); expect(formatNumberSpy).toBeCalledWith(params.fiatPrice?.price.toString(), 3); expect(walletBalanceTransformerSpy).toBeCalledWith(params.total.coins.toString(), params.fiatPrice?.price); @@ -189,7 +189,7 @@ describe('Testing assets transformers', () => { const isNumericSpy = jest.spyOn(formatNumber, 'isNumeric'); isNumericSpy.mockReturnValue(false); - expect(assetsTransformers.cardanoTransformer(params).fiatBalance).toEqual(`? ${params.fiatCode}`); + expect(assetsTransformers.cardanoTransformer(params).fiatBalance).toEqual('-'); expect(isNumericSpy).toBeCalledWith(walletBalanceTransformerResult.fiatBalance); isNumericSpy.mockRestore(); diff --git a/apps/browser-extension-wallet/src/utils/assets-transformers.ts b/apps/browser-extension-wallet/src/utils/assets-transformers.ts index 16a9e08769..d37c206eb5 100644 --- a/apps/browser-extension-wallet/src/utils/assets-transformers.ts +++ b/apps/browser-extension-wallet/src/utils/assets-transformers.ts @@ -32,8 +32,8 @@ export const cardanoTransformer = (params: { balance.fiatBalance === '-' ? balance.fiatBalance : isNumeric(balance.fiatBalance) - ? formatLocaleNumber(balance.fiatBalance) - : '?'; + ? `${formatLocaleNumber(balance.fiatBalance)} ${fiatCode}` + : '-'; return { id: cardanoCoin.id, @@ -44,7 +44,7 @@ export const cardanoTransformer = (params: { price: isNumber(fiatPrice?.price) ? formatLocaleNumber(fiatPrice.price.toString(), 3) : '-', variation: fiatPrice?.priceVariationPercentage24h ? variationParser(fiatPrice.priceVariationPercentage24h) : '-', balance: areBalancesVisible ? formatLocaleNumber(balance.coinBalance) : balancesPlaceholder, - fiatBalance: areBalancesVisible ? `${fiatBalance} ${fiatCode}` : balancesPlaceholder + fiatBalance: areBalancesVisible ? fiatBalance : balancesPlaceholder }; }; diff --git a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/activity/components/ActivityLayout.tsx b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/activity/components/ActivityLayout.tsx index ee8f1e46c8..20caf481bf 100644 --- a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/activity/components/ActivityLayout.tsx +++ b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/activity/components/ActivityLayout.tsx @@ -169,9 +169,9 @@ export const ActivityLayout = (): React.ReactElement => { ? 'PENDING' : formattedTimestamp(new Date(transaction.timestamp * 1000)), amount: `${new BigNumber(net.toString()).dividedBy(100_000_000).toFixed(8, BigNumber.ROUND_HALF_UP)} BTC`, - fiatAmount: `${computeBalance(Number(net) / SATS_IN_BTC, fiatCurrency.code, bitcoinPrice)} ${ - fiatCurrency.code === 'ADA' ? 'BTC' : fiatCurrency.code - }`, + fiatAmount: `${ + bitcoinPrice ? computeBalance(Number(net) / SATS_IN_BTC, fiatCurrency.code, bitcoinPrice) : '-' + } ${fiatCurrency.code === 'ADA' ? 'BTC' : fiatCurrency.code}`, status: transaction.status === Bitcoin.TransactionStatus.Pending ? ActivityStatus.PENDING : ActivityStatus.SUCCESS, type, diff --git a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/Assets.tsx b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/Assets.tsx index e92a314ca8..31ea48177f 100644 --- a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/Assets.tsx +++ b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/Assets.tsx @@ -96,7 +96,7 @@ export const Assets = ({ topSection }: AssetsProps): React.ReactElement => { variation: currencyCode === 'BTC' ? '-' : `${bitcoinPriceVariation.toFixed(2)}`, balance: areBalancesVisible ? (Number(balance) / SATS_IN_BTC).toString() : hiddenBalancePlaceholder, fiatBalance: areBalancesVisible - ? `${computeBalance(totalBalance, fiatCurrency.code, 1)} ${currencyCode}` + ? `${bitcoinPrice ? computeBalance(totalBalance, fiatCurrency.code, 1) : '-'} ${currencyCode}` : hiddenBalancePlaceholder } ] diff --git a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx index fbc9b1c785..69b31a11d4 100644 --- a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx +++ b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx @@ -85,13 +85,11 @@ export const AssetsPortfolio = ({ redirectToSend({ params: { id: '1' } }); }; - // Display banner after 3 minutes since last coin price save + // Display banner after 3 minutes since last coin price save or when there's an error const isPriceOutdated = useMemo( () => - // If there is no timestamp, that means that we never saved a previous price, so we just check if it has an error - coinPrice.status === 'error' && coinPrice.timestamp - ? dayjs().diff(coinPrice.timestamp, 'minutes') >= MINUTES_UNTIL_WARNING_BANNER - : coinPrice.status === 'error', + coinPrice.status === 'error' || + (coinPrice.timestamp && dayjs().diff(coinPrice.timestamp, 'minutes') >= MINUTES_UNTIL_WARNING_BANNER), [coinPrice] ); diff --git a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/ReviewTransaction.tsx b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/ReviewTransaction.tsx index f6dd4de42b..c538c50fe6 100644 --- a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/ReviewTransaction.tsx +++ b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/ReviewTransaction.tsx @@ -70,7 +70,7 @@ export const ReviewTransaction: React.FC = ({ weight={isPopupView ? '$medium' : '$semibold'} data-testid="output-summary-amount-fiat" > - {Number.parseFloat(usdValue.toFixed(2))} USD + {btcToUsdRate ? `${Number.parseFloat(usdValue.toFixed(2))} USD` : ''} diff --git a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/SendStepOne.tsx b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/SendStepOne.tsx index 8ac7f49ab5..14cc9c1903 100644 --- a/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/SendStepOne.tsx +++ b/apps/browser-extension-wallet/src/views/bitcoin-mode/features/send/components/SendStepOne.tsx @@ -188,7 +188,9 @@ export const SendStepOne: React.FC = ({ balance: `${t('browserView.transaction.btc.send.balance')}: ${(availableBalance / SATS_IN_BTC).toFixed(8)}` }; - const fiatValue = `≈ ${new BigNumber(enteredAmount.toString()).toFixed(2, BigNumber.ROUND_HALF_UP)} USD`; + const fiatValue = bitcoinPrice + ? `≈ ${new BigNumber(enteredAmount.toString()).toFixed(2, BigNumber.ROUND_HALF_UP)} USD` + : ''; const isAddressInputInvalidHandle = isAdaHandleEnabled && diff --git a/apps/browser-extension-wallet/src/views/browser-view/components/PortfolioBalance/PortfolioBalance.module.scss b/apps/browser-extension-wallet/src/views/browser-view/components/PortfolioBalance/PortfolioBalance.module.scss index f960abd74c..a88f7834da 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/components/PortfolioBalance/PortfolioBalance.module.scss +++ b/apps/browser-extension-wallet/src/views/browser-view/components/PortfolioBalance/PortfolioBalance.module.scss @@ -1,5 +1,5 @@ @import '../../../../../../../packages/common/src/ui/styles/theme.scss'; .warningBanner { - margin: size_unit(3) 0 -#{size_unit(3)} 0; + margin-top: size_unit(3); } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/ActivityDetail.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/ActivityDetail.tsx index 9f0fd03eea..dd260aaeb2 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/ActivityDetail.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/ActivityDetail.tsx @@ -130,7 +130,9 @@ export const ActivityDetail = ({ price }: ActivityDetailProps): ReactElement => : t(getTypeLabel(activityInfo.type)); const amountTransformer = (ada: string) => - `${Wallet.util.convertAdaToFiat({ ada, fiat: price?.cardano?.price })} ${fiatCurrency?.code}`; + `${price?.cardano?.price ? Wallet.util.convertAdaToFiat({ ada, fiat: price?.cardano?.price }) : '-'} ${ + fiatCurrency?.code + }`; if (activityInfo.type === TransactionActivityType.rewards) { return ( diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/Assets.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/Assets.tsx index f2228fc3d0..9138eeb241 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/Assets.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/Assets.tsx @@ -91,9 +91,9 @@ export const Assets = ({ topSection }: AssetsProps): React.ReactElement => { () => BigInt(utxoTotal?.coins || 0) + BigInt(lovelaceRewards || 0), [lovelaceRewards, utxoTotal] ); - // Wait for initial wallet's balance and price loading - const isLoadingFirstTime = !utxoTotal || !priceResult.cardano; + // Wait for initial wallet's balance and price loading + const isLoadingFirstTime = !utxoTotal; /** * Means it has more than 1 asset (ADA) in portfolio for Assets list that it's not an NFT. */ @@ -181,7 +181,7 @@ export const Assets = ({ topSection }: AssetsProps): React.ReactElement => { const totalWalletBalanceWithTokens = useMemo( () => getTotalWalletBalance( - balanceInAdaAndFiat?.total?.fiatBalance, + balanceInAdaAndFiat?.total?.fiatBalance || '0', priceResult.tokens, utxoTotal?.assets, priceResult?.cardano?.price || 0, diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx index 40f0ae01ad..bf994a58fe 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetsPortfolio/AssetsPortfolio.tsx @@ -83,13 +83,11 @@ export const AssetsPortfolio = ({ redirectToSend({ params: { id: '1' } }); }; - // Display banner after 3 minutes since last coin price save + // Display banner after 3 minutes since last coin price save or when there's an error const isPriceOutdated = useMemo( () => - // If there is no timestamp, that means that we never saved a previous price, so we just check if it has an error - coinPrice.status === 'error' && coinPrice.timestamp - ? dayjs().diff(coinPrice.timestamp, 'minutes') >= MINUTES_UNTIL_WARNING_BANNER - : coinPrice.status === 'error', + coinPrice.status === 'error' || + (coinPrice.timestamp && dayjs().diff(coinPrice.timestamp, 'minutes') >= MINUTES_UNTIL_WARNING_BANNER), [coinPrice] ); diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/Form/CoinInput/useSelectedCoins.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/Form/CoinInput/useSelectedCoins.tsx index a0f0944f5b..5f4cd748e3 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/Form/CoinInput/useSelectedCoins.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/Form/CoinInput/useSelectedCoins.tsx @@ -1,4 +1,4 @@ -/* eslint-disable complexity */ +/* eslint-disable complexity, sonarjs/cognitive-complexity */ import { Wallet } from '@lace/cardano'; import { AssetInputListProps, AssetInputProps } from '@lace/core'; import { @@ -193,10 +193,12 @@ export const useSelectedCoins = ({ assetInputItem?.value ?? '0', rewardAcountsData.lockedStakeRewards.toString() || '0' ); - const fiatValue = Wallet.util.convertAdaToFiat({ - ada: assetInputItem?.value || '0', - fiat: prices?.cardano?.price - }); + const fiatValue = prices?.cardano?.price + ? Wallet.util.convertAdaToFiat({ + ada: assetInputItem?.value || '0', + fiat: prices?.cardano?.price + }) + : ''; return { ...commonCoinProps, ...adaCoinProps, @@ -216,8 +218,8 @@ export const useSelectedCoins = ({ }) }) }, - formattedFiatValue: `≈ ${compactNumberWithUnit(fiatValue)} ${fiatCurrency?.code}`, - fiatValue: `≈ ${fiatValue} ${fiatCurrency?.code}`, + formattedFiatValue: fiatValue ? `≈ ${compactNumberWithUnit(fiatValue)} ${fiatCurrency?.code}` : '', + fiatValue: fiatValue ? `≈ ${fiatValue} ${fiatCurrency?.code}` : '', maxDecimals: cardanoCoin.decimals } as AssetInputListProps['rows'][number]; } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SendTransactionSummary.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SendTransactionSummary.tsx index 5cb9094dbb..df356d5a50 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SendTransactionSummary.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SendTransactionSummary.tsx @@ -36,14 +36,14 @@ export const getFee = ( if (!fee) return { ada: `0.00 ${cardanoCoin.symbol}`, - fiat: `0.00 ${fiatCurrency?.code}` + fiat: adaPrice ? `0.00 ${fiatCurrency?.code}` : '' }; const feeValue = walletBalanceTransformer(fee, adaPrice); return { ada: `${feeValue.coinBalance} ${cardanoCoin.symbol}`, - fiat: `${feeValue.fiatBalance} ${fiatCurrency?.code}` + fiat: adaPrice ? `${feeValue.fiatBalance} ${fiatCurrency?.code}` : '' }; }; diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SharedWalletSendTransactionSummary.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SharedWalletSendTransactionSummary.tsx index 421d5e2ebc..1250ee8dc5 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SharedWalletSendTransactionSummary.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/send-transaction/components/SharedWalletSendTransactionSummary.tsx @@ -62,7 +62,9 @@ const SharedWalletSendTransactionSummary = ({ rows, fee }: SharedWalletSendTrans }, [builtTxData.importedSharedWalletTx, coSigners]); const amountTransformer = (ada: string) => - `${Wallet.util.convertAdaToFiat({ ada, fiat: priceResult?.cardano?.price })} ${fiatCurrency?.code}`; + `${priceResult?.cardano?.price ? Wallet.util.convertAdaToFiat({ ada, fiat: priceResult.cardano.price }) : '-'} ${ + fiatCurrency?.code + }`; return ( (ada: string) => - `${Wallet.util.convertAdaToFiat({ ada, fiat: fiat.price })} ${fiat.code}`; + `${fiat.price ? Wallet.util.convertAdaToFiat({ ada, fiat: fiat.price }) : '-'} ${fiat.code}`; export interface DappTransactionProps { /** Transaction details such as type, amount, fee and address */