Skip to content

Commit

Permalink
feat: stacks ft fiat values from alex-sdk, closes #4653
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Apr 4, 2024
1 parent fb859b6 commit b1e0ab9
Show file tree
Hide file tree
Showing 23 changed files with 166 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { StacksFungibleTokenAsset } from '@shared/models/crypto-asset.model';
import { createMoney } from '@shared/models/money.model';

import {
isFtNameLikeStx,
Expand Down Expand Up @@ -31,6 +32,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
price: createMoney(0, 'USD'),
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
Expand All @@ -47,6 +49,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
price: createMoney(0, 'USD'),
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);

Expand Down Expand Up @@ -45,6 +47,7 @@ export function StacksFungibleTokenAssetItemLayout({
</styled.span>
</BasicTooltip>
}
captionRight={balanceAsFiat}
/>
</Pressable>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ interface StacksBalanceListItemProps {
address: string;
}
export function StacksBalanceListItem({ address }: StacksBalanceListItemProps) {
const balaceDetails = useStxBalance();
const balanceDetails = useStxBalance();
return (
<StacksBalanceListItemLayout
address={address}
isInitialLoading={balaceDetails.stxBalanceQuery.isInitialLoading}
{...balaceDetails}
isInitialLoading={balanceDetails.stxBalanceQuery.isInitialLoading}
{...balanceDetails}
/>
);
}
25 changes: 7 additions & 18 deletions src/app/pages/fund/components/fund.layout.tsx
Original file line number Diff line number Diff line change
@@ -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<CryptoCurrencies, { name: string; symbol: string }> = {
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 (
<Stack
alignItems={{ base: 'left', md: 'center' }}
Expand All @@ -44,9 +32,10 @@ export function FundLayout({ symbol, children }: FundLayoutProps) {
maxWidth="544px"
textAlign={{ base: 'left', md: 'center' }}
>
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{' '}
<styled.span textTransform="capitalize">{blockchain}</styled.span> ({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.
</styled.span>
{children}
</Stack>
Expand Down
10 changes: 1 addition & 9 deletions src/app/pages/fund/fiat-providers-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { Grid } from 'leather-styles/jsx';
Expand Down Expand Up @@ -30,14 +29,7 @@ export function FiatProvidersList(props: FiatProvidersProps) {
const analytics = useAnalytics();
const location = useLocation();

const routeToQr = useMemo(() => {
switch (symbol) {
case 'BTC':
return RouteUrls.ReceiveBtc;
case 'STX':
return RouteUrls.ReceiveStx;
}
}, [symbol]);
const routeToQr = symbol === 'BTC' ? RouteUrls.ReceiveBtc : RouteUrls.ReceiveStx;

const goToProviderExternalWebsite = (provider: string, providerUrl: string) => {
void analytics.track('select_buy_option', { provider });
Expand Down
68 changes: 38 additions & 30 deletions src/app/pages/fund/fund.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -11,44 +17,46 @@ 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<CryptoCurrencies, FundCryptoCurrencyInfo> = {
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, symbol } =
fundCryptoCurrencyMap[currency as CryptoCurrencies];

if (!address || !balance) return <FullPageLoadingSpinner />;

return (
<>
<FundLayout symbol={symbol}>
<FundLayout blockchain={blockchain} symbol={symbol}>
<FiatProvidersList address={address} symbol={symbol} />
</FundLayout>
<Outlet />
Expand Down
10 changes: 5 additions & 5 deletions src/app/pages/swap/alex-swap-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -55,7 +56,6 @@ function AlexSwapContainer() {
});

const {
alexSDK,
fetchToAmount,
createSwapAssetFromAlexCurrency,
isFetchingExchangeRate,
Expand All @@ -66,7 +66,7 @@ function AlexSwapContainer() {
swapSubmissionData,
} = useAlexSwap();

const broadcastAlexSwap = useAlexBroadcastSwap(alexSDK);
const broadcastAlexSwap = useAlexBroadcastSwap();
const broadcastStacksSwap = useStacksBroadcastSwap();

const swappableAssets: SwapAsset[] = useMemo(
Expand All @@ -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({
Expand Down Expand Up @@ -141,7 +141,7 @@ function AlexSwapContainer() {
.toString()
);

const tx = alexSDK.runSwap(
const tx = alex.runSwap(
currentAccount?.address,
swapSubmissionData.swapAssetFrom.currency,
swapSubmissionData.swapAssetTo.currency,
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/swap/components/swap-amount-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function getPlaceholderValue(name: string, values: SwapFormValues) {
}

interface SwapAmountFieldProps {
amountAsFiat: string;
amountAsFiat?: string;
isDisabled?: boolean;
name: string;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/swap/components/swap-selected-asset-from.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/swap/components/swap-selected-asset-to.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
9 changes: 5 additions & 4 deletions src/app/pages/swap/hooks/use-alex-broadcast-swap.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -31,6 +32,6 @@ export function useAlexBroadcastSwap(alexSDK: AlexSDK) {
});
}
},
[alexSDK, navigate, setIsIdle]
[navigate, setIsIdle]
);
}
Loading

0 comments on commit b1e0ab9

Please sign in to comment.