Skip to content

Commit

Permalink
refactor: ordinal aware utxo query, closes #4163
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Oct 3, 2023
1 parent 6a8be03 commit 9f8291f
Show file tree
Hide file tree
Showing 79 changed files with 610 additions and 606 deletions.
2 changes: 1 addition & 1 deletion src/app/common/hooks/balance/btc/use-btc-balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { baseCurrencyAmountInQuote, subtractMoney } from '@app/common/money/calc
import { i18nFormatCurrency } from '@app/common/money/format-money';
import { createBitcoinCryptoCurrencyAssetTypeWrapper } from '@app/query/bitcoin/address/address.utils';
import { useBitcoinPendingTransactionsBalance } from '@app/query/bitcoin/address/transactions-by-address.hooks';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';

export function useBtcAssetBalance(btcAddress: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useMemo } from 'react';

import type { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model';

import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { useTransferableStacksFungibleTokenAssetBalances } from '@app/query/stacks/balance/stacks-ft-balances.hooks';
import { createStacksCryptoCurrencyAssetTypeWrapper } from '@app/query/stacks/balance/stacks-ft-balances.utils';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/balance-btc.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { formatMoney } from '@app/common/money/format-money';
import { Caption } from '@app/components/typography';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';

export function BtcBalance() {
const balance = useCurrentNativeSegwitAddressBalance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
determineUtxosForSpend,
determineUtxosForSpendAll,
} from '@app/common/transactions/bitcoin/coinselect/local-coin-selection';
import { useSpendableCurrentNativeSegwitAccountUtxos } from '@app/query/bitcoin/address/utxos-by-address.hooks';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentNativeSegwitAccountSpendableUtxos } from '@app/query/bitcoin/address/utxos-by-address.hooks';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';

export const MAX_FEE_RATE_MULTIPLIER = 50;
Expand All @@ -21,7 +21,7 @@ interface UseBitcoinCustomFeeArgs {
}
export function useBitcoinCustomFee({ amount, isSendingMax, recipient }: UseBitcoinCustomFeeArgs) {
const balance = useCurrentNativeSegwitAddressBalance();
const { data: utxos = [] } = useSpendableCurrentNativeSegwitAccountUtxos();
const { data: utxos = [] } = useCurrentNativeSegwitAccountSpendableUtxos();
const btcMarketData = useCryptoCurrencyMarketData('BTC');

return useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
determineUtxosForSpend,
determineUtxosForSpendAll,
} from '@app/common/transactions/bitcoin/coinselect/local-coin-selection';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { UtxoResponseItem } from '@app/query/bitcoin/bitcoin-client';
import { useAverageBitcoinFeeRates } from '@app/query/bitcoin/fees/fee-estimates.hooks';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
convertInscriptionToSupportedInscriptionType,
createInscriptionInfoUrl,
} from '@app/query/bitcoin/ordinals/inscription.hooks';
import { useGetInscriptionsByOutputQuery } from '@app/query/bitcoin/ordinals/use-inscription-by-output.query';
import { useGetInscriptionsByOutputQuery } from '@app/query/bitcoin/ordinals/inscriptions-by-param.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';

import { CaptionDotSeparator } from '../caption-dot-separator';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { noop } from '@shared/utils';

import { Brc20TokenAssetItem } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item';
import { Tooltip } from '@app/components/tooltip';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Box, Spinner, Text } from '@stacks/ui';
import { sanitize } from 'dompurify';

import { figmaTheme } from '@app/common/utils/figma-theme';
import { useTextInscriptionContentQuery } from '@app/query/bitcoin/ordinals/use-text-ordinal-content.query';
import { useInscriptionTextContentQuery } from '@app/query/bitcoin/ordinals/inscription-text-content.query';

interface InscriptionTextProps {
contentSrc: string;
}
export function InscriptionText(props: InscriptionTextProps) {
const query = useTextInscriptionContentQuery(props.contentSrc);
const query = useInscriptionTextContentQuery(props.contentSrc);

if (query.isLoading) return <Spinner color={figmaTheme.icon} size="16px" />;

Expand Down
2 changes: 1 addition & 1 deletion src/app/features/activity-list/activity-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import uniqby from 'lodash.uniqby';
import { LoadingSpinner } from '@app/components/loading-spinner';
import { useBitcoinPendingTransactions } from '@app/query/bitcoin/address/transactions-by-address.hooks';
import { useGetBitcoinTransactionsByAddressesQuery } from '@app/query/bitcoin/address/transactions-by-address.query';
import { useZeroIndexTaprootAddress } from '@app/query/bitcoin/ordinals/use-zero-index-taproot-address';
import { useConfigBitcoinEnabled } from '@app/query/common/remote-config/remote-config.query';
import { useStacksPendingTransactions } from '@app/query/stacks/mempool/mempool.hooks';
import { useGetAccountTransactionsWithTransfersQuery } from '@app/query/stacks/transactions/transactions-with-transfers.query';
import { useZeroIndexTaprootAddress } from '@app/store/accounts/blockchain/bitcoin/bitcoin.hooks';
import { useCurrentAccountNativeSegwitIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useSubmittedTransactions } from '@app/store/submitted-transactions/submitted-transactions.selectors';

Expand Down
2 changes: 1 addition & 1 deletion src/app/features/bitcoin-choose-fee/bitcoin-choose-fee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AvailableBalance } from '@app/components/available-balance';
import { BitcoinCustomFee } from '@app/components/bitcoin-custom-fee/bitcoin-custom-fee';
import { MAX_FEE_RATE_MULTIPLIER } from '@app/components/bitcoin-custom-fee/hooks/use-bitcoin-custom-fee';
import { OnChooseFeeArgs } from '@app/components/bitcoin-fees-list/bitcoin-fees-list';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { useCurrentAccountNativeSegwitIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';

import { BitcoinChooseFeeLayout } from './components/bitcoin-choose-fee.layout';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useState } from 'react';
import { Money, createMoney } from '@shared/models/money.model';

import { subtractMoney, sumMoney } from '@app/common/money/calculate-money';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';

export function useValidateBitcoinSpend(amount?: Money, isSendingMax?: boolean) {
const [showInsufficientBalanceError, setShowInsufficientBalanceError] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OrdinalMinimalIcon } from '@app/components/icons/ordinal-minimal-icon';
import { useTextInscriptionContentQuery } from '@app/query/bitcoin/ordinals/use-text-ordinal-content.query';
import { useInscriptionTextContentQuery } from '@app/query/bitcoin/ordinals/inscription-text-content.query';

import { CollectibleText } from '../_collectible-types/collectible-text';

Expand All @@ -23,7 +23,7 @@ export function InscriptionText({
onClickCallToAction,
onClickSend,
}: InscriptionTextProps) {
const query = useTextInscriptionContentQuery(contentSrc);
const query = useInscriptionTextContentQuery(contentSrc);

if (query.isLoading || query.isError) return null;

Expand Down
4 changes: 2 additions & 2 deletions src/app/features/collectibles/components/bitcoin/ordinals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useInView } from 'react-intersection-observer';
import { Box } from '@stacks/ui';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useTaprootInscriptionsInfiniteQuery } from '@app/query/bitcoin/ordinals/use-inscriptions.query';
import { useGetInscriptionsInfiniteQuery } from '@app/query/bitcoin/ordinals/inscriptions.query';

import { Inscription } from './inscription';

Expand All @@ -13,7 +13,7 @@ interface OrdinalsProps {
}

export function Ordinals({ setIsLoadingMore }: OrdinalsProps) {
const query = useTaprootInscriptionsInfiniteQuery();
const query = useGetInscriptionsInfiniteQuery();
const pages = query.data?.pages;
const analytics = useAnalytics();
const { ref: intersectionSentinel, inView } = useInView({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatMoney } from '@app/common/money/format-money';
import { Tooltip } from '@app/components/tooltip';
import { Caption } from '@app/components/typography';
import { useCurrentTaprootAccountBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentTaprootAccountBalance } from '@app/query/bitcoin/balance/btc-taproot-balance.hooks';

const taprootSpendNotSupportedYetMsg = `
Total amount of BTC in your Taproot account addresses. Click to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { StatusPending } from '@app/components/status-pending';
import { StatusReady } from '@app/components/status-ready';
import { Tooltip } from '@app/components/tooltip';
import { Caption } from '@app/components/typography';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { useCheckOrderStatuses } from '@app/query/bitcoin/ordinals/brc20/use-check-order-status';
import { fetchInscripionById } from '@app/query/bitcoin/ordinals/inscription-by-id.query';
import { convertInscriptionToSupportedInscriptionType } from '@app/query/bitcoin/ordinals/inscription.hooks';
import { fetchInscripionById } from '@app/query/bitcoin/ordinals/use-inscription-by-id';
import { useOrdinalsbotClient } from '@app/query/bitcoin/ordinalsbot-client';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export function PsbtAddressReceiveTotals({ showTaprootTotal }: PsbtAddressTotals
/>
) : null}
{isReceivingInscriptions
? accountInscriptionsBeingReceived.map(path => <PsbtInscription key={path} path={path} />)
? accountInscriptionsBeingReceived.map(inscription => (
<PsbtInscription key={inscription.id} inscription={inscription} />
))
: null}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@ interface PsbtAddressTotalsProps {
showNativeSegwitTotal: boolean;
}
export function PsbtAddressTransferTotals({ showNativeSegwitTotal }: PsbtAddressTotalsProps) {
const {
accountInscriptionsBeingTransferred,

addressNativeSegwit,

addressNativeSegwitTotal,
} = usePsbtSignerContext();
const { accountInscriptionsBeingTransferred, addressNativeSegwit, addressNativeSegwitTotal } =
usePsbtSignerContext();
const calculateBitcoinFiatValue = useCalculateBitcoinFiatValue();

const isTransferringInscriptions = accountInscriptionsBeingTransferred?.length;
Expand All @@ -33,8 +28,8 @@ export function PsbtAddressTransferTotals({ showNativeSegwitTotal }: PsbtAddress
/>
) : null}
{isTransferringInscriptions
? accountInscriptionsBeingTransferred.map(path => (
<PsbtInscription key={path} path={path} />
? accountInscriptionsBeingTransferred.map(inscription => (
<PsbtInscription key={inscription.id} inscription={inscription} />
))
: null}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { Inscription } from '@shared/models/inscription.model';
import { isUndefined } from '@shared/utils';

import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { OrdinalIcon } from '@app/components/icons/ordinal-icon';
import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview';
import { useInscription } from '@app/query/bitcoin/ordinals/inscription.hooks';
import {
createInscriptionInfoUrl,
useInscription,
} from '@app/query/bitcoin/ordinals/inscription.hooks';

import { PsbtAddressTotalItem } from './psbt-address-total-item';

interface PsbtInscriptionProps {
path: string;
inscription: Inscription;
}
export function PsbtInscription({ path }: PsbtInscriptionProps) {
const {
isLoading,
isError,
data: inscription,
} = useInscription(path.replace('/inscription/', ''));
export function PsbtInscription({ inscription }: PsbtInscriptionProps) {
const { isLoading, isError, data: supportedInscription } = useInscription(inscription?.id ?? '');

if (isLoading) return null;
if (isError || isUndefined(inscription))
if (isError || isUndefined(supportedInscription))
return (
<PsbtAddressTotalItem
image={<OrdinalIcon />}
Expand All @@ -27,12 +27,13 @@ export function PsbtInscription({ path }: PsbtInscriptionProps) {
/>
);

//
return (
<PsbtAddressTotalItem
image={<InscriptionPreview inscription={inscription} height="40px" width="40px" />}
image={<InscriptionPreview inscription={supportedInscription} height="40px" width="40px" />}
title="Inscription"
value={`#${inscription.number}`}
valueAction={() => openInNewTab(inscription.infoUrl)}
value={`#${inscription?.number}`}
valueAction={() => openInNewTab(createInscriptionInfoUrl(inscription?.id))}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { color } from '@stacks/ui-utils';
import { Box } from 'leather-styles/jsx';
import { Box, styled } from 'leather-styles/jsx';

import { Hr } from '@app/components/hr';
import { usePsbtSignerContext } from '@app/features/psbt-signer/psbt-signer.context';

import { PsbtRequestDetailsSectionHeader } from '../psbt-request-details-section-header';
Expand Down Expand Up @@ -34,7 +32,9 @@ export function PsbtInputsOutputsTotals() {
<PsbtAddressTransferTotals showNativeSegwitTotal={isNativeSegwitTotalGreaterThanZero} />
</Box>
) : null}
{showDivider ? <Hr backgroundColor={color('border')} height="3px" /> : null}
{showDivider ? (
<styled.hr border="1px solid" borderColor="accent.border-default !important" />
) : null}
{isReceiving ? (
<Box p="space.05">
<PsbtRequestDetailsSectionHeader title="You'll receive" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Stack, StackProps, color } from '@stacks/ui';
import { Stack, StackProps } from 'leather-styles/jsx';

import { HasChildren } from '@app/common/has-children';

export function PsbtRequestDetailsSectionLayout({ children, ...props }: HasChildren & StackProps) {
return (
<Stack
border="4px solid"
borderColor={color('border')}
border="1px solid"
borderColor="accent.border-default !important"
borderRadius="16px"
p="loose"
spacing="extra-tight"
gap="space.01"
p="space.05"
width="100%"
{...props}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { mockInscription1, mockInscription2 } from '@tests/mocks/mock-inscriptions';
import {
mockInscriptions1,
mockInscriptions2,
mockPsbtInputs1,
mockPsbtInputs2,
mockPsbtOutputs1,
Expand All @@ -12,27 +11,23 @@ import { findOutputsReceivingInscriptions } from './find-outputs-receiving-inscr
describe('find outputs receiving inscriptions', () => {
test('that the correct output receives the inscription (scenario 1)', () => {
const outputsReceivingInscriptions = findOutputsReceivingInscriptions({
inscriptions: mockInscriptions1,
psbtInputs: mockPsbtInputs1,
psbtOutputs: mockPsbtOutputs1,
});
expect(outputsReceivingInscriptions[0]).toEqual({
address: 'bc1p9pnzvq52956jht5deha82qp96pxw0a0tvey6fhdea7vwhf33tarskqq3nr',
inscription:
'/inscription/ba39f922074c0d338a13ac10e770a5da47ce09df8310c8d3cfaec13a347e8202i0',
inscription: mockInscription1,
});
});

test('that the correct output receives the inscription (scenario 2)', () => {
const outputsReceivingInscriptions = findOutputsReceivingInscriptions({
inscriptions: mockInscriptions2,
psbtInputs: mockPsbtInputs2,
psbtOutputs: mockPsbtOutputs2,
});
expect(outputsReceivingInscriptions[0]).toEqual({
address: 'bc1p9pnzvq52956jht5deha82qp96pxw0a0tvey6fhdea7vwhf33tarskqq3nr',
inscription:
'/inscription/ba39f922074c0d338a13ac10e770a5da47ce09df8310c8d3cfaec13a347e8202i0',
inscription: mockInscription2,
});
});
});
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
import BigNumber from 'bignumber.js';

import { Inscription } from '@shared/models/inscription.model';
import { isDefined } from '@shared/utils';

import { PsbtInput } from './use-parsed-inputs';
import { PsbtOutput } from './use-parsed-outputs';

interface FindOutputsReceivingInscriptionsArgs {
inscriptions: Inscription[];
psbtInputs: PsbtInput[];
psbtOutputs: PsbtOutput[];
}
// If an input has an inscription, we use the offset to determine where it matches
// up from total input sats position to total output sats position. By doing this,
// we can predict where the inscription will be sent.
export function findOutputsReceivingInscriptions({
inscriptions,
psbtInputs,
psbtOutputs,
}: FindOutputsReceivingInscriptionsArgs) {
let inputsSatsTotal = new BigNumber(0);

return psbtInputs
.flatMap(input => {
if (input.inscription) {
const inscription = inscriptions.find(
inscription => input.inscription?.includes(inscription.id)
);

if (isDefined(input.inscription)) {
// Offset is zero indexed, so 1 is added here to match the sats total
const inscriptionTotalOffset = inputsSatsTotal.plus(Number(inscription?.offset) + 1);
const inscriptionTotalOffset = inputsSatsTotal.plus(Number(input.inscription.offset) + 1);

let outputsSatsTotal = new BigNumber(0);

Expand Down
Loading

0 comments on commit 9f8291f

Please sign in to comment.