diff --git a/ios/LndMobile/Lnd.swift b/ios/LndMobile/Lnd.swift index 943cbf509..14375fe59 100644 --- a/ios/LndMobile/Lnd.swift +++ b/ios/LndMobile/Lnd.swift @@ -122,6 +122,7 @@ open class Lnd { "VerifyMessage": { bytes, cb in LndmobileVerifyMessage(bytes, cb) }, "SignMessage": { bytes, cb in LndmobileSignMessage(bytes, cb) }, "SignerSignMessage": { bytes, cb in LndmobileSignerSignMessage(bytes, cb) }, + "WalletKitListSweeps": { bytes, cb in LndmobileWalletKitListSweeps(bytes, cb) }, // autopilot "AutopilotStatus": { bytes, cb in LndmobileAutopilotStatus(bytes, cb) }, diff --git a/src/components/PendingChannelCard.tsx b/src/components/PendingChannelCard.tsx index 99dd3d13c..1fa782d0f 100644 --- a/src/components/PendingChannelCard.tsx +++ b/src/components/PendingChannelCard.tsx @@ -5,7 +5,7 @@ import Long from "long"; import BigNumber from "bignumber.js"; import { style } from "./ChannelCard"; -import { lnrpc } from "../../proto/lightning"; +import { lnrpc, walletrpc } from "../../proto/lightning"; import { blixtTheme } from "../native-base-theme/variables/commonColor"; import { useStoreActions, useStoreState } from "../state/store"; import { identifyService, lightningServices } from "../utils/lightning-services"; @@ -16,6 +16,7 @@ import { getUnitNice, valueBitcoin, valueFiat } from "../utils/bitcoin-units"; import { useTranslation } from "react-i18next"; import { namespaces } from "../i18n/i18n.constants"; import { Alert } from "../utils/alert"; +import { pendingSweeps } from "../lndmobile/wallet"; const dataLossChannelState = "ChanStatusLocalDataLoss|ChanStatusRestored"; @@ -98,6 +99,54 @@ export const PendingChannelCard = ({ channel, type, alias }: IPendingChannelCard ); }; + const dragForceCloseAnchor = async ( + channel: lnrpc.PendingChannelsResponse.IWaitingCloseChannel, + ) => { + Alert.prompt(t("channel.bumpFee"), t("channel.bumpFeeAlerts.enterFeeRate"), [ + { + text: t("buttons.cancel", { ns: namespaces.common }), + style: "cancel", + onPress: () => {}, + }, + { + text: "OK", + onPress: async (feeRate) => { + if (!feeRate) { + Alert.alert(t("channel.bumpFeeAlerts.missingFeeRate")); + return; + } + + const feeRateNumber = Number.parseInt(feeRate); + + // Follows anchor sweep code in bumpForceCloseFee.go in lnd/cmd/lncli/walletrpc_active.go + + //& Fetch waiting close channel commitments. + const sweeps = await pendingSweeps(); + + //& Retrieve pending sweeps. + const commitments = [channel.commitments?.localTxid, channel.commitments?.remoteTxid]; + + //& Match pending sweeps with commitments of the channel for which a bump + //& is requested and bump their fees. + for (const sweep of sweeps.pendingSweeps) { + //& Only bump anchor sweeps. + if (sweep.witnessType !== walletrpc.WitnessType.COMMITMENT_ANCHOR) { + continue; + } + + if (commitments.includes(sweep.outpoint?.txidStr)) { + await bumpFee({ + txid: sweep.outpoint?.txidStr ?? "", + index: sweep.outpoint?.outputIndex ?? 0, + feeRate: feeRateNumber, + }); + } + } + }, + }, + ]); + }; + const bumpChannelFee = async (channel: lnrpc.PendingChannelsResponse.IPendingOpenChannel) => { if (!channel.channel || !channel.channel.channelPoint) { Alert.alert(t("msg.error", { ns: namespaces.common })); @@ -391,6 +440,18 @@ export const PendingChannelCard = ({ channel, type, alias }: IPendingChannelCard )} + + + + + )} {type === "FORCE_CLOSING" && ( diff --git a/src/lndmobile/wallet.ts b/src/lndmobile/wallet.ts index 7f289cb04..ed5b3a0c5 100644 --- a/src/lndmobile/wallet.ts +++ b/src/lndmobile/wallet.ts @@ -2,7 +2,7 @@ import * as base64 from "base64-js"; import { sendCommand, sendStreamCommand, decodeStreamResult } from "./utils"; import { stringToUint8Array } from "../utils"; -import { lnrpc, signrpc } from "../../proto/lightning"; +import { lnrpc, signrpc, walletrpc } from "../../proto/lightning"; /** * @throws @@ -156,6 +156,21 @@ export const signMessage = async (keyFamily: number, keyIndex: number, msg: Uint return response; }; + +/** + * @throws + */ +export const pendingSweeps = async (): Promise => { + const response = await sendCommand({ + request: walletrpc.PendingSweepsRequest, + response: walletrpc.PendingSweepsResponse, + method: "WalletKitPendingSweeps", + options: { + }, + }); + return response; +}; + // TODO exception? // TODO move to a more appropriate file? export const subscribeInvoices = async (): Promise => { diff --git a/src/windows/InitProcess/DEV_Commands.tsx b/src/windows/InitProcess/DEV_Commands.tsx index 41f8a4ac3..ba3c4cb5d 100644 --- a/src/windows/InitProcess/DEV_Commands.tsx +++ b/src/windows/InitProcess/DEV_Commands.tsx @@ -45,7 +45,7 @@ import { getTransaction, getTransactions, } from "../../storage/database/transaction"; -import { genSeed, initWallet, signMessage } from "../../lndmobile/wallet"; +import { genSeed, initWallet, pendingSweeps, signMessage } from "../../lndmobile/wallet"; import { getPin, getWalletPassword } from "../../storage/keystore"; import { lnrpc, routerrpc } from "../../../proto/lightning"; import { modifyStatus, queryScores, status } from "../../lndmobile/autopilot"; @@ -71,6 +71,7 @@ import { blixtTheme } from "../../native-base-theme/variables/commonColor"; import { generateSecureRandom } from "react-native-securerandom"; import { localNotification } from "../../utils/push-notification"; import { sendCommand } from "../../lndmobile/utils"; +import { getCFilter } from "../../lndmobile/neutrino"; let iCloudStorage: any; console.log(PLATFORM); @@ -145,6 +146,17 @@ export default function DEV_Commands({ navigation, continueCallback }: IProps) { )} Random: +