diff --git a/src/app/pages/swap/hooks/use-alex-sdk-fiat-price.tsx b/src/app/common/hooks/use-alex-sdk.ts
similarity index 79%
rename from src/app/pages/swap/hooks/use-alex-sdk-fiat-price.tsx
rename to src/app/common/hooks/use-alex-sdk.ts
index 067538e9df7..f7ab94e4785 100644
--- a/src/app/pages/swap/hooks/use-alex-sdk-fiat-price.tsx
+++ b/src/app/common/hooks/use-alex-sdk.ts
@@ -1,4 +1,4 @@
-import { Money, createMoney } from '@shared/models/money.model';
+import { type Money, createMoney } from '@shared/models/money.model';
import { isUndefined } from '@shared/utils';
import { useConvertAlexSdkCurrencyToFiatAmount } from '@app/common/hooks/use-convert-to-fiat-amount';
@@ -7,7 +7,6 @@ import { unitToFractionalUnit } from '@app/common/money/unit-conversion';
export function useAlexSdkAmountAsFiat(balance?: Money, price?: Money, value?: string) {
const convertAlexSdkCurrencyToUsd = useConvertAlexSdkCurrencyToFiatAmount(
- // @ts-expect-error TODO: balance?.symbol should be of a Cryptocurrency type.
balance?.symbol ?? '',
price ?? createMoney(0, 'USD')
);
@@ -23,7 +22,6 @@ export function useAlexSdkAmountAsFiat(balance?: Money, price?: Money, value?: s
export function useAlexSdkBalanceAsFiat(balance?: Money, price?: Money) {
const convertAlexSdkCurrencyToUsd = useConvertAlexSdkCurrencyToFiatAmount(
- // @ts-expect-error TODO: balance?.symbol should be of a Cryptocurrency type.
balance?.symbol ?? '',
price ?? createMoney(0, 'USD')
);
@@ -34,5 +32,7 @@ export function useAlexSdkBalanceAsFiat(balance?: Money, price?: Money) {
createMoney(balance.amount, balance.symbol, balance.decimals)
);
- return convertedBalanceAsMoney.amount.isNaN() ? '' : i18nFormatCurrency(convertedBalanceAsMoney);
+ return convertedBalanceAsMoney.amount.isNaN() || convertedBalanceAsMoney.amount.isEqualTo(0)
+ ? ''
+ : i18nFormatCurrency(convertedBalanceAsMoney);
}
diff --git a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx b/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
index d3034ebd737..22da0ca62bd 100644
--- a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
@@ -2,6 +2,7 @@ import { styled } from 'leather-styles/jsx';
import { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asset-balance.model';
+import { useAlexSdkBalanceAsFiat } from '@app/common/hooks/use-alex-sdk';
import { StacksAssetAvatar } from '@app/components/crypto-assets/stacks/components/stacks-asset-avatar';
import { ItemLayout } from '@app/ui/components/item-layout/item-layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
@@ -17,6 +18,7 @@ export function StacksFungibleTokenAssetItemLayout({
assetBalance,
onClick,
}: StacksFungibleTokenAssetItemLayoutProps) {
+ const balanceAsFiat = useAlexSdkBalanceAsFiat(assetBalance.balance, assetBalance.asset.price);
const { amount, avatar, caption, dataTestId, formattedBalance, imageCanonicalUri, title } =
parseStacksFungibleTokenAssetBalance(assetBalance);
@@ -45,6 +47,7 @@ export function StacksFungibleTokenAssetItemLayout({
}
+ captionRight={balanceAsFiat}
/>
);
diff --git a/src/app/features/asset-list/components/stacks-balance-list-item.tsx b/src/app/features/asset-list/components/stacks-balance-list-item.tsx
index a5f728565d6..3e804bf4e2a 100644
--- a/src/app/features/asset-list/components/stacks-balance-list-item.tsx
+++ b/src/app/features/asset-list/components/stacks-balance-list-item.tsx
@@ -6,6 +6,6 @@ interface StacksBalanceListItemProps {
address: string;
}
export function StacksBalanceListItem({ address }: StacksBalanceListItemProps) {
- const balaceDetails = useStxBalance();
- return ;
+ const balanceDetails = useStxBalance();
+ return ;
}
diff --git a/src/app/pages/fund/components/fund.layout.tsx b/src/app/pages/fund/components/fund.layout.tsx
index 8c5013f9b17..b6d20905ba6 100644
--- a/src/app/pages/fund/components/fund.layout.tsx
+++ b/src/app/pages/fund/components/fund.layout.tsx
@@ -1,27 +1,16 @@
import { Stack, styled } from 'leather-styles/jsx';
+import type { Blockchains } from '@shared/models/blockchain.model';
import { CryptoCurrencies } from '@shared/models/currencies.model';
import { HasChildren } from '@app/common/has-children';
-
-const nameMap: Record = {
- BTC: {
- name: 'Bitcoin',
- symbol: 'BTC',
- },
- STX: {
- name: 'Stacks',
- symbol: 'STX',
- },
-};
+import { capitalize } from '@app/common/utils';
interface FundLayoutProps extends HasChildren {
+ blockchain: Blockchains;
symbol: CryptoCurrencies;
}
-
-export function FundLayout({ symbol, children }: FundLayoutProps) {
- const name = nameMap[symbol].name;
- const nameAbbr = nameMap[symbol].symbol;
+export function FundLayout({ blockchain, symbol, children }: FundLayoutProps) {
return (
- Choose an exchange to fund your account with {name} ({nameAbbr}) or deposit from elsewhere.
- Exchanges with “Fast checkout” make it easier to purchase {nameAbbr} for direct deposit into
- your wallet with a credit card.
+ Choose an exchange to fund your account with {capitalize(blockchain)} ({symbol}) or deposit
+ from elsewhere. Exchanges with “Fast checkout” make it easier to purchase {symbol} for
+ direct deposit into your wallet with a credit card.
{children}
diff --git a/src/app/pages/fund/fund.tsx b/src/app/pages/fund/fund.tsx
index 1dfdf95e892..a3dd5f32b78 100644
--- a/src/app/pages/fund/fund.tsx
+++ b/src/app/pages/fund/fund.tsx
@@ -1,7 +1,5 @@
import { Outlet, useParams } from 'react-router-dom';
-import { isCryptoCurrency } from '@shared/models/currencies.model';
-
import { useBtcCryptoCurrencyAssetBalance } from '@app/common/hooks/balance/btc/use-btc-crypto-currency-asset-balance';
import { useStxCryptoCurrencyAssetBalance } from '@app/common/hooks/balance/stx/use-stx-crypto-currency-asset-balance';
import { FullPageLoadingSpinner } from '@app/components/loading-spinner';
@@ -18,37 +16,26 @@ export function FundPage() {
const stxCryptoCurrencyAssetBalance = useStxCryptoCurrencyAssetBalance();
const { currency } = useParams();
- function getSymbol() {
- if (isCryptoCurrency(currency)) {
- return currency;
- }
- return 'STX';
- }
- function getAddress() {
- switch (symbol) {
- case 'BTC':
- return bitcoinSigner?.address;
- case 'STX':
- return currentStxAccount?.address;
- }
- }
- function getBalance() {
- switch (symbol) {
- case 'BTC':
- return btcCryptoCurrencyAssetBalance;
- case 'STX':
- return stxCryptoCurrencyAssetBalance;
- }
- }
-
- const symbol = getSymbol();
- const address = getAddress();
- const balance = getBalance();
+ const { address, balance, blockchain, symbol } =
+ currency === 'BTC'
+ ? {
+ address: bitcoinSigner?.address,
+ balance: btcCryptoCurrencyAssetBalance,
+ blockchain: 'Bitcoin',
+ symbol: currency,
+ }
+ : {
+ address: currentStxAccount?.address,
+ balance: stxCryptoCurrencyAssetBalance,
+ blockchain: 'Stacks',
+ symbol: 'STX',
+ };
if (!address || !balance) return ;
+
return (
<>
-
+
diff --git a/src/app/pages/swap/components/swap-choose-asset/components/swap-asset-item.tsx b/src/app/pages/swap/components/swap-choose-asset/components/swap-asset-item.tsx
index 7fabdbcd131..8e56372da2b 100644
--- a/src/app/pages/swap/components/swap-choose-asset/components/swap-asset-item.tsx
+++ b/src/app/pages/swap/components/swap-choose-asset/components/swap-asset-item.tsx
@@ -1,15 +1,14 @@
import { SwapSelectors } from '@tests/selectors/swap.selectors';
+import { useAlexSdkBalanceAsFiat } from '@app/common/hooks/use-alex-sdk';
import { formatMoneyWithoutSymbol } from '@app/common/money/format-money';
+import type { SwapAsset } from '@app/pages/swap/hooks/use-swap-form';
import { useGetFungibleTokenMetadataQuery } from '@app/query/stacks/tokens/fungible-tokens/fungible-token-metadata.query';
import { isFtAsset } from '@app/query/stacks/tokens/token-metadata.utils';
import { Avatar, defaultFallbackDelay, getAvatarFallback } from '@app/ui/components/avatar/avatar';
import { ItemLayout } from '@app/ui/components/item-layout/item-layout';
import { Pressable } from '@app/ui/pressable/pressable';
-import { useAlexSdkBalanceAsFiat } from '../../../hooks/use-alex-sdk-fiat-price';
-import { SwapAsset } from '../../../hooks/use-swap-form';
-
interface SwapAssetItemProps {
asset: SwapAsset;
onClick(): void;
diff --git a/src/app/pages/swap/components/swap-selected-asset-from.tsx b/src/app/pages/swap/components/swap-selected-asset-from.tsx
index 3a493dadef4..7dac171bcff 100644
--- a/src/app/pages/swap/components/swap-selected-asset-from.tsx
+++ b/src/app/pages/swap/components/swap-selected-asset-from.tsx
@@ -5,10 +5,10 @@ import { createMoney } from '@shared/models/money.model';
import { isUndefined } from '@shared/utils';
import { useShowFieldError } from '@app/common/form-utils';
+import { useAlexSdkAmountAsFiat } from '@app/common/hooks/use-alex-sdk';
import { convertAmountToFractionalUnit } from '@app/common/money/calculate-money';
import { formatMoneyWithoutSymbol } from '@app/common/money/format-money';
-import { useAlexSdkAmountAsFiat } from '../hooks/use-alex-sdk-fiat-price';
import { SwapFormValues } from '../hooks/use-swap-form';
import { useSwapContext } from '../swap.context';
import { SwapAmountField } from './swap-amount-field';
diff --git a/src/app/pages/swap/components/swap-selected-asset-to.tsx b/src/app/pages/swap/components/swap-selected-asset-to.tsx
index 7e2c94f7049..284f9e0b823 100644
--- a/src/app/pages/swap/components/swap-selected-asset-to.tsx
+++ b/src/app/pages/swap/components/swap-selected-asset-to.tsx
@@ -1,9 +1,9 @@
import { useField } from 'formik';
+import { useAlexSdkAmountAsFiat } from '@app/common/hooks/use-alex-sdk';
import { formatMoneyWithoutSymbol } from '@app/common/money/format-money';
import { LoadingSpinner } from '@app/components/loading-spinner';
-import { useAlexSdkAmountAsFiat } from '../hooks/use-alex-sdk-fiat-price';
import { useSwapContext } from '../swap.context';
import { SwapAmountField } from './swap-amount-field';
import { SwapSelectedAssetLayout } from './swap-selected-asset.layout';
diff --git a/src/app/pages/swap/hooks/use-alex-swap.tsx b/src/app/pages/swap/hooks/use-alex-swap.tsx
index 21f95a8bd08..e7aec796460 100644
--- a/src/app/pages/swap/hooks/use-alex-swap.tsx
+++ b/src/app/pages/swap/hooks/use-alex-swap.tsx
@@ -1,5 +1,4 @@
import { useCallback, useState } from 'react';
-import { useAsync } from 'react-async-hook';
import { AlexSDK, Currency, TokenInfo } from 'alex-sdk';
import BigNumber from 'bignumber.js';
@@ -10,7 +9,8 @@ import { createMoney } from '@shared/models/money.model';
import { useStxBalance } from '@app/common/hooks/balance/stx/use-stx-balance';
import { convertAmountToFractionalUnit } from '@app/common/money/calculate-money';
import { pullContractIdFromIdentity } from '@app/common/utils';
-import { useSwappableCurrencyQuery } from '@app/query/common/alex-swaps/swappable-currency.query';
+import { useAlexSdkLatestPricesQuery } from '@app/query/common/alex-sdk/latest-prices.query';
+import { useAlexSdkSwappableCurrencyQuery } from '@app/query/common/alex-sdk/swappable-currency.query';
import { useTransferableStacksFungibleTokenAssetBalances } from '@app/query/stacks/balance/stacks-ft-balances.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
@@ -24,8 +24,8 @@ export function useAlexSwap() {
const [swapSubmissionData, setSwapSubmissionData] = useState();
const [slippage, _setSlippage] = useState(0.04);
const [isFetchingExchangeRate, setIsFetchingExchangeRate] = useState(false);
- const { data: supportedCurrencies = [] } = useSwappableCurrencyQuery(alexSDK);
- const { result: prices } = useAsync(async () => await alexSDK.getLatestPrices(), [alexSDK]);
+ const { data: supportedCurrencies = [] } = useAlexSdkSwappableCurrencyQuery(alexSDK);
+ const { data: prices } = useAlexSdkLatestPricesQuery(alexSDK);
const { availableBalance: availableStxBalance } = useStxBalance();
const account = useCurrentStacksAccount();
const stacksFtAssetBalances = useTransferableStacksFungibleTokenAssetBalances(
diff --git a/src/app/query/common/alex-sdk/alex-sdk.hooks.ts b/src/app/query/common/alex-sdk/alex-sdk.hooks.ts
new file mode 100644
index 00000000000..3e0fe7e4953
--- /dev/null
+++ b/src/app/query/common/alex-sdk/alex-sdk.hooks.ts
@@ -0,0 +1,36 @@
+import { useCallback, useState } from 'react';
+
+import { AlexSDK, type Currency } from 'alex-sdk';
+import BigNumber from 'bignumber.js';
+
+import { logger } from '@shared/logger';
+import { createMoney } from '@shared/models/money.model';
+import { isDefined } from '@shared/utils';
+
+import { convertAmountToFractionalUnit } from '@app/common/money/calculate-money';
+import { pullContractIdFromIdentity } from '@app/common/utils';
+
+import { useAlexSdkLatestPricesQuery } from './latest-prices.query';
+import { useAlexSdkSwappableCurrencyQuery } from './swappable-currency.query';
+
+export function useAlexSdKCurrencyPriceAsMoney() {
+ const alexSDK = useState(() => new AlexSDK())[0];
+ const { data: supportedCurrencies = [] } = useAlexSdkSwappableCurrencyQuery(alexSDK);
+ const { data: prices } = useAlexSdkLatestPricesQuery(alexSDK);
+
+ return useCallback(
+ (principal: string) => {
+ if (!prices) {
+ logger.error('Latest prices could not be found');
+ return createMoney(0, 'USD');
+ }
+ const tokenInfo = supportedCurrencies
+ .filter(isDefined)
+ .find(token => pullContractIdFromIdentity(token.contractAddress) === principal);
+ const currency = tokenInfo?.id as Currency;
+ const price = convertAmountToFractionalUnit(new BigNumber(prices[currency] ?? 0), 2);
+ return createMoney(price, 'USD');
+ },
+ [prices, supportedCurrencies]
+ );
+}
diff --git a/src/app/query/common/alex-sdk/latest-prices.query.ts b/src/app/query/common/alex-sdk/latest-prices.query.ts
new file mode 100644
index 00000000000..992a3dbe624
--- /dev/null
+++ b/src/app/query/common/alex-sdk/latest-prices.query.ts
@@ -0,0 +1,12 @@
+import { useQuery } from '@tanstack/react-query';
+import { AlexSDK } from 'alex-sdk';
+
+export function useAlexSdkLatestPricesQuery(alexSDK: AlexSDK) {
+ return useQuery(['alex-sdk-latest-prices'], async () => alexSDK.getLatestPrices(), {
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ refetchOnWindowFocus: false,
+ retryDelay: 1000 * 60,
+ staleTime: 1000 * 60 * 10,
+ });
+}
diff --git a/src/app/query/common/alex-sdk/swappable-currency.query.ts b/src/app/query/common/alex-sdk/swappable-currency.query.ts
new file mode 100644
index 00000000000..3b7f5149fdb
--- /dev/null
+++ b/src/app/query/common/alex-sdk/swappable-currency.query.ts
@@ -0,0 +1,12 @@
+import { useQuery } from '@tanstack/react-query';
+import { AlexSDK } from 'alex-sdk';
+
+export function useAlexSdkSwappableCurrencyQuery(alexSDK: AlexSDK) {
+ return useQuery(['alex-sdk-swappable-currencies'], async () => alexSDK.fetchSwappableCurrency(), {
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ refetchOnWindowFocus: false,
+ retryDelay: 1000 * 60,
+ staleTime: 1000 * 60 * 10,
+ });
+}
diff --git a/src/app/query/common/alex-swaps/swappable-currency.query.ts b/src/app/query/common/alex-swaps/swappable-currency.query.ts
deleted file mode 100644
index 415bbcc09df..00000000000
--- a/src/app/query/common/alex-swaps/swappable-currency.query.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { useQuery } from '@tanstack/react-query';
-import { AlexSDK } from 'alex-sdk';
-
-export function useSwappableCurrencyQuery(alexSDK: AlexSDK) {
- return useQuery(
- ['alex-supported-swap-currencies'],
- async () => alexSDK.fetchSwappableCurrency(),
- {
- refetchOnMount: false,
- refetchOnReconnect: false,
- refetchOnWindowFocus: false,
- retryDelay: 1000 * 60,
- staleTime: 1000 * 60 * 10,
- }
- );
-}
diff --git a/src/app/query/stacks/balance/stacks-ft-balances.hooks.ts b/src/app/query/stacks/balance/stacks-ft-balances.hooks.ts
index f7059f30df3..1dcd2a36d37 100644
--- a/src/app/query/stacks/balance/stacks-ft-balances.hooks.ts
+++ b/src/app/query/stacks/balance/stacks-ft-balances.hooks.ts
@@ -7,6 +7,7 @@ import type { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asse
import { formatContractId } from '@app/common/utils';
import { useToast } from '@app/features/toasts/use-toast';
+import { useAlexSdKCurrencyPriceAsMoney } from '@app/query/common/alex-sdk/alex-sdk.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useGetFungibleTokenMetadataListQuery } from '../tokens/fungible-tokens/fungible-token-metadata.query';
@@ -35,6 +36,7 @@ function useStacksFungibleTokenAssetBalances(address: string) {
export function useStacksFungibleTokenAssetBalancesWithMetadata(address: string) {
const { data: initializedAssetBalances = [] } = useStacksFungibleTokenAssetBalances(address);
+ const priceAsMoney = useAlexSdKCurrencyPriceAsMoney();
const ftAssetsMetadata = useGetFungibleTokenMetadataListQuery(
initializedAssetBalances.map(assetBalance =>
@@ -49,7 +51,10 @@ export function useStacksFungibleTokenAssetBalancesWithMetadata(address: string)
if (!(metadata && isFtAsset(metadata))) return assetBalance;
return addQueriedMetadataToInitializedStacksFungibleTokenAssetBalance(
assetBalance,
- metadata
+ metadata,
+ priceAsMoney(
+ formatContractId(assetBalance.asset.contractAddress, assetBalance.asset.contractName)
+ )
);
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/src/app/query/stacks/balance/stacks-ft-balances.utils.ts b/src/app/query/stacks/balance/stacks-ft-balances.utils.ts
index b93f7bd0211..de6d494fb23 100644
--- a/src/app/query/stacks/balance/stacks-ft-balances.utils.ts
+++ b/src/app/query/stacks/balance/stacks-ft-balances.utils.ts
@@ -7,7 +7,7 @@ import type {
StacksCryptoCurrencyAssetBalance,
StacksFungibleTokenAssetBalance,
} from '@shared/models/crypto-asset-balance.model';
-import { createMoney } from '@shared/models/money.model';
+import { type Money, createMoney } from '@shared/models/money.model';
import { isTransferableStacksFungibleTokenAsset } from '@app/common/crypto-assets/stacks-crypto-asset.utils';
import { getAssetStringParts } from '@app/ui/utils/get-asset-string-parts';
@@ -47,6 +47,7 @@ export function createStacksFtCryptoAssetBalanceTypeWrapper(
hasMemo: false,
imageCanonicalUri: '',
name: '',
+ price: createMoney(0, 'USD'),
symbol: '',
},
};
@@ -68,7 +69,8 @@ export function convertFtBalancesToStacksFungibleTokenAssetBalanceType(
export function addQueriedMetadataToInitializedStacksFungibleTokenAssetBalance(
assetBalance: StacksFungibleTokenAssetBalance,
- metadata: FtMetadataResponse
+ metadata: FtMetadataResponse,
+ price: Money
) {
return {
...assetBalance,
@@ -84,6 +86,7 @@ export function addQueriedMetadataToInitializedStacksFungibleTokenAssetBalance(
hasMemo: isTransferableStacksFungibleTokenAsset(assetBalance.asset),
imageCanonicalUri: metadata.image_canonical_uri ?? '',
name: metadata.name ?? '',
+ price,
symbol: metadata.symbol ?? '',
},
};
diff --git a/src/shared/models/crypto-asset.model.ts b/src/shared/models/crypto-asset.model.ts
index 057282fc6c0..a2d8f9b9a33 100644
--- a/src/shared/models/crypto-asset.model.ts
+++ b/src/shared/models/crypto-asset.model.ts
@@ -1,3 +1,5 @@
+import type { Money } from './money.model';
+
export interface BitcoinCryptoCurrencyAsset {
decimals: number;
hasMemo: boolean;
@@ -22,6 +24,7 @@ export interface StacksFungibleTokenAsset {
hasMemo: boolean;
imageCanonicalUri: string;
name: string;
+ price: Money;
symbol: string;
}
diff --git a/src/shared/models/currencies.model.ts b/src/shared/models/currencies.model.ts
index 115968881a5..ffbdfdf0045 100644
--- a/src/shared/models/currencies.model.ts
+++ b/src/shared/models/currencies.model.ts
@@ -1,9 +1,6 @@
-const CRYPTO_CURRENCIES_ARRAY = ['BTC', 'STX'] as const;
+import type { LiteralUnion } from 'leather-styles/types';
-export type CryptoCurrencies = (typeof CRYPTO_CURRENCIES_ARRAY)[number];
-
-export const isCryptoCurrency = (value: unknown): value is CryptoCurrencies =>
- CRYPTO_CURRENCIES_ARRAY.some(cryptocurrency => cryptocurrency === value);
+export type CryptoCurrencies = LiteralUnion<'BTC' | 'STX', string>;
export type FiatCurrencies = 'USD' | string;