From 1c823ba26aef81500fc98673371bef316eef8592 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 11:31:50 -0500 Subject: [PATCH 1/8] Update dependencies and adjust balance calculation --- bun.lock | 4 ++-- client/package.json | 2 +- client/src/lib/balanceUtils.ts | 1 - client/src/screens/HomeScreen.tsx | 9 --------- scripts/captaind.toml | 12 +++++++++--- scripts/docker-compose.yml | 4 ++-- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/bun.lock b/bun.lock index 17edb59..392726a 100644 --- a/bun.lock +++ b/bun.lock @@ -65,7 +65,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.79", + "react-native-nitro-ark": "^0.0.80", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", @@ -1728,7 +1728,7 @@ "react-native-mmkv": ["react-native-mmkv@4.1.0", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-ia76WnU6dkLZxFkSSflxqFgHT2pIaML763aucEu7nMglF41oEWTdTtBu0o8a1cxbhZOaONk6KF8RQp5fLvPitA=="], - "react-native-nitro-ark": ["react-native-nitro-ark@0.0.79", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.4" } }, "sha512-PXUxmWDi6H7+ugkb2bl0LI/Qa+T23LSPlzSv46S9Xxt7q1+TrK7bZ9SAVxWgCteQ1sUQeCg29JQLcOL3b0iqWg=="], + "react-native-nitro-ark": ["react-native-nitro-ark@0.0.80", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.10" } }, "sha512-KXzW/ffKWMWjlpgoyoLOhZBjTRLnsZKt7jzFBeQs8km3o8DX905M5/pMYtKScBdbLRrbqCjYXSi0kPIVN3buHw=="], "react-native-nitro-modules": ["react-native-nitro-modules@0.31.10", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-hcvjTu9YJE9fMmnAUvhG8CxvYLpOuMQ/2eyi/S6GyrecezF6Rmk/uRQEL6v09BRFWA/xRVZNQVulQPS+2HS3mQ=="], diff --git a/client/package.json b/client/package.json index c390557..0701112 100644 --- a/client/package.json +++ b/client/package.json @@ -102,7 +102,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.79", + "react-native-nitro-ark": "^0.0.80", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", diff --git a/client/src/lib/balanceUtils.ts b/client/src/lib/balanceUtils.ts index 8ae5d4c..21b23e4 100644 --- a/client/src/lib/balanceUtils.ts +++ b/client/src/lib/balanceUtils.ts @@ -31,7 +31,6 @@ export function calculateOffchainBalance(offchain: OffchainBalanceResult): numbe return ( (offchain.pending_exit ?? 0) + (offchain.pending_lightning_send ?? 0) + - (offchain.pending_lightning_receive?.claimable ?? 0) + (offchain.pending_in_round ?? 0) + (offchain.spendable ?? 0) + (offchain.pending_board ?? 0) diff --git a/client/src/screens/HomeScreen.tsx b/client/src/screens/HomeScreen.tsx index 2e0910b..6498665 100644 --- a/client/src/screens/HomeScreen.tsx +++ b/client/src/screens/HomeScreen.tsx @@ -258,15 +258,6 @@ const HomeScreen = () => { {formatBip177(balance?.offchain.pending_lightning_send ?? 0)} - - Pending Receive - - {formatBip177( - balance?.offchain.pending_lightning_receive.claimable ?? 0, - )} - - - Pending In Round {formatBip177(balance?.offchain.pending_in_round ?? 0)} diff --git a/scripts/captaind.toml b/scripts/captaind.toml index e2e7787..5e9ef95 100644 --- a/scripts/captaind.toml +++ b/scripts/captaind.toml @@ -46,6 +46,15 @@ htlc_send_expiry_delta = 258 # invoice generation with. max_user_invoice_cltv_delta = 250 +# The duration after which a generated invoice will expire. +invoice_expiry = "10m" + +# The duration for which the server will hold inbound HTLC(s) while +# waiting for a user to claim a lightning receive. +# After this timeout the server will fail the HTLC(s) back to the sender and +# also cancel the hold invoice. +receive_htlc_forward_timeout = "30s" + # Interval to retry connecting to disconnected CLN nodes cln_reconnect_interval = "10s" @@ -64,9 +73,6 @@ invoice_check_max_delay = "10m" # FIXME invoice_poll_interval = "30s" -# Timeout on the HTLC subscription RPC call -htlc_subscription_timeout = "10m" - ln_receive_anti_dos_required = false ################ diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml index 2c5bb03..5611d15 100644 --- a/scripts/docker-compose.yml +++ b/scripts/docker-compose.yml @@ -73,7 +73,7 @@ services: condition: service_healthy captaind: - image: niteshbalusu/captaind:nightly-2025-11-21 + image: niteshbalusu/captaind:nightly-2025-12-24 volumes: - captaind:/data/captaind - ./captaind.toml:/data/captaind/captaind.toml @@ -90,7 +90,7 @@ services: condition: service_healthy bark: - image: niteshbalusu/bark:nightly-2025-11-21 + image: niteshbalusu/bark:nightly-2025-12-24 volumes: - bark:/root depends_on: From b7d37ce2bffd7b12cf98cbc7ae27d092ceb15911 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 11:38:16 -0500 Subject: [PATCH 2/8] Update types and rename API methods for payment flows --- client/src/hooks/usePayments.ts | 11 +++-------- client/src/hooks/useSendScreen.ts | 9 ++++----- client/src/lib/paymentsApi.ts | 21 ++++++++------------- client/src/lib/syncTransactions.ts | 4 ++-- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/client/src/hooks/usePayments.ts b/client/src/hooks/usePayments.ts index 1725c0d..c43b7ba 100644 --- a/client/src/hooks/usePayments.ts +++ b/client/src/hooks/usePayments.ts @@ -10,8 +10,7 @@ import { payLightningInvoice, payLightningAddress, type ArkoorPaymentResult, - type Bolt11PaymentResult, - type LnurlPaymentResult, + type LightningSendResult, type OnchainPaymentResult, boardAllArk, offboardAllArk, @@ -163,11 +162,7 @@ type SendVariables = { btcPrice?: number; }; -type SendResult = - | ArkoorPaymentResult - | Bolt11PaymentResult - | LnurlPaymentResult - | OnchainPaymentResult; +type SendResult = ArkoorPaymentResult | LightningSendResult | OnchainPaymentResult; const mapDestinationToPaymentType = (destinationType: DestinationTypes): PaymentTypes | null => { switch (destinationType) { @@ -302,7 +297,7 @@ async function handleNoahWalletPayment( destination: string, amountSat: number, comment: string | null, -): Promise | null> { +): Promise | null> { try { const [user, domain] = destination.split("@"); const lnurlEndpoint = `https://${domain}/.well-known/lnurlp/${user}`; diff --git a/client/src/hooks/useSendScreen.ts b/client/src/hooks/useSendScreen.ts index 6427e00..3b94fd2 100644 --- a/client/src/hooks/useSendScreen.ts +++ b/client/src/hooks/useSendScreen.ts @@ -11,8 +11,7 @@ import { import { useSend } from "./usePayments"; import { type ArkoorPaymentResult, - type Bolt11PaymentResult, - type LnurlPaymentResult, + type LightningSendResult, type OnchainPaymentResult, type PaymentResult, } from "../lib/paymentsApi"; @@ -169,7 +168,7 @@ export const useSendScreen = () => { }; } case "Lnurl": { - const lnurlRes = res as LnurlPaymentResult; + const lnurlRes = res as LightningSendResult; return { success: true, amount_sat: amountSat, @@ -179,11 +178,11 @@ export const useSendScreen = () => { }; } case "Bolt11": { - const bolt11Res = res as Bolt11PaymentResult; + const bolt11Res = res as LightningSendResult; return { success: true, amount_sat: amountSat, - destination: bolt11Res.bolt11_invoice, + destination: bolt11Res.invoice, preimage: bolt11Res.preimage, type: res.payment_type, }; diff --git a/client/src/lib/paymentsApi.ts b/client/src/lib/paymentsApi.ts index 74ca27d..29c0d2d 100644 --- a/client/src/lib/paymentsApi.ts +++ b/client/src/lib/paymentsApi.ts @@ -8,13 +8,12 @@ import { bolt11Invoice as bolt11InvoiceNitro, type ArkoorPaymentResult, type OnchainPaymentResult, - type Bolt11PaymentResult, - type LnurlPaymentResult, + type LightningSendResult, newAddress as newAddressNitro, onchainAddress as onchainAddressNitro, payLightningInvoice as payLightningInvoiceNitro, onchainSend as onchainSendNitro, - movements as movementsNitro, + history as historyNitro, tryClaimAllLightningReceives as tryClaimAllLightningReceivesNitro, tryClaimLightningReceive as tryClaimLightningReceiveNitro, peakAddress as peakAddressNitro, @@ -26,13 +25,9 @@ import { } from "react-native-nitro-ark"; import { Result, ResultAsync } from "neverthrow"; -export type { ArkoorPaymentResult, OnchainPaymentResult, Bolt11PaymentResult, LnurlPaymentResult }; +export type { ArkoorPaymentResult, OnchainPaymentResult, LightningSendResult }; -export type PaymentResult = - | ArkoorPaymentResult - | OnchainPaymentResult - | Bolt11PaymentResult - | LnurlPaymentResult; +export type PaymentResult = ArkoorPaymentResult | OnchainPaymentResult | LightningSendResult; export const newAddress = async (): Promise> => { return ResultAsync.fromPromise( @@ -116,7 +111,7 @@ export const sendArkoorPayment = async ( export const payLightningInvoice = async ( destination: string, amountSat: number | undefined, -): Promise> => { +): Promise> => { return ResultAsync.fromPromise(payLightningInvoiceNitro(destination, amountSat), (error) => { const e = new Error( `Failed to send bolt11 payment: ${error instanceof Error ? error.message : String(error)}`, @@ -145,7 +140,7 @@ export const payLightningAddress = async ( addr: string, amountSat: number, comment: string, -): Promise> => { +): Promise> => { return ResultAsync.fromPromise(payLightningAddressNitro(addr, amountSat, comment), (error) => { const e = new Error( `Failed to send to lightning address: ${ @@ -167,8 +162,8 @@ export const syncPendingBoards = async (): Promise> => { }); }; -export const movements = async (): Promise> => { - return ResultAsync.fromPromise(movementsNitro(), (error) => { +export const history = async (): Promise> => { + return ResultAsync.fromPromise(historyNitro(), (error) => { const e = new Error( `Failed to get movements: ${error instanceof Error ? error.message : String(error)}`, ); diff --git a/client/src/lib/syncTransactions.ts b/client/src/lib/syncTransactions.ts index 69bd873..8fbd96c 100644 --- a/client/src/lib/syncTransactions.ts +++ b/client/src/lib/syncTransactions.ts @@ -4,7 +4,7 @@ import type { Transaction } from "../types/transaction"; import uuid from "react-native-uuid"; import { getHistoricalBtcToUsdRate } from "~/hooks/useMarketData"; import logger from "~/lib/log"; -import { movements } from "./paymentsApi"; +import { history } from "./paymentsApi"; import type { BarkMovement as NitroBarkMovement, MovementStatus } from "react-native-nitro-ark"; import type { MovementKind } from "~/types/movement"; import { INCOMING_MOVEMENT_KINDS } from "~/types/movement"; @@ -27,7 +27,7 @@ const SUBSYSTEM_KIND_TO_MOVEMENT_KIND: Record = { const INCOMING_MOVEMENT_KIND_SET = new Set(INCOMING_MOVEMENT_KINDS); export const syncArkReceives = async () => { - const movementsResult = await movements(); + const movementsResult = await history(); if (movementsResult.isErr()) { log.e("Failed to fetch movements:", [movementsResult.error]); From bb1130c6d1e7fe2a581f8e1ace07cd08df8bbc60 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 11:54:15 -0500 Subject: [PATCH 3/8] Add support for Lightning Offers (Bolt12) --- client/src/components/Bip321Picker.tsx | 11 +- client/src/components/SendConfirmation.tsx | 2 +- client/src/hooks/usePayments.ts | 6 ++ client/src/hooks/useSendScreen.ts | 113 +++++++++++---------- client/src/lib/paymentsApi.ts | 13 +++ client/src/lib/sendUtils.ts | 13 ++- 6 files changed, 100 insertions(+), 58 deletions(-) diff --git a/client/src/components/Bip321Picker.tsx b/client/src/components/Bip321Picker.tsx index 12891d7..16f09f0 100644 --- a/client/src/components/Bip321Picker.tsx +++ b/client/src/components/Bip321Picker.tsx @@ -6,7 +6,7 @@ import { LightningIcon } from "~/lib/icons/Lightning"; import { OnchainIcon } from "~/lib/icons/Onchain"; import { cn } from "~/lib/utils"; -type PaymentMethod = "ark" | "lightning" | "onchain"; +type PaymentMethod = "ark" | "lightning" | "onchain" | "offer"; type Bip321PickerProps = { bip321Data: ParsedBip321; @@ -71,6 +71,15 @@ export const Bip321Picker = ({ onSelect={onSelect} /> )} + {bip321Data.offer && ( + } + label="Lightning Offer" + isSelected={selectedPaymentMethod === "offer"} + onSelect={onSelect} + /> + )} {bip321Data.onchainAddress && ( void; onCancel: () => void; isLoading?: boolean; diff --git a/client/src/hooks/usePayments.ts b/client/src/hooks/usePayments.ts index c43b7ba..993b5ea 100644 --- a/client/src/hooks/usePayments.ts +++ b/client/src/hooks/usePayments.ts @@ -9,6 +9,7 @@ import { sendArkoorPayment, payLightningInvoice, payLightningAddress, + payLightningOffer, type ArkoorPaymentResult, type LightningSendResult, type OnchainPaymentResult, @@ -174,6 +175,8 @@ const mapDestinationToPaymentType = (destinationType: DestinationTypes): Payment return "Lnurl"; case "onchain": return "Onchain"; + case "offer": + return "Bolt12"; default: return null; } @@ -222,6 +225,9 @@ export function useSend(destinationType: DestinationTypes) { result = await payLightningAddress(destination, amountSat, comment || ""); break; + case "offer": + result = await payLightningOffer(destination, amountSat); + break; default: throw new Error("Invalid destination type"); } diff --git a/client/src/hooks/useSendScreen.ts b/client/src/hooks/useSendScreen.ts index 3b94fd2..4155f39 100644 --- a/client/src/hooks/useSendScreen.ts +++ b/client/src/hooks/useSendScreen.ts @@ -47,7 +47,7 @@ export const useSendScreen = () => { const [parsedAmount, setParsedAmount] = useState(null); const [bip321Data, setBip321Data] = useState(null); const [selectedPaymentMethod, setSelectedPaymentMethod] = useState< - "ark" | "lightning" | "onchain" + "ark" | "lightning" | "onchain" | "offer" >("onchain"); const [showConfirmation, setShowConfirmation] = useState(false); const [showSuccess, setShowSuccess] = useState(false); @@ -89,6 +89,8 @@ export const useSendScreen = () => { setSelectedPaymentMethod("ark"); } else if (bip321.lightningInvoice) { setSelectedPaymentMethod("lightning"); + } else if (bip321.offer) { + setSelectedPaymentMethod("offer"); } else { setSelectedPaymentMethod("onchain"); } @@ -146,60 +148,54 @@ export const useSendScreen = () => { let displayResult: DisplayResult | null = null; - const processResult = (res: PaymentResult) => { - switch (res.payment_type) { - case "Onchain": { - const onchainRes = res as OnchainPaymentResult; - return { - success: true, - amount_sat: onchainRes.amount_sat, - destination: onchainRes.destination_address, - txid: onchainRes.txid, - type: res.payment_type, - }; - } - case "Arkoor": { - const arkoorRes = res as ArkoorPaymentResult; - return { - success: true, - amount_sat: arkoorRes.amount_sat, - destination: arkoorRes.destination_pubkey, - type: res.payment_type, - }; - } - case "Lnurl": { - const lnurlRes = res as LightningSendResult; - return { - success: true, - amount_sat: amountSat, - destination: lnurlRes.lnurl, - preimage: lnurlRes.preimage, - type: res.payment_type, - }; - } - case "Bolt11": { - const bolt11Res = res as LightningSendResult; - return { - success: true, - amount_sat: amountSat, - destination: bolt11Res.invoice, - preimage: bolt11Res.preimage, - type: res.payment_type, - }; - } - default: - log.e("Could not process the transaction result. Unknown result type:", [result]); - showAlert({ - title: "Error", - description: "Could not process the transaction result. Unknown result type.", - }); - return { - success: false, - amount_sat: 0, - destination: "", - type: "error", - }; + const processResult = (res: PaymentResult): DisplayResult => { + // Check for onchain payment (has txid and destination_address) + if ("txid" in res && "destination_address" in res) { + const onchainRes = res as OnchainPaymentResult; + return { + success: true, + amount_sat: onchainRes.amount_sat, + destination: onchainRes.destination_address, + txid: onchainRes.txid, + type: "Onchain", + }; + } + + // Check for arkoor payment (has destination_pubkey) + if ("destination_pubkey" in res) { + const arkoorRes = res as ArkoorPaymentResult; + return { + success: true, + amount_sat: arkoorRes.amount_sat, + destination: arkoorRes.destination_pubkey, + type: "Arkoor", + }; } + + // Check for lightning payment (has invoice) + if ("invoice" in res) { + const lightningRes = res as LightningSendResult; + return { + success: true, + amount_sat: lightningRes.amount, + destination: lightningRes.invoice, + preimage: lightningRes.preimage ?? undefined, + type: "Lightning", + }; + } + + // Unknown type + log.e("Could not process the transaction result. Unknown result type:", [result]); + showAlert({ + title: "Error", + description: "Could not process the transaction result. Unknown result type.", + }); + return { + success: false, + amount_sat: 0, + destination: "", + type: "error", + }; }; displayResult = processResult(result); @@ -242,6 +238,9 @@ export const useSendScreen = () => { } else if (selectedPaymentMethod === "lightning" && bip321Data.lightningInvoice) { destinationToSend = bip321Data.lightningInvoice; newDestinationType = "lightning"; + } else if (selectedPaymentMethod === "offer" && bip321Data.offer) { + destinationToSend = bip321Data.offer; + newDestinationType = "offer"; } else if (selectedPaymentMethod === "onchain" && bip321Data.onchainAddress) { destinationToSend = bip321Data.onchainAddress; newDestinationType = "onchain"; @@ -257,7 +256,11 @@ export const useSendScreen = () => { send({ destination: destinationToSend, - amountSat: newDestinationType === "lightning" && !isAmountEditable ? undefined : amountSat, + amountSat: + (newDestinationType === "lightning" || newDestinationType === "offer") && + !isAmountEditable + ? undefined + : amountSat, resolvedAmountSat: amountSat, comment: comment || null, btcPrice, diff --git a/client/src/lib/paymentsApi.ts b/client/src/lib/paymentsApi.ts index 29c0d2d..29aea19 100644 --- a/client/src/lib/paymentsApi.ts +++ b/client/src/lib/paymentsApi.ts @@ -5,6 +5,7 @@ import { offboardAll as offboardAllNitro, sendArkoorPayment as sendArkoorPaymentNitro, payLightningAddress as payLightningAddressNitro, + payLightningOffer as payLightningOfferNitro, bolt11Invoice as bolt11InvoiceNitro, type ArkoorPaymentResult, type OnchainPaymentResult, @@ -120,6 +121,18 @@ export const payLightningInvoice = async ( }); }; +export const payLightningOffer = async ( + destination: string, + amountSat: number | undefined, +): Promise> => { + return ResultAsync.fromPromise(payLightningOfferNitro(destination, amountSat), (error) => { + const e = new Error( + `Failed to send bolt12 payment: ${error instanceof Error ? error.message : String(error)}`, + ); + return e; + }); +}; + export const onchainSend = async ({ destination, amountSat, diff --git a/client/src/lib/sendUtils.ts b/client/src/lib/sendUtils.ts index 0bf3dfd..24faeed 100644 --- a/client/src/lib/sendUtils.ts +++ b/client/src/lib/sendUtils.ts @@ -12,12 +12,20 @@ import { isNetworkMatch } from "./utils"; const log = logger("sendUtils"); -export type DestinationTypes = "onchain" | "lightning" | "ark" | "lnurl" | "bip321" | null; +export type DestinationTypes = + | "onchain" + | "lightning" + | "ark" + | "lnurl" + | "bip321" + | "offer" + | null; export type ParsedBip321 = { onchainAddress?: string; arkAddress?: string; lightningInvoice?: string; + offer?: string; }; export type ParsedDestination = { @@ -106,6 +114,9 @@ export const parseBip321Uri = (uri: string): ParsedDestination => { case "lightning": bip321.lightningInvoice = method.value; break; + case "offer": + bip321.offer = method.value; + break; } } From 02b1a106358ae2b5525ea755b50cb56772d804b3 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 12:40:10 -0500 Subject: [PATCH 4/8] Update Ark-related dependencies and implement payment checks --- Cargo.lock | 13 +++---- bun.lock | 4 +-- client/package.json | 2 +- client/src/hooks/usePayments.ts | 63 ++++++++++++++++++++++++++------- client/src/lib/paymentsApi.ts | 16 +++++++++ client/src/types/transaction.ts | 6 ++-- server/Cargo.toml | 2 +- server/src/ark_client.rs | 4 +-- 8 files changed, 83 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4168d7..f225c0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,12 +279,13 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "ark-lib" -version = "0.1.0-beta.2" -source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.2#2d81f096ad41e866eeb8262830d8f59d4567096a" +version = "0.1.0-beta.5" +source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.5#916e0d61d0fa1be274eb731a545a73774e2df492" dependencies = [ "bark-bitcoin-ext", "bitcoin", "chrono", + "getrandom 0.3.3", "hex-conservative 0.3.0", "lazy_static", "lightning", @@ -868,8 +869,8 @@ dependencies = [ [[package]] name = "bark-bitcoin-ext" -version = "0.1.0-beta.2" -source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.2#2d81f096ad41e866eeb8262830d8f59d4567096a" +version = "0.1.0-beta.5" +source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.5#916e0d61d0fa1be274eb731a545a73774e2df492" dependencies = [ "bitcoin", "lazy_static", @@ -880,8 +881,8 @@ dependencies = [ [[package]] name = "bark-server-rpc" -version = "0.1.0-beta.2" -source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.2#2d81f096ad41e866eeb8262830d8f59d4567096a" +version = "0.1.0-beta.5" +source = "git+https://gitlab.com/ark-bitcoin/bark?tag=server-0.1.0-beta.5#916e0d61d0fa1be274eb731a545a73774e2df492" dependencies = [ "ark-lib", "bitcoin", diff --git a/bun.lock b/bun.lock index 392726a..cf50d8b 100644 --- a/bun.lock +++ b/bun.lock @@ -65,7 +65,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.80", + "react-native-nitro-ark": "^0.0.81", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", @@ -1728,7 +1728,7 @@ "react-native-mmkv": ["react-native-mmkv@4.1.0", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-ia76WnU6dkLZxFkSSflxqFgHT2pIaML763aucEu7nMglF41oEWTdTtBu0o8a1cxbhZOaONk6KF8RQp5fLvPitA=="], - "react-native-nitro-ark": ["react-native-nitro-ark@0.0.80", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.10" } }, "sha512-KXzW/ffKWMWjlpgoyoLOhZBjTRLnsZKt7jzFBeQs8km3o8DX905M5/pMYtKScBdbLRrbqCjYXSi0kPIVN3buHw=="], + "react-native-nitro-ark": ["react-native-nitro-ark@0.0.81", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.10" } }, "sha512-6dBVpqeoDRJJwFPpAo0nJiVzwZr6OvHnTEoVIXj+S+IMFCt7EC0ca4aiCl17PwVTvVMxdvmuBUt4VlM/RcsLaQ=="], "react-native-nitro-modules": ["react-native-nitro-modules@0.31.10", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-hcvjTu9YJE9fMmnAUvhG8CxvYLpOuMQ/2eyi/S6GyrecezF6Rmk/uRQEL6v09BRFWA/xRVZNQVulQPS+2HS3mQ=="], diff --git a/client/package.json b/client/package.json index 0701112..33581b5 100644 --- a/client/package.json +++ b/client/package.json @@ -102,7 +102,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.80", + "react-native-nitro-ark": "^0.0.81", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", diff --git a/client/src/hooks/usePayments.ts b/client/src/hooks/usePayments.ts index 993b5ea..82157f5 100644 --- a/client/src/hooks/usePayments.ts +++ b/client/src/hooks/usePayments.ts @@ -10,6 +10,7 @@ import { payLightningInvoice, payLightningAddress, payLightningOffer, + checkLightningPayment, type ArkoorPaymentResult, type LightningSendResult, type OnchainPaymentResult, @@ -207,10 +208,19 @@ export function useSend(destinationType: DestinationTypes) { } result = await sendArkoorPayment(destination, amountSat); break; - case "lightning": - result = await payLightningInvoice(destination, amountSat); - break; - case "lnurl": + case "lightning": { + const lnResult = await payLightningInvoice(destination, amountSat); + if (lnResult.isErr()) { + throw lnResult.error; + } + const checkResult = await checkLightningPayment(lnResult.value.payment_hash, true); + if (checkResult.isErr()) { + throw checkResult.error; + } + lnResult.value.preimage = checkResult.value; + return lnResult.value; + } + case "lnurl": { if (amountSat === undefined) { throw new Error("Amount is required for LNURL payments"); } @@ -218,16 +228,44 @@ export function useSend(destinationType: DestinationTypes) { if (destination.toLowerCase().endsWith(getLnurlDomain())) { const noahResult = await handleNoahWalletPayment(destination, amountSat, comment); if (noahResult) { - result = noahResult; - break; + if (noahResult.isErr()) { + throw noahResult.error; + } + const data = noahResult.value; + if ("payment_hash" in data) { + const checkResult = await checkLightningPayment(data.payment_hash, true); + if (checkResult.isErr()) { + throw checkResult.error; + } + data.preimage = checkResult.value; + } + return data; } } - result = await payLightningAddress(destination, amountSat, comment || ""); - break; - case "offer": - result = await payLightningOffer(destination, amountSat); - break; + const lnurlResult = await payLightningAddress(destination, amountSat, comment || ""); + if (lnurlResult.isErr()) { + throw lnurlResult.error; + } + const checkResult = await checkLightningPayment(lnurlResult.value.payment_hash, true); + if (checkResult.isErr()) { + throw checkResult.error; + } + lnurlResult.value.preimage = checkResult.value; + return lnurlResult.value; + } + case "offer": { + const offerResult = await payLightningOffer(destination, amountSat); + if (offerResult.isErr()) { + throw offerResult.error; + } + const checkResult = await checkLightningPayment(offerResult.value.payment_hash, true); + if (checkResult.isErr()) { + throw checkResult.error; + } + offerResult.value.preimage = checkResult.value; + return offerResult.value; + } default: throw new Error("Invalid destination type"); } @@ -324,7 +362,8 @@ async function handleNoahWalletPayment( return await sendArkoorPayment(callbackJson.ark, amountSat); } else if (callbackJson.pr) { log.d("Paying via Lightning Invoice from LNURL"); - return await payLightningInvoice(callbackJson.pr, amountSat); + const lnResult = await payLightningInvoice(callbackJson.pr, amountSat); + return lnResult; } else { log.w( "Invalid LNURL callback response for optimized Noah payment, falling back to standard LNURL.", diff --git a/client/src/lib/paymentsApi.ts b/client/src/lib/paymentsApi.ts index 29aea19..8096cf2 100644 --- a/client/src/lib/paymentsApi.ts +++ b/client/src/lib/paymentsApi.ts @@ -6,6 +6,7 @@ import { sendArkoorPayment as sendArkoorPaymentNitro, payLightningAddress as payLightningAddressNitro, payLightningOffer as payLightningOfferNitro, + checkLightningPayment as checkLightningPaymentNitro, bolt11Invoice as bolt11InvoiceNitro, type ArkoorPaymentResult, type OnchainPaymentResult, @@ -165,6 +166,21 @@ export const payLightningAddress = async ( }); }; +export const checkLightningPayment = async ( + paymentHash: string, + wait: boolean = false, +): Promise> => { + return ResultAsync.fromPromise(checkLightningPaymentNitro(paymentHash, wait), (error) => { + const e = new Error( + `Failed to check lightning payment: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + + return e; + }); +}; + export const syncPendingBoards = async (): Promise> => { return ResultAsync.fromPromise(syncPendingBoardsNitro(), (error) => { const e = new Error( diff --git a/client/src/types/transaction.ts b/client/src/types/transaction.ts index 0ce9d22..6a1fad9 100644 --- a/client/src/types/transaction.ts +++ b/client/src/types/transaction.ts @@ -1,4 +1,6 @@ -import type { MovementStatus, PaymentTypes } from "react-native-nitro-ark"; +import type { MovementStatus } from "react-native-nitro-ark"; + +export type PaymentTypes = "Bolt11" | "Bolt12" | "Lnurl" | "Arkoor" | "Onchain"; import type { MovementKind } from "./movement"; export type Transaction = { @@ -28,8 +30,6 @@ export type Transaction = { exitedVtxos?: string[]; }; -export type { PaymentTypes }; - export type MovementDestination = { destination: string; amount_sat: number; diff --git a/server/Cargo.toml b/server/Cargo.toml index 633c213..3416361 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -23,7 +23,7 @@ tokio-cron-scheduler = { version = "0.15.1", features = ["english"] } serde_json = "1.0.145" random_word = { version = "0.5.0", features = ["en"] } futures-util = "0.3.30" -bark-server-rpc = { git = "https://gitlab.com/ark-bitcoin/bark", tag = "server-0.1.0-beta.2" } +bark-server-rpc = { git = "https://gitlab.com/ark-bitcoin/bark", tag = "server-0.1.0-beta.5" } deadpool-redis = { version = "0.22.0", features = ["serde", "rt_tokio_1"] } redis = { version = "0.32.7", features = ["aio", "tokio-comp"] } diff --git a/server/src/ark_client.rs b/server/src/ark_client.rs index 8c62567..fb5cc02 100644 --- a/server/src/ark_client.rs +++ b/server/src/ark_client.rs @@ -103,7 +103,7 @@ async fn establish_connection_and_process( while let Some(item) = stream.next().await { match item { Ok(round_event) => { - if let Some(round_event::Event::Start(event)) = round_event.event { + if let Some(round_event::Event::Attempt(event)) = round_event.event { round_counter += 1; // Handle offboarding requests for every round @@ -118,7 +118,7 @@ async fn establish_connection_and_process( service = "ark_client", event = "maintenance_triggered", round_seq = event.round_seq, - offboard_feerate = event.offboard_feerate_sat_vkb, + round_attempt_challenge = %event.round_attempt_challenge.to_lower_hex_string(), "triggering maintenance" ); let app_state_clone = app_state.clone(); From 86714bca9c2b44ba883937183923ad0394961b6c Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 12:43:59 -0500 Subject: [PATCH 5/8] Update NitroArk pod version to 0.0.81 --- client/ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index 6c6b1b2..ac98b8f 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -262,7 +262,7 @@ PODS: - hermes-engine/Pre-built (= 0.81.5) - hermes-engine/Pre-built (0.81.5) - MMKVCore (2.2.4) - - NitroArk (0.0.79): + - NitroArk (0.0.81): - hermes-engine - NitroModules - RCTRequired @@ -2976,7 +2976,7 @@ SPEC CHECKSUMS: FBLazyVector: e95a291ad2dadb88e42b06e0c5fb8262de53ec12 hermes-engine: 8bb0bdb1bf49c3bbc17cf4c2d02dcc2f706ab555 MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df - NitroArk: e29874d62421cb89d89c67e938624fb6c3aabf08 + NitroArk: 5c165e43e32f663cdcf0f0bfc95c89a758c1e997 NitroMmkv: a7f267ea1359e25072960fc17f8b2c2e023d7bac NitroModules: b7b51ba7f49acf5c4c13a56f2b0037b5f7bf55a7 NoahTools: efea1336628719c3ab4a565f3c03d2deeadd3d14 From 96d72f1979969cedf553e4b3356e522a129e07c8 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 19:50:41 -0500 Subject: [PATCH 6/8] Update react-native-nitro-ark to version 0.0.82 --- bun.lock | 4 ++-- client/package.json | 2 +- client/src/hooks/usePayments.ts | 4 ++-- client/src/lib/paymentsApi.ts | 3 ++- client/src/lib/pushNotifications.ts | 2 +- client/src/screens/BackupSettingsScreen.tsx | 18 ++++++++++++++++++ client/src/screens/DebugScreen.tsx | 4 ++-- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/bun.lock b/bun.lock index cf50d8b..d8188cd 100644 --- a/bun.lock +++ b/bun.lock @@ -65,7 +65,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.81", + "react-native-nitro-ark": "^0.0.82", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", @@ -1728,7 +1728,7 @@ "react-native-mmkv": ["react-native-mmkv@4.1.0", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-ia76WnU6dkLZxFkSSflxqFgHT2pIaML763aucEu7nMglF41oEWTdTtBu0o8a1cxbhZOaONk6KF8RQp5fLvPitA=="], - "react-native-nitro-ark": ["react-native-nitro-ark@0.0.81", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.10" } }, "sha512-6dBVpqeoDRJJwFPpAo0nJiVzwZr6OvHnTEoVIXj+S+IMFCt7EC0ca4aiCl17PwVTvVMxdvmuBUt4VlM/RcsLaQ=="], + "react-native-nitro-ark": ["react-native-nitro-ark@0.0.82", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "^0.31.10" } }, "sha512-IrcSNWdH/5UqZPw9uKfRsQtzEOFvLxPDcz5lUvWxgaCCKMkRRzfZ7QnQ8lAgktokXIMbQil92wityN8iMdz/Vw=="], "react-native-nitro-modules": ["react-native-nitro-modules@0.31.10", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-hcvjTu9YJE9fMmnAUvhG8CxvYLpOuMQ/2eyi/S6GyrecezF6Rmk/uRQEL6v09BRFWA/xRVZNQVulQPS+2HS3mQ=="], diff --git a/client/package.json b/client/package.json index 33581b5..4d67d68 100644 --- a/client/package.json +++ b/client/package.json @@ -102,7 +102,7 @@ "react-native-gesture-handler": "~2.28.0", "react-native-keychain": "^10.0.0", "react-native-mmkv": "^4.1.0", - "react-native-nitro-ark": "^0.0.81", + "react-native-nitro-ark": "^0.0.82", "react-native-nitro-modules": "^0.31.10", "react-native-qrcode-svg": "^6.3.21", "react-native-reanimated": "~4.1.6", diff --git a/client/src/hooks/usePayments.ts b/client/src/hooks/usePayments.ts index 82157f5..8417104 100644 --- a/client/src/hooks/usePayments.ts +++ b/client/src/hooks/usePayments.ts @@ -315,11 +315,11 @@ export function useCheckAndClaimLnReceive() { log.d("Claim result", [result]); - if (result.isOk()) { + if (result.isOk() && result.value && result.value.length > 0) { return { amountSat }; } - log.d(`Attempt ${i + 1}/${maxAttempts} failed:`, [result.error.message]); + log.d(`Attempt ${i + 1}/${maxAttempts} failed:`, [result]); if (i < maxAttempts - 1) { await new Promise((resolve) => setTimeout(resolve, intervalMs)); diff --git a/client/src/lib/paymentsApi.ts b/client/src/lib/paymentsApi.ts index 8096cf2..46fdf76 100644 --- a/client/src/lib/paymentsApi.ts +++ b/client/src/lib/paymentsApi.ts @@ -24,6 +24,7 @@ import { Bolt11Invoice, BoardResult, RoundStatus, + BarkVtxo, } from "react-native-nitro-ark"; import { Result, ResultAsync } from "neverthrow"; @@ -204,7 +205,7 @@ export const history = async (): Promise> => { export const tryClaimLightningReceive = async ( paymentHash: string, wait: boolean = false, -): Promise> => { +): Promise> => { return ResultAsync.fromPromise(tryClaimLightningReceiveNitro(paymentHash, wait), (error) => { const e = new Error( `Failed to check and claim lightning receive: ${error instanceof Error ? error.message : String(error)}`, diff --git a/client/src/lib/pushNotifications.ts b/client/src/lib/pushNotifications.ts index c8d15bb..ba2c37b 100644 --- a/client/src/lib/pushNotifications.ts +++ b/client/src/lib/pushNotifications.ts @@ -148,7 +148,7 @@ TaskManager.defineTask( true, ); - if (claimResult.isOk()) { + if (claimResult.isOk() && claimResult.value && claimResult.value.length > 0) { const sats = notificationData.amount / 1000; await Notifications.scheduleNotificationAsync({ content: { diff --git a/client/src/screens/BackupSettingsScreen.tsx b/client/src/screens/BackupSettingsScreen.tsx index b20efcb..0d5d05a 100644 --- a/client/src/screens/BackupSettingsScreen.tsx +++ b/client/src/screens/BackupSettingsScreen.tsx @@ -13,6 +13,7 @@ import { CheckCircle } from "lucide-react-native"; import { NoahActivityIndicator } from "../components/ui/NoahActivityIndicator"; import { NoahButton } from "~/components/ui/NoahButton"; import * as Haptics from "expo-haptics"; +import { AlertCircle } from "lucide-react-native"; export const BackupSettingsScreen = () => { const navigation = useNavigation(); @@ -29,6 +30,8 @@ export const BackupSettingsScreen = () => { const [showBackups, setShowBackups] = useState(false); const [showSuccessAlert, setShowSuccessAlert] = useState(false); + const [showErrorAlert, setShowErrorAlert] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); return ( @@ -56,6 +59,13 @@ export const BackupSettingsScreen = () => { )} + {showErrorAlert && ( + + Backup Failed + {errorMessage ?? "An unknown error occurred"} + + )} + { const result = await triggerBackup(); @@ -65,6 +75,9 @@ export const BackupSettingsScreen = () => { setTimeout(() => setShowSuccessAlert(false), 3000); } else { await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); + setErrorMessage(result.error.message); + setShowErrorAlert(true); + setTimeout(() => setShowErrorAlert(false), 5000); } }} className="mb-4" @@ -80,6 +93,11 @@ export const BackupSettingsScreen = () => { const result = await listBackups(); if (result.isOk()) { setShowBackups(true); + } else { + await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); + setErrorMessage(result.error.message); + setShowErrorAlert(true); + setTimeout(() => setShowErrorAlert(false), 5000); } }} className="mb-8 border-border" diff --git a/client/src/screens/DebugScreen.tsx b/client/src/screens/DebugScreen.tsx index bf295ec..545842b 100644 --- a/client/src/screens/DebugScreen.tsx +++ b/client/src/screens/DebugScreen.tsx @@ -203,9 +203,9 @@ const DebugScreen = () => { {resultMessage && ( - {resultMessage} + {resultMessage} {copied ? "Copied!" : "Long press to copy"} From d5a6bb20fd53838b7a390a97b7d07a29c75ddb4d Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Wed, 24 Dec 2025 19:52:58 -0500 Subject: [PATCH 7/8] Bump NitroArk iOS library version to 0.0.82 --- client/ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index ac98b8f..09e02cc 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -262,7 +262,7 @@ PODS: - hermes-engine/Pre-built (= 0.81.5) - hermes-engine/Pre-built (0.81.5) - MMKVCore (2.2.4) - - NitroArk (0.0.81): + - NitroArk (0.0.82): - hermes-engine - NitroModules - RCTRequired @@ -2976,7 +2976,7 @@ SPEC CHECKSUMS: FBLazyVector: e95a291ad2dadb88e42b06e0c5fb8262de53ec12 hermes-engine: 8bb0bdb1bf49c3bbc17cf4c2d02dcc2f706ab555 MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df - NitroArk: 5c165e43e32f663cdcf0f0bfc95c89a758c1e997 + NitroArk: 61ef84ad85ad0ee2edd5ec319373f8f6c165c1c9 NitroMmkv: a7f267ea1359e25072960fc17f8b2c2e023d7bac NitroModules: b7b51ba7f49acf5c4c13a56f2b0037b5f7bf55a7 NoahTools: efea1336628719c3ab4a565f3c03d2deeadd3d14 From 79b692c846964ca19445174d608049cd9d52ba04 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Mon, 29 Dec 2025 09:57:59 -0500 Subject: [PATCH 8/8] gemini suggestion fixes --- client/src/hooks/usePayments.ts | 62 ++++++++++++------------------- client/src/hooks/useSendScreen.ts | 26 +++++-------- 2 files changed, 32 insertions(+), 56 deletions(-) diff --git a/client/src/hooks/usePayments.ts b/client/src/hooks/usePayments.ts index 8417104..f5bdd09 100644 --- a/client/src/hooks/usePayments.ts +++ b/client/src/hooks/usePayments.ts @@ -166,6 +166,21 @@ type SendVariables = { type SendResult = ArkoorPaymentResult | LightningSendResult | OnchainPaymentResult; +const awaitLightningPayment = async ( + paymentPromise: Promise>, +): Promise => { + const result = await paymentPromise; + if (result.isErr()) { + throw result.error; + } + const checkResult = await checkLightningPayment(result.value.payment_hash, true); + if (checkResult.isErr()) { + throw checkResult.error; + } + result.value.preimage = checkResult.value; + return result.value; +}; + const mapDestinationToPaymentType = (destinationType: DestinationTypes): PaymentTypes | null => { switch (destinationType) { case "ark": @@ -208,18 +223,8 @@ export function useSend(destinationType: DestinationTypes) { } result = await sendArkoorPayment(destination, amountSat); break; - case "lightning": { - const lnResult = await payLightningInvoice(destination, amountSat); - if (lnResult.isErr()) { - throw lnResult.error; - } - const checkResult = await checkLightningPayment(lnResult.value.payment_hash, true); - if (checkResult.isErr()) { - throw checkResult.error; - } - lnResult.value.preimage = checkResult.value; - return lnResult.value; - } + case "lightning": + return awaitLightningPayment(payLightningInvoice(destination, amountSat)); case "lnurl": { if (amountSat === undefined) { throw new Error("Amount is required for LNURL payments"); @@ -233,39 +238,18 @@ export function useSend(destinationType: DestinationTypes) { } const data = noahResult.value; if ("payment_hash" in data) { - const checkResult = await checkLightningPayment(data.payment_hash, true); - if (checkResult.isErr()) { - throw checkResult.error; - } - data.preimage = checkResult.value; + return awaitLightningPayment( + Promise.resolve(noahResult as Result), + ); } return data; } } - const lnurlResult = await payLightningAddress(destination, amountSat, comment || ""); - if (lnurlResult.isErr()) { - throw lnurlResult.error; - } - const checkResult = await checkLightningPayment(lnurlResult.value.payment_hash, true); - if (checkResult.isErr()) { - throw checkResult.error; - } - lnurlResult.value.preimage = checkResult.value; - return lnurlResult.value; - } - case "offer": { - const offerResult = await payLightningOffer(destination, amountSat); - if (offerResult.isErr()) { - throw offerResult.error; - } - const checkResult = await checkLightningPayment(offerResult.value.payment_hash, true); - if (checkResult.isErr()) { - throw checkResult.error; - } - offerResult.value.preimage = checkResult.value; - return offerResult.value; + return awaitLightningPayment(payLightningAddress(destination, amountSat, comment || "")); } + case "offer": + return awaitLightningPayment(payLightningOffer(destination, amountSat)); default: throw new Error("Invalid destination type"); } diff --git a/client/src/hooks/useSendScreen.ts b/client/src/hooks/useSendScreen.ts index 4155f39..d263851 100644 --- a/client/src/hooks/useSendScreen.ts +++ b/client/src/hooks/useSendScreen.ts @@ -9,12 +9,7 @@ import { ParsedBip321, } from "../lib/sendUtils"; import { useSend } from "./usePayments"; -import { - type ArkoorPaymentResult, - type LightningSendResult, - type OnchainPaymentResult, - type PaymentResult, -} from "../lib/paymentsApi"; +import { type PaymentResult } from "../lib/paymentsApi"; import { useQRCodeScanner } from "~/hooks/useQRCodeScanner"; import { useBtcToUsdRate } from "./useMarketData"; import { satsToUsd, usdToSats } from "../lib/utils"; @@ -151,35 +146,32 @@ export const useSendScreen = () => { const processResult = (res: PaymentResult): DisplayResult => { // Check for onchain payment (has txid and destination_address) if ("txid" in res && "destination_address" in res) { - const onchainRes = res as OnchainPaymentResult; return { success: true, - amount_sat: onchainRes.amount_sat, - destination: onchainRes.destination_address, - txid: onchainRes.txid, + amount_sat: res.amount_sat, + destination: res.destination_address, + txid: res.txid, type: "Onchain", }; } // Check for arkoor payment (has destination_pubkey) if ("destination_pubkey" in res) { - const arkoorRes = res as ArkoorPaymentResult; return { success: true, - amount_sat: arkoorRes.amount_sat, - destination: arkoorRes.destination_pubkey, + amount_sat: res.amount_sat, + destination: res.destination_pubkey, type: "Arkoor", }; } // Check for lightning payment (has invoice) if ("invoice" in res) { - const lightningRes = res as LightningSendResult; return { success: true, - amount_sat: lightningRes.amount, - destination: lightningRes.invoice, - preimage: lightningRes.preimage ?? undefined, + amount_sat: res.amount, + destination: res.invoice, + preimage: res.preimage ?? undefined, type: "Lightning", }; }