diff --git a/src/app/components/confirmBtcTransactionComponent/index.tsx b/src/app/components/confirmBtcTransactionComponent/index.tsx index 5c5e7170f..c443b3007 100644 --- a/src/app/components/confirmBtcTransactionComponent/index.tsx +++ b/src/app/components/confirmBtcTransactionComponent/index.tsx @@ -19,7 +19,7 @@ import { Recipient, SignedBtcTx, signNonOrdinalBtcSendTransaction, - signOrdinalSendTransaction, + signOrdinalTransaction, } from '@secretkeylabs/xverse-core/transactions/btc'; import { StoreState } from '@stores/index'; import { useMutation } from '@tanstack/react-query'; @@ -30,6 +30,7 @@ import { NumericFormat } from 'react-number-format'; import { useSelector } from 'react-redux'; import styled from 'styled-components'; import TransactionDetailComponent from '../transactionDetailComponent'; +import { Inscription } from '@secretkeylabs/xverse-core/types'; const OuterContainer = styled.div` display: flex; @@ -123,6 +124,8 @@ interface Props { isRestoreFundFlow?: boolean; nonOrdinalUtxos?: BtcUtxoDataResponse[]; isBtcSendBrowserTx?: boolean; + ordinal?: Inscription; + isRestoreOrdinalFlow?: boolean; currentFeeRate: BigNumber; setCurrentFee: (feeRate: BigNumber) => void; setCurrentFeeRate: (feeRate: BigNumber) => void; @@ -143,6 +146,8 @@ function ConfirmBtcTransactionComponent({ isRestoreFundFlow, nonOrdinalUtxos, isBtcSendBrowserTx, + ordinal, + isRestoreOrdinalFlow = false, currentFeeRate, setCurrentFee, setCurrentFeeRate, @@ -153,9 +158,8 @@ function ConfirmBtcTransactionComponent({ const { t } = useTranslation('translation'); const isGalleryOpen: boolean = document.documentElement.clientWidth > 360; const [loading, setLoading] = useState(false); - const { btcAddress, selectedAccount, seedPhrase, network, btcFiatRate } = useSelector( - (state: StoreState) => state.walletState, - ); + const { btcAddress, selectedAccount, seedPhrase, network, btcFiatRate, ordinalsAddress } = + useSelector((state: StoreState) => state.walletState); const [showFeeSettings, setShowFeeSettings] = useState(false); const [error, setError] = useState(''); const [signedTx, setSignedTx] = useState(signedTxHex); @@ -210,21 +214,21 @@ function ConfirmBtcTransactionComponent({ data: ordinalData, error: ordinalError, mutate: ordinalMutate, - } = useMutation({ + } = useMutation({ mutationFn: async (txFee) => { - const ordinalsUtxos = ordinals!.map((ord) => ord.utxo); - - const newSignedTx = await signOrdinalSendTransaction( - recipients[0]?.address, - ordinalTxUtxo!, + if (!ordinal) return null; + const signedTx = await signOrdinalTransaction({ + recipientAddress: recipients[0]?.address, btcAddress, - Number(selectedAccount?.id), + ordinalsAddress, + accountIndex: Number(selectedAccount?.id), seedPhrase, - network.type, - ordinalsUtxos, - new BigNumber(txFee), - ); - return newSignedTx; + network: network.type, + ordinal, + fee: new BigNumber(txFee), + isRecover: isRestoreOrdinalFlow, + }); + return signedTx; }, }); @@ -408,6 +412,8 @@ function ConfirmBtcTransactionComponent({ isRestoreFlow={isRestoreFundFlow} showFeeSettings={showFeeSettings} setShowFeeSettings={setShowFeeSettings} + ordinal={ordinal} + isRestoreOrdinalFlow={isRestoreOrdinalFlow} /> diff --git a/src/app/components/transactionSetting/editFee.tsx b/src/app/components/transactionSetting/editFee.tsx index bc3a67b8e..4eecb46e6 100644 --- a/src/app/components/transactionSetting/editFee.tsx +++ b/src/app/components/transactionSetting/editFee.tsx @@ -13,12 +13,13 @@ import { NumericFormat } from 'react-number-format'; import { getBtcFees, getBtcFeesForNonOrdinalBtcSend, - getBtcFeesForOrdinalSend, + getBtcFeesForOrdinalTransaction, Recipient, } from '@secretkeylabs/xverse-core/transactions/btc'; import { BtcUtxoDataResponse, ErrorCodes, UTXO } from '@secretkeylabs/xverse-core'; import useDebounce from '@hooks/useDebounce'; import useOrdinalsByAddress from '@hooks/useOrdinalsByAddress'; +import { Inscription } from '@secretkeylabs/xverse-core/types'; const Container = styled.div((props) => ({ display: 'flex', @@ -151,6 +152,9 @@ interface Props { ordinalTxUtxo?: UTXO; isRestoreFlow?: boolean; nonOrdinalUtxos?: BtcUtxoDataResponse[]; + ordinal?: Inscription; + isRecover?: boolean; + isRestoreOrdinalFlow?: boolean; feeMode: string; error: string; setIsLoading: () => void; @@ -168,6 +172,9 @@ function EditFee({ ordinalTxUtxo, isRestoreFlow, nonOrdinalUtxos, + ordinal, + isRecover, + isRestoreOrdinalFlow = false, feeMode, error, setIsLoading, @@ -248,15 +255,17 @@ function EditFee({ setFeeRateInput(selectedFeeRate?.toString() || ''); setTotalFee(modifiedFee.toString()); } - } else if (type === 'Ordinals' && btcRecipients && ordinalTxUtxo) { - const { fee: modifiedFee, selectedFeeRate } = await getBtcFeesForOrdinalSend( - btcRecipients[0].address, - ordinalTxUtxo, + } else if (type === 'Ordinals' && btcRecipients && ordinal) { + const { fee: modifiedFee, selectedFeeRate } = await getBtcFeesForOrdinalTransaction({ + recipientAddress: btcRecipients[0].address, btcAddress, - network.type, - ordinalsUtxos || [], - mode, - ); + ordinalsAddress, + network: network.type, + ordinal, + isRecover: isRestoreOrdinalFlow, + feeMode: mode, + }); + setFeeRateInput(selectedFeeRate?.toString() || ''); setTotalFee(modifiedFee.toString()); } @@ -296,7 +305,7 @@ function EditFee({ feeMode, feeRateInput, ); - setFeeRateInput(selectedFeeRate?.toString()); + setFeeRateInput(selectedFeeRate?.toString() || ''); setTotalFee(modifiedFee.toString()); } else if (btcRecipients && selectedAccount) { const { fee: modifiedFee, selectedFeeRate } = await getBtcFees( @@ -306,7 +315,7 @@ function EditFee({ feeMode, feeRateInput, ); - setFeeRateInput(selectedFeeRate?.toString()); + setFeeRateInput(selectedFeeRate?.toString() || ''); setTotalFee(modifiedFee.toString()); } } catch (err: any) { @@ -318,21 +327,23 @@ function EditFee({ } finally { setIsNotLoading(); } - } else if (type === 'Ordinals' && btcRecipients && ordinalTxUtxo) { + } else if (type === 'Ordinals' && btcRecipients && ordinal) { try { setIsLoading(); setError(''); - const { fee: modifiedFee, selectedFeeRate } = await getBtcFeesForOrdinalSend( - btcRecipients[0].address, - ordinalTxUtxo, + const { fee: modifiedFee, selectedFeeRate } = await getBtcFeesForOrdinalTransaction({ + recipientAddress: btcRecipients[0].address, btcAddress, - network.type, - ordinalsUtxos || [], + ordinalsAddress, + network: network.type, + ordinal, + isRecover: isRestoreOrdinalFlow, feeMode, feeRateInput, - ); - setFeeRateInput(selectedFeeRate?.toString()); + }); + + setFeeRateInput(selectedFeeRate?.toString() || ''); setTotalFee(modifiedFee.toString()); } catch (err: any) { if (Number(err) === ErrorCodes.InSufficientBalance) { diff --git a/src/app/components/transactionSetting/index.tsx b/src/app/components/transactionSetting/index.tsx index 674cc19db..0a5bd1348 100644 --- a/src/app/components/transactionSetting/index.tsx +++ b/src/app/components/transactionSetting/index.tsx @@ -12,6 +12,7 @@ import { BtcUtxoDataResponse, UTXO } from '@secretkeylabs/xverse-core'; import useWalletSelector from '@hooks/useWalletSelector'; import EditNonce from './editNonce'; import EditFee from './editFee'; +import { Inscription } from '@secretkeylabs/xverse-core/types'; const ButtonContainer = styled.div((props) => ({ display: 'flex', @@ -65,6 +66,8 @@ interface Props { ordinalTxUtxo?: UTXO; isRestoreFlow?: boolean; nonOrdinalUtxos?: BtcUtxoDataResponse[]; + ordinal?: Inscription; + isRestoreOrdinalFlow?: boolean; showFeeSettings: boolean; setShowFeeSettings: (value: boolean) => void; } @@ -82,6 +85,8 @@ function TransactionSettingAlert({ ordinalTxUtxo, isRestoreFlow, nonOrdinalUtxos, + ordinal, + isRestoreOrdinalFlow = false, showFeeSettings, setShowFeeSettings, }: Props) { @@ -186,6 +191,8 @@ function TransactionSettingAlert({ ordinalTxUtxo={ordinalTxUtxo} isRestoreFlow={isRestoreFlow} nonOrdinalUtxos={nonOrdinalUtxos} + ordinal={ordinal} + isRestoreOrdinalFlow={isRestoreOrdinalFlow} /> ); } diff --git a/src/app/screens/confirmOrdinalTransaction/index.tsx b/src/app/screens/confirmOrdinalTransaction/index.tsx index 86538c167..f09acb897 100644 --- a/src/app/screens/confirmOrdinalTransaction/index.tsx +++ b/src/app/screens/confirmOrdinalTransaction/index.tsx @@ -94,7 +94,8 @@ function ConfirmOrdinalTransaction() { const btcClient = useBtcClient(); const [recipientAddress, setRecipientAddress] = useState(''); const location = useLocation(); - const { fee, feePerVByte, signedTxHex, ordinalUtxo } = location.state; + const { fee, feePerVByte, signedTxHex, ordinalUtxo, ordinal, isRestoreOrdinalFlow } = + location.state; const { isLoading, @@ -196,6 +197,8 @@ function ConfirmOrdinalTransaction() { setCurrentFee={setCurrentFee} currentFeeRate={currentFeeRate} setCurrentFeeRate={setCurrentFeeRate} + ordinal={ordinal} + isRestoreOrdinalFlow={isRestoreOrdinalFlow} > diff --git a/src/app/screens/restoreFunds/restoreOrdinals/index.tsx b/src/app/screens/restoreFunds/restoreOrdinals/index.tsx index f57dc14a5..2f32f0631 100644 --- a/src/app/screens/restoreFunds/restoreOrdinals/index.tsx +++ b/src/app/screens/restoreFunds/restoreOrdinals/index.tsx @@ -1,21 +1,19 @@ -import ActionButton from '@components/button'; -import BottomTabBar from '@components/tabBar'; -import TopRow from '@components/topRow'; -import useOrdinalDataReducer from '@hooks/stores/useOrdinalReducer'; -import useOrdinalsByAddress from '@hooks/useOrdinalsByAddress'; -import useWalletSelector from '@hooks/useWalletSelector'; -import { getBtcFiatEquivalent } from '@secretkeylabs/xverse-core/currency'; -import { - SignedBtcTx, - signOrdinalSendTransaction, -} from '@secretkeylabs/xverse-core/transactions/btc'; -import { BtcOrdinal, ErrorCodes, Inscription } from '@secretkeylabs/xverse-core/types'; import { useMutation } from '@tanstack/react-query'; -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate } from 'react-router-dom'; +import { BtcOrdinal, ErrorCodes, Inscription } from '@secretkeylabs/xverse-core/types'; +import { getBtcFiatEquivalent } from '@secretkeylabs/xverse-core/currency'; +import { SignedBtcTx, signOrdinalTransaction } from '@secretkeylabs/xverse-core/transactions/btc'; +import useWalletSelector from '@hooks/useWalletSelector'; +import useOrdinalsByAddress from '@hooks/useOrdinalsByAddress'; +import useOrdinalDataReducer from '@hooks/stores/useOrdinalReducer'; +import TopRow from '@components/topRow'; import styled from 'styled-components'; +import ActionButton from '@components/button'; +import BottomTabBar from '@components/tabBar'; import OrdinalRow from './ordinalRow'; +import useOrdinalsApi from '@hooks/useOrdinalsApi'; const RestoreFundTitle = styled.h1((props) => ({ ...props.theme.body_l, @@ -57,29 +55,30 @@ function RestoreOrdinals() { useWalletSelector(); const { setSelectedOrdinalDetails } = useOrdinalDataReducer(); const navigate = useNavigate(); + const { ordinals } = useOrdinalsByAddress(btcAddress); const [error, setError] = useState(''); const [transferringOrdinalId, setTransferringOrdinalId] = useState(null); const location = useLocation(); const isRestoreFundFlow = location.state?.isRestoreFundFlow; - - const ordinalsUtxos = useMemo(() => ordinals?.map((ord) => ord.utxo), [ordinals]); + const ordinalsApi = useOrdinalsApi(); const { isLoading, error: transactionError, mutateAsync, - } = useMutation({ + } = useMutation({ mutationFn: async (ordinal) => { - const tx = await signOrdinalSendTransaction( - ordinalsAddress, - ordinal.utxo, + const tx = await signOrdinalTransaction({ + recipientAddress: ordinalsAddress, btcAddress, - Number(selectedAccount?.id), + ordinalsAddress, + accountIndex: Number(selectedAccount?.id), seedPhrase, - network.type, - ordinalsUtxos!, - ); + network: network.type, + ordinal, + isRecover: true, + }); return tx; }, }); @@ -103,22 +102,25 @@ function RestoreOrdinals() { }; const onClickTransfer = async (selectedOrdinal: BtcOrdinal, ordinalData: Inscription) => { - setTransferringOrdinalId(selectedOrdinal.id); - - const signedTx = await mutateAsync(selectedOrdinal); - setSelectedOrdinalDetails(ordinalData); - navigate(`/confirm-ordinal-tx/${selectedOrdinal.id}`, { - state: { - signedTxHex: signedTx.signedTx, - recipientAddress: ordinalsAddress, - fee: signedTx.fee, - feePerVByte: signedTx.feePerVByte, - fiatFee: getBtcFiatEquivalent(signedTx.fee, btcFiatRate), - total: signedTx.total, - fiatTotal: getBtcFiatEquivalent(signedTx.total, btcFiatRate), - ordinalUtxo: selectedOrdinal.utxo, - }, - }); + if (selectedOrdinal) { + const selectedInscription: Inscription = await ordinalsApi.getInscription(selectedOrdinal.id); + const signedTx = await mutateAsync(selectedInscription); + setSelectedOrdinalDetails(ordinalData); + navigate(`/confirm-ordinal-tx/${selectedOrdinal.id}`, { + state: { + signedTxHex: signedTx.signedTx, + recipientAddress: ordinalsAddress, + fee: signedTx.fee, + feePerVByte: signedTx.feePerVByte, + fiatFee: getBtcFiatEquivalent(signedTx.fee, btcFiatRate), + total: signedTx.total, + fiatTotal: getBtcFiatEquivalent(signedTx.total, btcFiatRate), + ordinalUtxo: selectedOrdinal.utxo, + ordinal: selectedInscription, + isRestoreOrdinalFlow: true, + }, + }); + } }; return ( diff --git a/src/app/screens/sendOrdinal/index.tsx b/src/app/screens/sendOrdinal/index.tsx index 022825b53..a1a383c95 100644 --- a/src/app/screens/sendOrdinal/index.tsx +++ b/src/app/screens/sendOrdinal/index.tsx @@ -4,17 +4,13 @@ import SendForm from '@components/sendForm'; import BottomBar from '@components/tabBar'; import TopRow from '@components/topRow'; import useNftDataSelector from '@hooks/stores/useNftDataSelector'; -import useBtcClient from '@hooks/useBtcClient'; import { useResetUserFlow } from '@hooks/useResetUserFlow'; import useTextOrdinalContent from '@hooks/useTextOrdinalContent'; import useWalletSelector from '@hooks/useWalletSelector'; import OrdinalImage from '@screens/ordinals/ordinalImage'; import { isOrdinalOwnedByAccount } from '@secretkeylabs/xverse-core/api'; import { getBtcFiatEquivalent } from '@secretkeylabs/xverse-core/currency'; -import { - SignedBtcTx, - signOrdinalSendTransaction, -} from '@secretkeylabs/xverse-core/transactions/btc'; +import { SignedBtcTx, signOrdinalTransaction } from '@secretkeylabs/xverse-core/transactions/btc'; import { ErrorCodes, ResponseError, UTXO } from '@secretkeylabs/xverse-core/types'; import { validateBtcAddress } from '@secretkeylabs/xverse-core/wallet'; import { useMutation } from '@tanstack/react-query'; @@ -102,7 +98,6 @@ function SendOrdinal() { const { t } = useTranslation('translation', { keyPrefix: 'SEND' }); const navigate = useNavigate(); const { selectedOrdinal } = useNftDataSelector(); - const btcClient = useBtcClient(); const location = useLocation(); const { network, ordinalsAddress, btcAddress, selectedAccount, seedPhrase, btcFiatRate } = useWalletSelector(); @@ -123,25 +118,19 @@ function SendOrdinal() { data, error: txError, mutate, - } = useMutation({ + } = useMutation({ mutationFn: async (recipient) => { - const addressUtxos = await btcClient.getUnspentUtxos(ordinalsAddress); - const ordUtxo = addressUtxos.find( - (utx) => `${utx.txid}:${utx.vout}` === selectedOrdinal?.output, - ); - setOrdinalUtxo(ordUtxo); - if (ordUtxo) { - const signedTx = await signOrdinalSendTransaction( - recipient, - ordUtxo, - btcAddress, - Number(selectedAccount?.id), - seedPhrase, - network.type, - [ordUtxo], - ); - return signedTx; - } + if (!selectedOrdinal) return null; + const signedTx = await signOrdinalTransaction({ + recipientAddress: recipient, + btcAddress, + ordinalsAddress, + accountIndex: Number(selectedAccount?.id), + seedPhrase, + network: network.type, + ordinal: selectedOrdinal, + }); + return signedTx; }, }); @@ -167,6 +156,7 @@ function SendOrdinal() { total: data.total, fiatTotal: getBtcFiatEquivalent(data.total, btcFiatRate), ordinalUtxo, + ordinal: selectedOrdinal, }, }); }