From a205c2212655fd24a40805f06bc9d718203ad301 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 5 Aug 2025 10:01:34 +0200 Subject: [PATCH 1/2] feat(lightning): debug function to manual set tx as confirmed --- src/screens/Settings/DevSettings/LdkDebug.tsx | 164 +++++++++++++++++- 1 file changed, 163 insertions(+), 1 deletion(-) diff --git a/src/screens/Settings/DevSettings/LdkDebug.tsx b/src/screens/Settings/DevSettings/LdkDebug.tsx index e73a24063..498cf214b 100644 --- a/src/screens/Settings/DevSettings/LdkDebug.tsx +++ b/src/screens/Settings/DevSettings/LdkDebug.tsx @@ -1,5 +1,5 @@ import Clipboard from '@react-native-clipboard/clipboard'; -import lm from '@synonymdev/react-native-ldk'; +import lm, { ldk } from '@synonymdev/react-native-ldk'; import React, { ReactElement, memo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native'; @@ -46,11 +46,13 @@ const LdkDebug = (): ReactElement => { const dispatch = useAppDispatch(); const sheetRef = useSheetRef('forceTransfer'); const [peer, setPeer] = useState(''); + const [txid, setTxid] = useState(''); const [payingInvoice, setPayingInvoice] = useState(false); const [refreshingLdk, setRefreshingLdk] = useState(false); const [restartingLdk, setRestartingLdk] = useState(false); const [rebroadcastingLdk, setRebroadcastingLdk] = useState(false); const [spendingStuckOutputs, setSpendingStuckOutputs] = useState(false); + const [settingConfirmedTx, setSettingConfirmedTx] = useState(false); const { localBalance, remoteBalance } = useLightningBalance(); const selectedWallet = useAppSelector(selectedWalletSelector); @@ -324,6 +326,141 @@ const LdkDebug = (): ReactElement => { setPayingInvoice(false); }; + const onSetConfirmedTx = async (): Promise => { + if (!txid) { + // Attempt to grab and set txid string from clipboard. + const clipboardStr = await Clipboard.getString(); + setTxid(clipboardStr); + return; + } + + setSettingConfirmedTx(true); + try { + // Get network endpoint + const baseUrl = 'https://mempool.space/api'; + + // Fetch transaction details + const txResponse = await fetch(`${baseUrl}/tx/${txid.trim()}`); + if (!txResponse.ok) { + showToast({ + type: 'error', + title: 'Transaction Not Found', + description: 'Unable to find transaction on mempool.space', + }); + setSettingConfirmedTx(false); + return; + } + + const tx = await txResponse.json(); + + // Check if transaction is confirmed + if (!tx.status?.confirmed || !tx.status?.block_height) { + showToast({ + type: 'error', + title: 'Transaction Not Confirmed', + description: 'Transaction is not yet confirmed on the blockchain', + }); + setSettingConfirmedTx(false); + return; + } + + // Fetch transaction hex data + const txHexResponse = await fetch(`${baseUrl}/tx/${txid.trim()}/hex`); + if (!txHexResponse.ok) { + showToast({ + type: 'error', + title: 'Transaction Hex Error', + description: 'Unable to fetch transaction hex data', + }); + setSettingConfirmedTx(false); + return; + } + + const txHex = await txHexResponse.text(); + + // Fetch block header + const blockHash = tx.status.block_hash; + const blockResponse = await fetch(`${baseUrl}/block/${blockHash}/header`); + if (!blockResponse.ok) { + showToast({ + type: 'error', + title: 'Block Header Error', + description: 'Unable to fetch block header', + }); + setSettingConfirmedTx(false); + return; + } + + const blockHeader = await blockResponse.text(); + + // Validate all required parameters + if (!blockHeader) { + showToast({ + type: 'error', + title: 'Missing Block Header', + description: 'Block header is empty or invalid', + }); + setSettingConfirmedTx(false); + return; + } + + if (!txHex) { + showToast({ + type: 'error', + title: 'Missing Transaction Data', + description: 'Transaction hex data is missing', + }); + setSettingConfirmedTx(false); + return; + } + + if (!tx.status.block_height) { + showToast({ + type: 'error', + title: 'Missing Block Height', + description: 'Block height is missing or invalid', + }); + setSettingConfirmedTx(false); + return; + } + + // Call ldk.setTxConfirmed + const setTxConfirmedRes = await ldk.setTxConfirmed({ + header: blockHeader, + txData: [ + { + transaction: txHex, + pos: tx.status.block_time || 0, // Using block_time as position fallback + }, + ], + height: tx.status.block_height, + }); + + if (setTxConfirmedRes.isErr()) { + showToast({ + type: 'error', + title: 'Set Confirmed Failed', + description: setTxConfirmedRes.error.message, + }); + } else { + showToast({ + type: 'success', + title: 'Transaction Confirmed', + description: `Transaction ${txid.slice(0, 8)}... set as confirmed at height ${tx.status.block_height}`, + }); + } + } catch (error) { + showToast({ + type: 'error', + title: 'Error', + description: + error instanceof Error ? error.message : 'Unknown error occurred', + }); + } finally { + setSettingConfirmedTx(false); + } + }; + return ( @@ -356,6 +493,31 @@ const LdkDebug = (): ReactElement => { onPress={onAddPeer} /> + + Set Confirmed Transaction + + +