diff --git a/src/app/common/crypto-assets/stacks-crypto-asset.utils.spec.ts b/src/app/common/crypto-assets/stacks-crypto-asset.utils.spec.ts
index 1def2e0bb81..ae948f06fa1 100644
--- a/src/app/common/crypto-assets/stacks-crypto-asset.utils.spec.ts
+++ b/src/app/common/crypto-assets/stacks-crypto-asset.utils.spec.ts
@@ -1,4 +1,5 @@
import { StacksFungibleTokenAsset } from '@shared/models/crypto-asset.model';
+import { createMoney } from '@shared/models/money.model';
import {
isFtNameLikeStx,
@@ -31,6 +32,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
+ price: createMoney(0, 'USD'),
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
@@ -47,6 +49,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
+ price: createMoney(0, 'USD'),
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
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 62%
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..bb69ed7386f 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,32 +7,32 @@ 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')
);
- if (isUndefined(balance) || isUndefined(price) || isUndefined(value)) return '';
+ if (isUndefined(balance) || isUndefined(price) || isUndefined(value)) return;
const convertedAmountAsMoney = convertAlexSdkCurrencyToUsd(
createMoney(unitToFractionalUnit(balance.decimals)(value), balance.symbol, balance.decimals)
);
- return convertedAmountAsMoney.amount.isNaN() ? '' : i18nFormatCurrency(convertedAmountAsMoney);
+ if (convertedAmountAsMoney.amount.isNaN()) return;
+ return i18nFormatCurrency(convertedAmountAsMoney);
}
-export function useAlexSdkBalanceAsFiat(balance?: Money, price?: Money) {
+export function useAlexSdkBalanceAsFiat(balance: Money, price?: Money | null) {
const convertAlexSdkCurrencyToUsd = useConvertAlexSdkCurrencyToFiatAmount(
- // @ts-expect-error TODO: balance?.symbol should be of a Cryptocurrency type.
- balance?.symbol ?? '',
+ balance.symbol,
price ?? createMoney(0, 'USD')
);
- if (isUndefined(balance) || isUndefined(price)) return '';
+ if (isUndefined(balance) || isUndefined(price)) return;
const convertedBalanceAsMoney = convertAlexSdkCurrencyToUsd(
createMoney(balance.amount, balance.symbol, balance.decimals)
);
- return convertedBalanceAsMoney.amount.isNaN() ? '' : i18nFormatCurrency(convertedBalanceAsMoney);
+ if (convertedBalanceAsMoney.amount.isNaN() || convertedBalanceAsMoney.amount.isEqualTo(0)) return;
+ return 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 644eb3b000f..3106f3e1d68 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 8cb7bf8a39a..bab8510c5b7 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,12 +6,12 @@ interface StacksBalanceListItemProps {
address: string;
}
export function StacksBalanceListItem({ address }: StacksBalanceListItemProps) {
- const balaceDetails = useStxBalance();
+ 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..983b4309347 100644
--- a/src/app/pages/fund/components/fund.layout.tsx
+++ b/src/app/pages/fund/components/fund.layout.tsx
@@ -1,27 +1,15 @@
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',
- },
-};
-
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{' '}
+ {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/fiat-providers-list.tsx b/src/app/pages/fund/fiat-providers-list.tsx
index 446abe09cf3..3df29a146a5 100644
--- a/src/app/pages/fund/fiat-providers-list.tsx
+++ b/src/app/pages/fund/fiat-providers-list.tsx
@@ -1,10 +1,8 @@
-import { useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Grid } from 'leather-styles/jsx';
import { CryptoCurrencies } from '@shared/models/currencies.model';
-import { RouteUrls } from '@shared/route-urls';
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
@@ -20,25 +18,17 @@ import { ReceiveFundsItem } from './components/receive-funds-item';
interface FiatProvidersProps {
address: string;
+ route: string;
symbol: CryptoCurrencies;
}
export function FiatProvidersList(props: FiatProvidersProps) {
- const { address, symbol } = props;
+ const { address, route, symbol } = props;
const navigate = useNavigate();
const activeProviders = useActiveFiatProviders();
const hasProviders = useHasFiatProviders();
const analytics = useAnalytics();
const location = useLocation();
- const routeToQr = useMemo(() => {
- switch (symbol) {
- case 'BTC':
- return RouteUrls.ReceiveBtc;
- case 'STX':
- return RouteUrls.ReceiveStx;
- }
- }, [symbol]);
-
const goToProviderExternalWebsite = (provider: string, providerUrl: string) => {
void analytics.track('select_buy_option', { provider });
openInNewTab(providerUrl);
@@ -56,7 +46,7 @@ export function FiatProvidersList(props: FiatProvidersProps) {
- navigate(routeToQr, {
+ navigate(route, {
state: { backgroundLocation: location },
})
}
diff --git a/src/app/pages/fund/fund.tsx b/src/app/pages/fund/fund.tsx
index 1dfdf95e892..68bb064d802 100644
--- a/src/app/pages/fund/fund.tsx
+++ b/src/app/pages/fund/fund.tsx
@@ -1,6 +1,12 @@
import { Outlet, useParams } from 'react-router-dom';
-import { isCryptoCurrency } from '@shared/models/currencies.model';
+import type { Blockchains } from '@shared/models/blockchain.model';
+import type {
+ BitcoinCryptoCurrencyAssetBalance,
+ StacksCryptoCurrencyAssetBalance,
+} from '@shared/models/crypto-asset-balance.model';
+import type { CryptoCurrencies } from '@shared/models/currencies.model';
+import { RouteUrls } from '@shared/route-urls';
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';
@@ -11,45 +17,47 @@ import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/s
import { FundLayout } from './components/fund.layout';
import { FiatProvidersList } from './fiat-providers-list';
+interface FundCryptoCurrencyInfo {
+ address?: string;
+ balance?: BitcoinCryptoCurrencyAssetBalance | StacksCryptoCurrencyAssetBalance;
+ blockchain: Blockchains;
+ route: string;
+ symbol: CryptoCurrencies;
+}
+
export function FundPage() {
const currentStxAccount = useCurrentStacksAccount();
const bitcoinSigner = useCurrentAccountNativeSegwitIndexZeroSignerNullable();
const btcCryptoCurrencyAssetBalance = useBtcCryptoCurrencyAssetBalance();
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 { currency = 'STX' } = useParams();
+
+ const fundCryptoCurrencyMap: Record = {
+ BTC: {
+ address: bitcoinSigner?.address,
+ balance: btcCryptoCurrencyAssetBalance?.btcBalance,
+ blockchain: 'Bitcoin',
+ route: RouteUrls.ReceiveBtc,
+ symbol: currency,
+ },
+ STX: {
+ address: currentStxAccount?.address,
+ balance: stxCryptoCurrencyAssetBalance,
+ blockchain: 'Stacks',
+ route: RouteUrls.ReceiveStx,
+ symbol: currency,
+ },
+ };
+
+ const { address, balance, blockchain, route, symbol } =
+ fundCryptoCurrencyMap[currency as CryptoCurrencies];
if (!address || !balance) return ;
+
return (
<>
-
-
+
+
>
diff --git a/src/app/pages/swap/alex-swap-container.tsx b/src/app/pages/swap/alex-swap-container.tsx
index a86d90648f9..0107298857c 100644
--- a/src/app/pages/swap/alex-swap-container.tsx
+++ b/src/app/pages/swap/alex-swap-container.tsx
@@ -14,6 +14,7 @@ import BigNumber from 'bignumber.js';
import { logger } from '@shared/logger';
import { RouteUrls } from '@shared/route-urls';
import { isDefined, isUndefined } from '@shared/utils';
+import { alex } from '@shared/utils/alex-sdk';
import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading';
import { useWalletType } from '@app/common/use-wallet-type';
@@ -55,7 +56,6 @@ function AlexSwapContainer() {
});
const {
- alexSDK,
fetchToAmount,
createSwapAssetFromAlexCurrency,
isFetchingExchangeRate,
@@ -66,7 +66,7 @@ function AlexSwapContainer() {
swapSubmissionData,
} = useAlexSwap();
- const broadcastAlexSwap = useAlexBroadcastSwap(alexSDK);
+ const broadcastAlexSwap = useAlexBroadcastSwap();
const broadcastStacksSwap = useStacksBroadcastSwap();
const swappableAssets: SwapAsset[] = useMemo(
@@ -84,8 +84,8 @@ function AlexSwapContainer() {
}
const [router, lpFee] = await Promise.all([
- alexSDK.getRouter(values.swapAssetFrom.currency, values.swapAssetTo.currency),
- alexSDK.getFeeRate(values.swapAssetFrom.currency, values.swapAssetTo.currency),
+ alex.getRouter(values.swapAssetFrom.currency, values.swapAssetTo.currency),
+ alex.getFeeRate(values.swapAssetFrom.currency, values.swapAssetTo.currency),
]);
onSetSwapSubmissionData({
@@ -141,7 +141,7 @@ function AlexSwapContainer() {
.toString()
);
- const tx = alexSDK.runSwap(
+ const tx = alex.runSwap(
currentAccount?.address,
swapSubmissionData.swapAssetFrom.currency,
swapSubmissionData.swapAssetTo.currency,
diff --git a/src/app/pages/swap/components/swap-amount-field.tsx b/src/app/pages/swap/components/swap-amount-field.tsx
index dbd0a5e5425..c747ba8d336 100644
--- a/src/app/pages/swap/components/swap-amount-field.tsx
+++ b/src/app/pages/swap/components/swap-amount-field.tsx
@@ -22,7 +22,7 @@ function getPlaceholderValue(name: string, values: SwapFormValues) {
}
interface SwapAmountFieldProps {
- amountAsFiat: string;
+ amountAsFiat?: string;
isDisabled?: boolean;
name: string;
}
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-broadcast-swap.ts b/src/app/pages/swap/hooks/use-alex-broadcast-swap.ts
index efc5eaafbb1..df4b7814b82 100644
--- a/src/app/pages/swap/hooks/use-alex-broadcast-swap.ts
+++ b/src/app/pages/swap/hooks/use-alex-broadcast-swap.ts
@@ -1,22 +1,23 @@
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
-import { AlexSDK, SponsoredTxError } from 'alex-sdk';
+import { SponsoredTxError } from 'alex-sdk';
import { logger } from '@shared/logger';
import { RouteUrls } from '@shared/route-urls';
import { delay } from '@shared/utils';
+import { alex } from '@shared/utils/alex-sdk';
import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading';
-export function useAlexBroadcastSwap(alexSDK: AlexSDK) {
+export function useAlexBroadcastSwap() {
const { setIsIdle } = useLoading(LoadingKeys.SUBMIT_SWAP_TRANSACTION);
const navigate = useNavigate();
return useCallback(
async (txRaw: string) => {
try {
- const txId = await alexSDK.broadcastSponsoredTx(txRaw);
+ const txId = await alex.broadcastSponsoredTx(txRaw);
logger.info('transaction:', txId);
await delay(1000);
setIsIdle();
@@ -31,6 +32,6 @@ export function useAlexBroadcastSwap(alexSDK: AlexSDK) {
});
}
},
- [alexSDK, navigate, setIsIdle]
+ [navigate, setIsIdle]
);
}
diff --git a/src/app/pages/swap/hooks/use-alex-swap.tsx b/src/app/pages/swap/hooks/use-alex-swap.tsx
index 21f95a8bd08..71034ec39c5 100644
--- a/src/app/pages/swap/hooks/use-alex-swap.tsx
+++ b/src/app/pages/swap/hooks/use-alex-swap.tsx
@@ -1,16 +1,17 @@
import { useCallback, useState } from 'react';
-import { useAsync } from 'react-async-hook';
-import { AlexSDK, Currency, TokenInfo } from 'alex-sdk';
+import { Currency, TokenInfo } from 'alex-sdk';
import BigNumber from 'bignumber.js';
import { logger } from '@shared/logger';
import { createMoney } from '@shared/models/money.model';
+import { alex } from '@shared/utils/alex-sdk';
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';
@@ -20,12 +21,11 @@ import { SwapAsset } from './use-swap-form';
export const oneHundredMillion = 100_000_000;
export function useAlexSwap() {
- const alexSDK = useState(() => new AlexSDK())[0];
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();
+ const { data: prices } = useAlexSdkLatestPricesQuery();
const { availableBalance: availableStxBalance } = useStxBalance();
const account = useCurrentStacksAccount();
const stacksFtAssetBalances = useTransferableStacksFungibleTokenAssetBalances(
@@ -79,7 +79,7 @@ export function useAlexSwap() {
const amountAsBigInt = isNaN(Number(amount)) ? BigInt(0) : BigInt(amount);
try {
setIsFetchingExchangeRate(true);
- const result = await alexSDK.getAmountTo(from.currency, amountAsBigInt, to.currency);
+ const result = await alex.getAmountTo(from.currency, amountAsBigInt, to.currency);
setIsFetchingExchangeRate(false);
return new BigNumber(Number(result)).dividedBy(oneHundredMillion).toString();
} catch (e) {
@@ -90,7 +90,6 @@ export function useAlexSwap() {
}
return {
- alexSDK,
fetchToAmount,
createSwapAssetFromAlexCurrency,
isFetchingExchangeRate,
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..5add887bfbf
--- /dev/null
+++ b/src/app/query/common/alex-sdk/alex-sdk.hooks.ts
@@ -0,0 +1,35 @@
+import { useCallback } from 'react';
+
+import { 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 { data: supportedCurrencies = [] } = useAlexSdkSwappableCurrencyQuery();
+ const { data: prices } = useAlexSdkLatestPricesQuery();
+
+ return useCallback(
+ (principal: string) => {
+ if (!prices) {
+ logger.error('Latest prices could not be found');
+ return null;
+ }
+ 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..2cc29031120
--- /dev/null
+++ b/src/app/query/common/alex-sdk/latest-prices.query.ts
@@ -0,0 +1,13 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { alex } from '@shared/utils/alex-sdk';
+
+export function useAlexSdkLatestPricesQuery() {
+ return useQuery(['alex-sdk-latest-prices'], async () => alex.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..792b60b603e
--- /dev/null
+++ b/src/app/query/common/alex-sdk/swappable-currency.query.ts
@@ -0,0 +1,13 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { alex } from '@shared/utils/alex-sdk';
+
+export function useAlexSdkSwappableCurrencyQuery() {
+ return useQuery(['alex-sdk-swappable-currencies'], async () => alex.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..159d0af3409 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: null,
symbol: '',
},
};
@@ -68,7 +69,8 @@ export function convertFtBalancesToStacksFungibleTokenAssetBalanceType(
export function addQueriedMetadataToInitializedStacksFungibleTokenAssetBalance(
assetBalance: StacksFungibleTokenAssetBalance,
- metadata: FtMetadataResponse
+ metadata: FtMetadataResponse,
+ price: Money | null
) {
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..c91dc8d6f5b 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 | null;
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;
diff --git a/src/shared/utils/alex-sdk.ts b/src/shared/utils/alex-sdk.ts
new file mode 100644
index 00000000000..6f77af74c4d
--- /dev/null
+++ b/src/shared/utils/alex-sdk.ts
@@ -0,0 +1,3 @@
+import { AlexSDK } from 'alex-sdk';
+
+export const alex = new AlexSDK();