Skip to content

Commit 64596a1

Browse files
add parsing logic for payment methods and fix lightning send bug with amounts
1 parent 9ba48c3 commit 64596a1

8 files changed

Lines changed: 117 additions & 51 deletions

File tree

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"editor.formatOnSave": true,
3-
"editor.defaultFormatter": "esbenp.prettier-vscode"
3+
"editor.defaultFormatter": "esbenp.prettier-vscode",
4+
"cmake.sourceDirectory": "/Users/niteshchowdharybalusu/Documents/noah/nitromodules/noah-tools/android"
45
}

bun.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ PODS:
7070
- hermes-engine (0.79.4):
7171
- hermes-engine/Pre-built (= 0.79.4)
7272
- hermes-engine/Pre-built (0.79.4)
73-
- NitroArk (0.0.20):
73+
- NitroArk (0.0.22):
7474
- DoubleConversion
7575
- glog
7676
- hermes-engine
@@ -2561,7 +2561,7 @@ SPEC CHECKSUMS:
25612561
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
25622562
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
25632563
hermes-engine: 8b5a5eb386b990287d072fd7b6f6ebd9544dd251
2564-
NitroArk: c85047d1793693c9a66cc3bb38d19836759c9304
2564+
NitroArk: b20eef0d0cbeb910ef06b60532f031c47b7c9520
25652565
NitroModules: f36b94e48ff1705fc6b84bc1953f40e2da4196c2
25662566
NoahTools: 12a4e8705c339d40f7218c725de658f4a62ef646
25672567
RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"react-native-edge-to-edge": "^1.6.1",
7272
"react-native-keychain": "^10.0.0",
7373
"react-native-mmkv": "^3.3.0",
74-
"react-native-nitro-ark": "^0.0.20",
74+
"react-native-nitro-ark": "^0.0.22",
7575
"react-native-nitro-modules": "0.26.3",
7676
"react-native-qrcode-svg": "^6.3.15",
7777
"react-native-reanimated": "~3.17.4",

scripts/download_ark_binaries.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const path = require("path");
33
const https = require("https");
44
const { execSync } = require("child_process");
55

6-
const NITRO_ARK_VERSION = "v0.0.19";
6+
const NITRO_ARK_VERSION = "v0.0.22";
77

88
// --- Configuration ---
99
const XC_FRAMEWORK_URL = `https://github.com/BlixtWallet/react-native-nitro-ark/releases/download/${NITRO_ARK_VERSION}/Ark.xcframework.zip`;

src/lib/paymentsApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const send = async ({
7777
noSync = false,
7878
}: {
7979
destination: string;
80-
amountSat: number;
80+
amountSat: number | null;
8181
comment: string | null;
8282
noSync?: boolean;
8383
}): Promise<string> => {

src/lib/sendUtils.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { decodeBolt11, isArkPublicKey, isValidBitcoinAddress, isValidBolt11 } from "../constants";
2+
3+
export type DestinationTypes = "bitcoin" | "lightning" | "ark" | null;
4+
5+
export type ParsedDestination = {
6+
destinationType: DestinationTypes;
7+
amount?: number;
8+
isAmountEditable: boolean;
9+
error?: string;
10+
};
11+
12+
export const isValidDestination = (dest: string): boolean => {
13+
const cleanedDest = dest.replace(/^(bitcoin:|lightning:)/i, "");
14+
return (
15+
isArkPublicKey(cleanedDest) || isValidBitcoinAddress(cleanedDest) || isValidBolt11(cleanedDest)
16+
);
17+
};
18+
19+
export const parseDestination = (destination: string): ParsedDestination => {
20+
const cleanedDestination = destination.replace(/^(bitcoin:|lightning:)/i, "");
21+
22+
if (isValidBolt11(cleanedDestination)) {
23+
try {
24+
const decoded = decodeBolt11(cleanedDestination);
25+
if (decoded === null) {
26+
throw new Error("Invalid invoice");
27+
}
28+
29+
const msats = decoded.sections.find((n) => n.name === "amount")?.value;
30+
31+
if (msats === undefined) {
32+
return {
33+
destinationType: "lightning",
34+
isAmountEditable: true,
35+
};
36+
}
37+
38+
if (Number(msats) > 0 && Number(msats) < 1000) {
39+
return {
40+
destinationType: "lightning",
41+
isAmountEditable: true,
42+
error: "Invoice amount is less than 1 satoshi.",
43+
};
44+
}
45+
46+
const sats = Number(msats) / 1000;
47+
48+
if (sats >= 1) {
49+
return {
50+
destinationType: "lightning",
51+
amount: sats,
52+
isAmountEditable: false,
53+
};
54+
} else {
55+
return {
56+
destinationType: "lightning",
57+
isAmountEditable: true,
58+
};
59+
}
60+
} catch (e) {
61+
console.error("Failed to decode bolt11 invoice", e);
62+
return {
63+
destinationType: null,
64+
isAmountEditable: true,
65+
error: "Failed to decode bolt11 invoice",
66+
};
67+
}
68+
} else if (isValidBitcoinAddress(cleanedDestination)) {
69+
return {
70+
destinationType: "bitcoin",
71+
isAmountEditable: true,
72+
};
73+
} else if (isArkPublicKey(cleanedDestination)) {
74+
return {
75+
destinationType: "ark",
76+
isAmountEditable: true,
77+
};
78+
}
79+
80+
return {
81+
destinationType: null,
82+
isAmountEditable: true,
83+
};
84+
};

src/screens/SendScreen.tsx

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Text } from "../components/ui/text";
77
import { Input } from "../components/ui/input";
88
import { Button } from "../components/ui/button";
99
import { COLORS } from "../lib/constants";
10-
import { decodeBolt11, isArkPublicKey, isValidBitcoinAddress, isValidBolt11 } from "../constants";
10+
import { parseDestination, isValidDestination, type DestinationTypes } from "../lib/sendUtils";
1111
import { useSend } from "../hooks/usePayments";
1212
import SuccessAnimation from "../components/SuccessAnimation";
1313
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
@@ -32,43 +32,26 @@ const SendScreen = () => {
3232
const [comment, setComment] = useState("");
3333
const [showCamera, setShowCamera] = useState(false);
3434
const [parsedResult, setParsedResult] = useState<SendResult | null>(null);
35+
const [destinationType, setDestinationType] = useState<DestinationTypes | null>(null);
3536

3637
useEffect(() => {
37-
if (isValidBolt11(destination)) {
38-
try {
39-
const decoded = decodeBolt11(destination);
40-
if (decoded === null) {
41-
throw new Error("Invalid invoice");
42-
}
43-
44-
const msats = decoded.sections.find((n) => n.name === "amount")?.value;
45-
46-
if (msats === undefined) {
47-
throw new Error("Missing amount");
48-
}
38+
if (destination) {
39+
const {
40+
destinationType: newDestinationType,
41+
amount: newAmount,
42+
isAmountEditable: newIsAmountEditable,
43+
error: parseError,
44+
} = parseDestination(destination);
4945

50-
if (Number(msats) > 0 && Number(msats) < 1000) {
51-
Alert.alert("Invalid Amount", "Invoice amount is less than 1 satoshi.");
52-
setAmount("");
53-
setIsAmountEditable(true);
54-
return;
55-
}
56-
57-
const sats = Number(msats) / 1000;
58-
59-
if (sats >= 1) {
60-
setAmount(sats.toString());
61-
setIsAmountEditable(false);
62-
} else {
63-
setAmount("");
64-
setIsAmountEditable(true);
65-
}
66-
} catch (e) {
67-
console.error("Failed to decode bolt11 invoice", e);
68-
setAmount("");
69-
setIsAmountEditable(true);
46+
if (parseError) {
47+
Alert.alert("Invalid Destination", parseError);
7048
}
49+
50+
setDestinationType(newDestinationType);
51+
setAmount(newAmount?.toString() ?? "");
52+
setIsAmountEditable(newIsAmountEditable);
7153
} else {
54+
setDestinationType(null);
7255
setAmount("");
7356
setIsAmountEditable(true);
7457
}
@@ -87,17 +70,8 @@ const SendScreen = () => {
8770
}
8871
}, [result]);
8972

90-
const isValidDestination = (dest: string) => {
91-
const cleanedDest = dest.replace(/^(bitcoin:|lightning:)/i, "");
92-
return (
93-
isArkPublicKey(cleanedDest) ||
94-
isValidBitcoinAddress(cleanedDest) ||
95-
isValidBolt11(cleanedDest)
96-
);
97-
};
98-
9973
const handleSend = () => {
100-
const amountSat = parseInt(amount, 10);
74+
let amountSat: number | null = parseInt(amount, 10);
10175
if (!isValidDestination(destination)) {
10276
Alert.alert(
10377
"Invalid Destination",
@@ -109,7 +83,14 @@ const SendScreen = () => {
10983
Alert.alert("Invalid Amount", "Please enter a valid amount.");
11084
return;
11185
}
86+
87+
if (destinationType === "lightning" && amountSat !== 0) {
88+
amountSat = null;
89+
}
90+
11291
const cleanedDestination = destination.replace(/^(bitcoin:|lightning:)/i, "");
92+
93+
console.log("send details", cleanedDestination, amountSat, comment);
11394
send({ destination: cleanedDestination, amountSat, comment: comment || null });
11495
};
11596

0 commit comments

Comments
 (0)