Skip to content

Commit

Permalink
refactor: price as market data
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Apr 16, 2024
1 parent 17023b9 commit d8a6385
Show file tree
Hide file tree
Showing 29 changed files with 251 additions and 280 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { StacksFungibleTokenAsset } from '@shared/models/crypto-asset.model';
import { createMoney } from '@shared/models/money.model';

import {
isFtNameLikeStx,
Expand Down Expand Up @@ -32,7 +31,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
price: createMoney(0, 'USD'),
price: null,
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
Expand All @@ -49,7 +48,7 @@ describe(isTransferableStacksFungibleTokenAsset.name, () => {
canTransfer: true,
hasMemo: true,
imageCanonicalUri: '',
price: createMoney(0, 'USD'),
price: null,
symbol: 'CAT',
};
expect(isTransferableStacksFungibleTokenAsset(asset)).toBeTruthy();
Expand Down
2 changes: 1 addition & 1 deletion src/app/common/money/calculate-money.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isNumber } from '@shared/utils';

import { initBigNumber, sumNumbers } from '../math/helpers';
import { formatMoney } from './format-money';
import { isMoney } from './is-money';
import { isMoney } from './money.utils';

export function baseCurrencyAmountInQuote(quantity: Money, { pair, price }: MarketData) {
if (quantity.symbol.toLowerCase() !== pair.base.toLowerCase())
Expand Down
18 changes: 0 additions & 18 deletions src/app/common/money/fiat-conversion.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import BigNumber from 'bignumber.js';

import { Money } from '@shared/models/money.model';
import { isObject } from '@shared/utils';

export function isMoney(val: unknown): val is Money {
if (!isObject(val)) return false;
return 'amount' in val && 'symbol' in val && 'decimals' in val;
}

export function isMoneyGreaterThanZero(money: Money) {
if (!BigNumber.isBigNumber(money.amount)) return;
return !(money.amount.isNaN() || money.amount.isZero());
}
23 changes: 0 additions & 23 deletions src/app/common/utils/sort-assets-by-symbol.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function useBitcoinCustomFeeMultipleRecipients({
}: UseBitcoinCustomFeeArgsMultipleRecipients) {
const { balance } = useCurrentNativeSegwitAddressBalance();
const { data: utxos = [] } = useCurrentNativeSegwitUtxos();
const btcMarketData = useCryptoCurrencyMarketData('BTC');
const btcMarketData = useCryptoCurrencyMarketDataMeanAverage('BTC');

return useCallback(
(feeRate: number) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import { styled } from 'leather-styles/jsx';
import { createMoney } from '@shared/models/money.model';

import { formatBalance } from '@app/common/format-balance';
import {
checkIsMoneyAmountGreaterThanZero,
convertCryptoCurrencyMoneyToFiat,
} from '@app/common/money/fiat-conversion';
import { baseCurrencyAmountInQuote } from '@app/common/money/calculate-money';
import { i18nFormatCurrency } from '@app/common/money/format-money';
import { isMoneyGreaterThanZero } from '@app/common/money/money.utils';
import { Brc20Token } from '@app/query/bitcoin/bitcoin-client';
import { Brc20AvatarIcon } from '@app/ui/components/avatar/brc20-avatar-icon';
import { ItemLayout } from '@app/ui/components/item-layout/item-layout';
Expand All @@ -22,12 +20,9 @@ export function Brc20TokenAssetItemLayout({ onClick, token }: Brc20TokenAssetIte
const balanceAsMoney = createMoney(Number(token.overall_balance), token.ticker, token.decimals);
const balanceAsString = balanceAsMoney.amount.toString();
const formattedBalance = formatBalance(balanceAsString);
const priceAsMoney = createMoney(token.min_listed_unit_price, 'USD');
const showFiatBalance = checkIsMoneyAmountGreaterThanZero(priceAsMoney);
const showFiatBalance = isMoneyGreaterThanZero(token.price?.price);
const balanceAsFiat = showFiatBalance
? i18nFormatCurrency(
convertCryptoCurrencyMoneyToFiat(token.ticker, priceAsMoney, balanceAsMoney)
)
? i18nFormatCurrency(baseCurrencyAmountInQuote(balanceAsMoney, token.price))
: '';

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import type { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asse

import { getImageCanonicalUri } from '@app/common/crypto-assets/stacks-crypto-asset.utils';
import { formatBalance } from '@app/common/format-balance';
import {
checkIsMoneyAmountGreaterThanZero,
convertCryptoCurrencyMoneyToFiat,
} from '@app/common/money/fiat-conversion';
import { baseCurrencyAmountInQuote } from '@app/common/money/calculate-money';
import { i18nFormatCurrency } from '@app/common/money/format-money';
import { isMoneyGreaterThanZero } from '@app/common/money/money.utils';
import { ftDecimals } from '@app/common/stacks-utils';
import { formatContractId, getTicker } from '@app/common/utils';
import { spamFilter } from '@app/common/utils/spam-filter';
Expand All @@ -35,16 +33,10 @@ export function parseStacksFungibleTokenAssetBalance(
const title = spamFilter(friendlyName);

const showFiatBalance =
assetBalance.asset.price && checkIsMoneyAmountGreaterThanZero(assetBalance.asset.price);
assetBalance.asset.price && isMoneyGreaterThanZero(assetBalance.asset.price.price);
const balanceAsFiat = showFiatBalance
? assetBalance.asset.price &&
i18nFormatCurrency(
convertCryptoCurrencyMoneyToFiat(
assetBalance.balance.symbol,
assetBalance.asset.price,
assetBalance.balance
)
)
i18nFormatCurrency(baseCurrencyAmountInQuote(assetBalance.balance, assetBalance.asset.price))
: '';

return {
Expand Down
18 changes: 7 additions & 11 deletions src/app/pages/receive/components/receive-tokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ import { HomePageSelectors } from '@tests/selectors/home.selectors';
import { css } from 'leather-styles/css';
import { Stack } from 'leather-styles/jsx';

import { isDefined } from '@shared/utils';

import { copyToClipboard } from '@app/common/utils/copy-to-clipboard';
import { sortAssetsBySymbol } from '@app/common/utils/sort-assets-by-symbol';
import { useToast } from '@app/features/toasts/use-toast';
import { useAlexSdkSwappableCurrencyQuery } from '@app/query/common/alex-sdk/swappable-currency.query';
import { useAlexSwappableAssets } from '@app/query/common/alex-sdk/alex-sdk.hooks';
import { useConfigRunesEnabled } from '@app/query/common/remote-config/remote-config.query';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { Avatar, defaultFallbackDelay, getAvatarFallback } from '@app/ui/components/avatar/avatar';
import { Avatar, defaultFallbackDelay } from '@app/ui/components/avatar/avatar';
import { Brc20AvatarIcon } from '@app/ui/components/avatar/brc20-avatar-icon';
import { BtcAvatarIcon } from '@app/ui/components/avatar/btc-avatar-icon';
import { RunesAvatarIcon } from '@app/ui/components/avatar/runes-avatar-icon';
Expand All @@ -39,20 +36,19 @@ export function ReceiveTokens({
const toast = useToast();
const network = useCurrentNetwork();
const runesEnabled = useConfigRunesEnabled();
const { data: supportedCurrencies = [] } = useAlexSdkSwappableCurrencyQuery();
const { data: swapAssets = [] } = useAlexSwappableAssets();

const receivableAssets = useMemo(
() =>
sortAssetsBySymbol(supportedCurrencies.filter(isDefined))
swapAssets
.filter(asset => asset.name !== 'STX')
.map(asset => ({
...asset,
address: stxAddress,
fallback: getAvatarFallback(asset.name),
icon: asset.icon,
name: asset.name,
})),
[stxAddress, supportedCurrencies]
[stxAddress, swapAssets]
);

return (
<Stack className={css(receiveTabStyle)}>
<ReceiveItem
Expand Down
36 changes: 12 additions & 24 deletions src/app/pages/swap/alex-swap-container.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useState } from 'react';
import { Outlet } from 'react-router-dom';

import { bytesToHex } from '@stacks/common';
Expand All @@ -19,6 +19,10 @@ import { alex } from '@shared/utils/alex-sdk';
import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading';
import { useWalletType } from '@app/common/use-wallet-type';
import { NonceSetter } from '@app/components/nonce-setter';
import {
defaultSwapFee,
migratePositiveBalancesToTop,
} from '@app/query/common/alex-sdk/alex-sdk.utils';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useGenerateStacksContractCallUnsignedTx } from '@app/store/transactions/contract-call.hooks';
import { useSignStacksTransaction } from '@app/store/transactions/transaction.hooks';
Expand All @@ -29,14 +33,9 @@ import { generateSwapRoutes } from './generate-swap-routes';
import { useAlexBroadcastSwap } from './hooks/use-alex-broadcast-swap';
import { oneHundredMillion, useAlexSwap } from './hooks/use-alex-swap';
import { useStacksBroadcastSwap } from './hooks/use-stacks-broadcast-swap';
import { SwapAsset, SwapFormValues } from './hooks/use-swap-form';
import { SwapFormValues } from './hooks/use-swap-form';
import { useSwapNavigate } from './hooks/use-swap-navigate';
import { SwapContext, SwapProvider } from './swap.context';
import {
defaultSwapFee,
migratePositiveBalancesToTop,
sortSwappableAssetsBySymbol,
} from './swap.utils';

export const alexSwapRoutes = generateSwapRoutes(<AlexSwapContainer />);

Expand All @@ -57,27 +56,18 @@ function AlexSwapContainer() {
});

const {
fetchToAmount,
createSwapAssetFromAlexCurrency,
fetchQuoteAmount,
isFetchingExchangeRate,
onSetIsFetchingExchangeRate,
onSetSwapSubmissionData,
slippage,
supportedCurrencies,
swapAssets,
swapSubmissionData,
} = useAlexSwap();

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

const swappableAssets: SwapAsset[] = useMemo(
() =>
sortSwappableAssetsBySymbol(
supportedCurrencies.map(createSwapAssetFromAlexCurrency).filter(isDefined)
),
[createSwapAssetFromAlexCurrency, supportedCurrencies]
);

async function onSubmitSwapForReview(values: SwapFormValues) {
if (isUndefined(values.swapAssetBase) || isUndefined(values.swapAssetQuote)) {
logger.error('Error submitting swap for review');
Expand All @@ -96,9 +86,7 @@ function AlexSwapContainer() {
liquidityFee: new BigNumber(Number(lpFee)).dividedBy(oneHundredMillion).toNumber(),
nonce: values.nonce,
protocol: 'ALEX',
router: router
.map(x => createSwapAssetFromAlexCurrency(supportedCurrencies.find(y => y.id === x)))
.filter(isDefined),
router: router.map(x => swapAssets.find(asset => asset.currency === x)).filter(isDefined),
slippage,
sponsored: isSponsoredByAlex,
swapAmountBase: values.swapAmountBase,
Expand Down Expand Up @@ -191,15 +179,15 @@ function AlexSwapContainer() {
}

const swapContextValue: SwapContext = {
fetchToAmount,
fetchQuoteAmount,
isFetchingExchangeRate,
isSendingMax,
onSetIsFetchingExchangeRate,
onSetIsSendingMax: value => setIsSendingMax(value),
onSubmitSwapForReview,
onSubmitSwap,
swappableAssetsBase: migratePositiveBalancesToTop(swappableAssets),
swappableAssetsQuote: swappableAssets,
swappableAssetsBase: migratePositiveBalancesToTop(swapAssets),
swappableAssetsQuote: swapAssets,
swapSubmissionData,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { SwapSelectors } from '@tests/selectors/swap.selectors';

import {
checkIsMoneyAmountGreaterThanZero,
convertCryptoCurrencyMoneyToFiat,
} from '@app/common/money/fiat-conversion';
import { baseCurrencyAmountInQuote } from '@app/common/money/calculate-money';
import { formatMoneyWithoutSymbol, i18nFormatCurrency } from '@app/common/money/format-money';
import type { SwapAsset } from '@app/pages/swap/hooks/use-swap-form';
import { isMoneyGreaterThanZero } from '@app/common/money/money.utils';
import type { SwapAsset } from '@app/query/common/alex-sdk/alex-sdk.hooks';
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';
Expand All @@ -22,11 +20,9 @@ export function SwapAssetItem({ asset, onClick }: SwapAssetItemProps) {
const ftMetadataName = ftMetadata && isFtAsset(ftMetadata) ? ftMetadata.name : asset.name;
const displayName = asset.displayName ?? ftMetadataName;
const fallback = getAvatarFallback(asset.name);
const showFiatBalance = checkIsMoneyAmountGreaterThanZero(asset.price);
const showFiatBalance = isMoneyGreaterThanZero(asset.price.price);
const balanceAsFiat = showFiatBalance
? i18nFormatCurrency(
convertCryptoCurrencyMoneyToFiat(asset.balance.symbol, asset.price, asset.balance)
)
? i18nFormatCurrency(baseCurrencyAmountInQuote(asset.balance, asset.price))
: '';

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { isUndefined } from '@shared/utils';
import { convertAmountToFractionalUnit } from '@app/common/money/calculate-money';
import { formatMoneyWithoutSymbol } from '@app/common/money/format-money';
import { useSwapContext } from '@app/pages/swap/swap.context';
import type { SwapAsset } from '@app/query/common/alex-sdk/alex-sdk.hooks';

import { SwapAsset, SwapFormValues } from '../../../hooks/use-swap-form';
import { SwapFormValues } from '../../../hooks/use-swap-form';
import { SwapAssetItem } from './swap-asset-item';

interface SwapAssetList {
assets: SwapAsset[];
type: string;
}
export function SwapAssetList({ assets, type }: SwapAssetList) {
const { fetchToAmount } = useSwapContext();
const { fetchQuoteAmount } = useSwapContext();
const { setFieldError, setFieldValue, values } = useFormikContext<SwapFormValues>();
const navigate = useNavigate();
const { base, quote } = useParams();
Expand All @@ -35,33 +36,33 @@ export function SwapAssetList({ assets, type }: SwapAssetList) {
);

async function onSelectAsset(asset: SwapAsset) {
let from: SwapAsset | undefined;
let to: SwapAsset | undefined;
let baseAsset: SwapAsset | undefined;
let quoteAsset: SwapAsset | undefined;
if (isBaseList) {
from = asset;
to = values.swapAssetQuote;
baseAsset = asset;
quoteAsset = values.swapAssetQuote;
await setFieldValue('swapAssetBase', asset);
navigate(RouteUrls.Swap.replace(':base', from.name).replace(':quote', quote ?? ''));
navigate(RouteUrls.Swap.replace(':base', baseAsset.name).replace(':quote', quote ?? ''));
} else if (isQuoteList) {
from = values.swapAssetBase;
to = asset;
baseAsset = values.swapAssetBase;
quoteAsset = asset;
await setFieldValue('swapAssetQuote', asset);
setFieldError('swapAssetQuote', undefined);
navigate(RouteUrls.Swap.replace(':base', base ?? '').replace(':quote', to.name));
navigate(RouteUrls.Swap.replace(':base', base ?? '').replace(':quote', quoteAsset.name));
}

if (from && to && values.swapAmountBase) {
const toAmount = await fetchToAmount(from, to, values.swapAmountBase);
if (isUndefined(toAmount)) {
if (baseAsset && quoteAsset && values.swapAmountBase) {
const quoteAmount = await fetchQuoteAmount(baseAsset, quoteAsset, values.swapAmountBase);
if (isUndefined(quoteAmount)) {
await setFieldValue('swapAmountQuote', '');
return;
}
const toAmountAsMoney = createMoney(
convertAmountToFractionalUnit(new BigNumber(toAmount), to?.balance.decimals),
to?.balance.symbol ?? '',
to?.balance.decimals
const quoteAmountAsMoney = createMoney(
convertAmountToFractionalUnit(new BigNumber(quoteAmount), quoteAsset?.balance.decimals),
quoteAsset?.balance.symbol ?? '',
quoteAsset?.balance.decimals
);
await setFieldValue('swapAmountQuote', formatMoneyWithoutSymbol(toAmountAsMoney));
await setFieldValue('swapAmountQuote', formatMoneyWithoutSymbol(quoteAmountAsMoney));
setFieldError('swapAmountQuote', undefined);
}
}
Expand Down
Loading

0 comments on commit d8a6385

Please sign in to comment.