Skip to content

Commit 78941a7

Browse files
committed
Create invoice
1 parent 6a7e41b commit 78941a7

File tree

7 files changed

+136
-35
lines changed

7 files changed

+136
-35
lines changed

example/App.tsx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,25 @@ const App = () => {
163163
/>
164164

165165
<Button
166-
title={'Show version'}
166+
title={'Create invoice'}
167167
onPress={async () => {
168-
const res = await ldk.version();
169-
if (res.isErr()) {
170-
return setMessage(res.error.message);
171-
}
168+
try {
169+
const res = await ldk.createPaymentRequest({
170+
amountSats: 1234,
171+
description: 'paymeplz',
172+
});
172173

173-
setMessage(res.value.ldk);
174+
if (res.isErr()) {
175+
setMessage(res.error.message);
176+
return;
177+
}
178+
179+
const {to_str} = res.value;
180+
181+
setMessage(to_str);
182+
} catch (e) {
183+
setMessage(e.toString());
184+
}
174185
}}
175186
/>
176187

@@ -187,6 +198,18 @@ const App = () => {
187198
setMessage(`Node ID: ${nodeIdRes.value}`);
188199
}}
189200
/>
201+
202+
<Button
203+
title={'Show version'}
204+
onPress={async () => {
205+
const res = await ldk.version();
206+
if (res.isErr()) {
207+
return setMessage(res.error.message);
208+
}
209+
210+
setMessage(res.value.ldk);
211+
}}
212+
/>
190213
</ScrollView>
191214
</SafeAreaView>
192215
</>

ios/Helpers.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import Foundation
9+
import LDKFramework
910

1011
func handleResolve(_ resolve: RCTPromiseResolveBlock, _ res: LdkCallbackResponses) {
1112
LdkEventEmitter.shared.send(withEvent: .swift_log, body: "Success: \(res.rawValue)")
@@ -23,6 +24,26 @@ func handleReject(_ reject: RCTPromiseRejectBlock, _ ldkError: LdkErrors, _ erro
2324
reject(ldkError.rawValue, message ?? ldkError.rawValue, NSError(domain: ldkError.rawValue, code: ldkError.hashValue))
2425
}
2526

27+
extension Invoice {
28+
var asJson: Any {
29+
return [
30+
"amount_milli_satoshis": self.amount_milli_satoshis().getValue() as Any,
31+
"check_signature": self.check_signature().isOk(),
32+
"is_expired": self.is_expired(),
33+
"duration_since_epoch": self.duration_since_epoch(),
34+
"expiry_time": self.expiry_time(),
35+
"min_final_cltv_expiry": self.min_final_cltv_expiry(),
36+
"payee_pub_key": Data(self.payee_pub_key()).hexEncodedString(),
37+
"recover_payee_pub_key": Data(self.recover_payee_pub_key()).hexEncodedString(),
38+
"payment_hash": Data(self.payment_hash()).hexEncodedString(),
39+
"payment_secret": Data(self.payment_secret()).hexEncodedString(),
40+
"timestamp": self.timestamp(),
41+
"features": Data(self.features().write()).hexEncodedString(),
42+
"currency": self.currency().rawValue,
43+
"to_str": self.to_str()
44+
]
45+
}
46+
}
2647

2748
extension Data {
2849
struct HexEncodingOptions: OptionSet {

ios/Ldk.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ @interface RCT_EXTERN_MODULE(Ldk, NSObject)
6464
RCT_EXTERN_METHOD(pay:(NSString *)paymentRequest
6565
resolve:(RCTPromiseResolveBlock)resolve
6666
reject:(RCTPromiseRejectBlock)reject)
67+
RCT_EXTERN_METHOD(createPaymentRequest:(NSInteger *)amountSats
68+
description:(NSString *)description
69+
resolve:(RCTPromiseResolveBlock)resolve
70+
reject:(RCTPromiseRejectBlock)reject)
6771
@end
6872

6973
//MARK: Events

ios/Ldk.swift

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ enum LdkErrors: String {
4646
case decode_invoice_fail = "decode_invoice_fail"
4747
case init_invoice_payer = "init_invoice_payer"
4848
case invoice_payment_fail = "invoice_payment_fail"
49+
case init_ldk_currency = "init_ldk_currency"
50+
case invoice_create_failed = "invoice_create_failed"
4951
}
5052

5153
enum LdkCallbackResponses: String {
@@ -86,6 +88,8 @@ class Ldk: NSObject {
8688
var peerHandler: TCPPeerHandler?
8789
var channelManagerConstructor: ChannelManagerConstructor?
8890
var invoicePayer: InvoicePayer?
91+
var ldkNetwork: LDKNetwork?
92+
var ldkCurrency: LDKCurrency?
8993

9094
lazy var ldkStorage: URL = {
9195
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
@@ -205,14 +209,16 @@ class Ldk: NSObject {
205209
return handleReject(reject, .init_network_graph)
206210
}
207211

208-
let ldkNetwork: LDKNetwork!
209212
switch network {
210213
case "regtest":
211214
ldkNetwork = LDKNetwork_Regtest
215+
ldkCurrency = LDKCurrency_Regtest
212216
case "testnet":
213217
ldkNetwork = LDKNetwork_Testnet
218+
ldkCurrency = LDKCurrency_BitcoinTestnet
214219
case "mainnet":
215220
ldkNetwork = LDKNetwork_Bitcoin
221+
ldkCurrency = LDKCurrency_Bitcoin
216222
default:
217223
return handleReject(reject, .invalid_network)
218224
}
@@ -221,7 +227,7 @@ class Ldk: NSObject {
221227
if channelMonitors.count == 0 {
222228
//New node
223229
channelManagerConstructor = ChannelManagerConstructor(
224-
network: ldkNetwork,
230+
network: ldkNetwork!,
225231
config: userConfig,
226232
current_blockchain_tip_hash: String(blockHash).hexaBytes,
227233
current_blockchain_tip_height: UInt32(blockHeight),
@@ -331,23 +337,8 @@ class Ldk: NSObject {
331337
let error = parsedInvoice.getError()?.getValueAsParseError()
332338
return handleReject(reject, .decode_invoice_fail, nil, error?.to_str())
333339
}
334-
335-
336-
resolve([
337-
"amount_milli_satoshis": invoice.amount_milli_satoshis().getValue() as Any,
338-
"check_signature": invoice.check_signature().isOk(),
339-
"is_expired": invoice.is_expired(),
340-
"duration_since_epoch": invoice.duration_since_epoch(),
341-
"expiry_time": invoice.expiry_time(),
342-
"min_final_cltv_expiry": invoice.min_final_cltv_expiry(),
343-
"payee_pub_key": Data(invoice.payee_pub_key()).hexEncodedString(),
344-
"recover_payee_pub_key": Data(invoice.recover_payee_pub_key()).hexEncodedString(),
345-
"payment_hash": Data(invoice.payment_hash()).hexEncodedString(),
346-
"payment_secret": Data(invoice.payment_secret()).hexEncodedString(),
347-
"timestamp": invoice.timestamp(),
348-
"features": Data(invoice.features().write()).hexEncodedString(),
349-
"currency": invoice.currency().rawValue
350-
])
340+
341+
resolve(invoice.asJson) //Invoice class extended in Helpers file
351342
}
352343

353344
@objc
@@ -393,7 +384,43 @@ class Ldk: NSObject {
393384
default:
394385
return handleReject(reject, .invoice_payment_fail, nil, res.getError().debugDescription)
395386
}
387+
}
388+
389+
@objc
390+
func createPaymentRequest(_ amountSats: NSInteger, description: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
391+
guard let channelManager = channelManager else {
392+
return handleReject(reject, .init_channel_manager)
393+
}
394+
395+
guard let keysManager = keysManager else {
396+
return handleReject(reject, .init_keys_manager)
397+
}
396398

399+
guard let ldkCurrency = ldkCurrency else {
400+
return handleReject(reject, .init_ldk_currency)
401+
}
402+
403+
let res = Bindings.createInvoiceFromChannelManager(
404+
channelManager: channelManager,
405+
keysManager: keysManager.as_KeysInterface(),
406+
network: ldkCurrency,
407+
amountMsat: UInt64(amountSats),
408+
description: String(description)
409+
)
410+
411+
if res.isOk() {
412+
guard let invoice = res.getValue() else {
413+
return handleReject(reject, .invoice_create_failed)
414+
}
415+
416+
return resolve(invoice.asJson) //Invoice class extended in Helpers file
417+
}
418+
419+
guard let error = res.getError(), let creationError = error.getValueAsCreationError() else {
420+
return handleReject(reject, .invoice_create_failed)
421+
}
422+
423+
return handleReject(reject, .invoice_create_failed, nil, "Invoice creation error: \(creationError.rawValue)")
397424
}
398425

399426
//MARK: Fetch methods
@@ -410,7 +437,7 @@ class Ldk: NSObject {
410437
@objc
411438
func nodeId(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
412439
guard let channelManager = channelManager else {
413-
return handleReject(reject, .load_channel_monitors)
440+
return handleReject(reject, .init_channel_manager)
414441
}
415442

416443
resolve(Data(channelManager.get_our_node_id()).hexEncodedString())

src/ldk.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import {
55
ELdkLogLevels,
66
TAddPeerReq,
77
TChannel,
8-
TDecodedPaymentRequest,
8+
TInvoice,
99
TFeeUpdateReq,
1010
TInitChannelManagerReq,
1111
TInitConfig,
1212
TLogListener,
1313
TPaymentReq,
14-
TSyncTipReq
14+
TSyncTipReq,
15+
TCreatePaymentReq
1516
} from './utils/types';
1617

1718
const LINKING_ERROR =
@@ -217,7 +218,7 @@ class LDK {
217218
* @param paymentRequest
218219
* @returns {Promise<Ok<any> | Err<unknown>>}
219220
*/
220-
async decode({ paymentRequest }: TPaymentReq): Promise<Result<TDecodedPaymentRequest>> {
221+
async decode({ paymentRequest }: TPaymentReq): Promise<Result<TInvoice>> {
221222
try {
222223
const res = await NativeLDK.decode(paymentRequest);
223224
return ok(res);
@@ -226,6 +227,25 @@ class LDK {
226227
}
227228
}
228229

230+
/**
231+
* Creates bolt11 payment request
232+
* @param amountSats
233+
* @param description
234+
* @returns {Promise<Ok<Ok<TInvoice> | Err<TInvoice>> | Err<unknown>>}
235+
*/
236+
async createPaymentRequest({
237+
amountSats,
238+
description
239+
}: TCreatePaymentReq): Promise<Result<TInvoice>> {
240+
try {
241+
const res = await NativeLDK.createPaymentRequest(amountSats, description);
242+
return ok(res);
243+
} catch (e) {
244+
return err(e);
245+
}
246+
}
247+
//createPaymentRequest
248+
229249
/**
230250
* Pays a bolt11 payment request
231251
* @param paymentRequest

src/lightning-manager.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class LightningManager {
205205
if (!isExistingNode) {
206206
// https://github.com/lightningdevkit/ldk-sample/blob/c0a722430b8fbcb30310d64487a32aae839da3e8/src/main.rs#L479
207207
// Sample app only syncs when restarting an existing node
208-
await this.syncToChain();
208+
await this.syncLdk();
209209
}
210210

211211
// Step 10: Give ChannelMonitors to ChainMonitor
@@ -227,15 +227,15 @@ class LightningManager {
227227
* @returns {Promise<void>}
228228
*/
229229
keepBlockchainInSync() {
230-
setInterval(this.syncToChain, 2500);
230+
setInterval(this.syncLdk, 2500);
231231
}
232232

233233
/**
234234
* Fetches current best block and sends to LDK.
235235
* Updates both channelManager and chainMonitor.
236236
* @returns {Promise<Err<string> | Ok<string>>}
237237
*/
238-
async syncToChain() {
238+
async syncLdk() {
239239
const { bestblockhash, blocks } = await regtestBestBlock();
240240

241241
if (this.currentBlockHash === bestblockhash) {
@@ -253,18 +253,18 @@ class LightningManager {
253253

254254
this.currentBlockHash = bestblockhash;
255255

256+
//TODO fetch latest data for watchTxs and watchOutputs. Feed to transactions_confirmed() and transactions_confirmed()
257+
256258
return ok(`Synced to block ${blocks}`);
257259
}
258260

259261
//LDK events
260262

261263
private onRegisterTx(res: TRegisterTxEvent) {
262-
//lightning-manager needs to keep check these and updating LDK using transactions_confirmed()
263264
this.watchTxs.push(res);
264265
}
265266

266267
private onRegisterOutput(res: TRegisterOutputEvent) {
267-
//lightning-manager needs to keep check these and updating LDK using transactions_confirmed()
268268
this.watchOutputs.push(res);
269269
}
270270

src/utils/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export type TChannel = {
121121
unspendable_punishment_reserve?: number;
122122
};
123123

124-
export type TDecodedPaymentRequest = {
124+
export type TInvoice = {
125125
amount_milli_satoshis?: number;
126126
check_signature: boolean;
127127
is_expired: boolean;
@@ -135,6 +135,7 @@ export type TDecodedPaymentRequest = {
135135
timestamp: number;
136136
features: string;
137137
currency: number;
138+
to_str: string; //Actual bolt11 invoice string
138139
};
139140

140141
export type TLogListener = {
@@ -163,6 +164,11 @@ export type TPaymentReq = {
163164
paymentRequest: string;
164165
};
165166

167+
export type TCreatePaymentReq = {
168+
amountSats: number;
169+
description: string;
170+
};
171+
166172
export type TInitChannelManagerReq = {
167173
network: ENetworks;
168174
serializedChannelManager: string;

0 commit comments

Comments
 (0)