From ae73aaabace2be8dd8cecf24c595bb9f81f36ee6 Mon Sep 17 00:00:00 2001 From: alter-eggo Date: Thu, 15 Feb 2024 17:44:40 +0400 Subject: [PATCH] feat: add check inscription send utxos --- .../send-inscription-review.tsx | 24 ++++++++++++++++--- .../bitcoin/transaction/use-check-utxos.ts | 19 +++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx b/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx index 36ec06caeaa..fd4464b00d0 100644 --- a/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx +++ b/src/app/pages/send/ordinal-inscription/send-inscription-review.tsx @@ -4,6 +4,7 @@ import { bytesToHex } from '@noble/hashes/utils'; import { Box, Stack } from 'leather-styles/jsx'; import get from 'lodash.get'; +import { decodeBitcoinTx } from '@shared/crypto/bitcoin/bitcoin.utils'; import { RouteUrls } from '@shared/route-urls'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; @@ -12,6 +13,10 @@ import { BaseDrawer } from '@app/components/drawer/base-drawer'; import { InfoCard, InfoCardRow, InfoCardSeparator } from '@app/components/info-card/info-card'; import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview'; import { useCurrentNativeSegwitUtxos } from '@app/query/bitcoin/address/utxos-by-address.hooks'; +import { + filterOutIntentionalInscriptionsSpend, + useCheckInscribedUtxos, +} from '@app/query/bitcoin/transaction/use-check-utxos'; import { useAppDispatch } from '@app/store'; import { inscriptionSent } from '@app/store/ordinals/ordinals.slice'; import { Button } from '@app/ui/components/button/button'; @@ -40,8 +45,17 @@ export function SendInscriptionReview() { const { refetch } = useCurrentNativeSegwitUtxos(); const { broadcastTx, isBroadcasting } = useBitcoinBroadcastTransaction(); + const { checkIfUtxosListIncludesInscribed, isLoading } = useCheckInscribedUtxos({ + // Filer out inscription txid from the check list + inputs: filterOutIntentionalInscriptionsSpend({ + inputs: decodeBitcoinTx(bytesToHex(signedTx)).inputs, + inscriptions: [inscription], + }), + }); + async function sendInscription() { await broadcastTx({ + checkForInscribedUtxos: checkIfUtxosListIncludesInscribed, tx: bytesToHex(signedTx), async onSuccess(txid: string) { void analytics.track('broadcast_ordinal_transaction'); @@ -58,8 +72,12 @@ export function SendInscriptionReview() { }, }); }, - onError() { - navigate(`/${RouteUrls.SendOrdinalInscription}/${RouteUrls.SendOrdinalInscriptionError}`); + onError(e) { + navigate(`/${RouteUrls.SendOrdinalInscription}/${RouteUrls.SendOrdinalInscriptionError}`, { + state: { + error: e, + }, + }); }, }); } @@ -82,7 +100,7 @@ export function SendInscriptionReview() { - diff --git a/src/app/query/bitcoin/transaction/use-check-utxos.ts b/src/app/query/bitcoin/transaction/use-check-utxos.ts index da669311126..20d619d8267 100644 --- a/src/app/query/bitcoin/transaction/use-check-utxos.ts +++ b/src/app/query/bitcoin/transaction/use-check-utxos.ts @@ -3,6 +3,7 @@ import { useCallback, useState } from 'react'; import * as btc from '@scure/btc-signer'; import { bytesToHex } from '@stacks/common'; +import type { SupportedInscription } from '@shared/models/inscription.model'; import { isUndefined } from '@shared/utils'; import { useAnalytics } from '@app/common/hooks/analytics/use-analytics'; @@ -23,6 +24,24 @@ interface UseCheckInscribedUtxosArgs { blockTxAction?(): void; } +interface FilterOutIntentionalInscriptionsSpendArgs { + inputs: btc.TransactionInput[]; + inscriptions: SupportedInscription[]; +} +export function filterOutIntentionalInscriptionsSpend({ + inputs, + inscriptions, +}: FilterOutIntentionalInscriptionsSpendArgs) { + return inputs.filter(input => { + if (!input.txid) throw new Error('Transaction ID is missing in the input'); + const inputTxid = bytesToHex(input.txid); + + return inscriptions.every(inscription => { + return inscription.tx_id !== inputTxid; + }); + }); +} + export function useCheckInscribedUtxos({ inputs, blockTxAction }: UseCheckInscribedUtxosArgs) { const client = useBitcoinClient(); const analytics = useAnalytics();