From 607bdb4014b6a480db6a2f9c28ad47f7ad185e1a Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Sat, 26 Aug 2023 22:26:31 +0300 Subject: [PATCH 1/5] Add invoice optional fields --- libs/sdk-bindings/src/breez_sdk.udl | 7 +- libs/sdk-core/src/breez_services.rs | 15 ++++- libs/sdk-core/src/bridge_generated.io.rs | 30 +++++++++ libs/sdk-core/src/bridge_generated.rs | 6 ++ libs/sdk-core/src/greenlight/node_api.rs | 32 +++++---- libs/sdk-core/src/models.rs | 8 ++- libs/sdk-core/src/swap.rs | 3 + libs/sdk-core/src/test_utils.rs | 20 ++---- .../ios/Classes/bridge_generated.h | 9 +++ libs/sdk-flutter/lib/bridge_generated.dart | 66 +++++++++++++++++++ .../main/java/com/breezsdk/BreezSDKMapper.kt | 6 +- libs/sdk-react-native/example/App.js | 20 ++++-- .../sdk-react-native/ios/BreezSDKMapper.swift | 6 +- libs/sdk-react-native/src/index.tsx | 3 + tools/sdk-cli/src/command_handlers.rs | 6 ++ tools/sdk-cli/src/commands.rs | 11 +++- 16 files changed, 207 insertions(+), 41 deletions(-) diff --git a/libs/sdk-bindings/src/breez_sdk.udl b/libs/sdk-bindings/src/breez_sdk.udl index 5dff2995b..ff2ccb349 100644 --- a/libs/sdk-bindings/src/breez_sdk.udl +++ b/libs/sdk-bindings/src/breez_sdk.udl @@ -295,8 +295,11 @@ dictionary ReverseSwapFeesRequest { dictionary ReceivePaymentRequest { u64 amount_sats; string description; - sequence? preimage; - OpeningFeeParams? opening_fee_params; + sequence? preimage = null; + OpeningFeeParams? opening_fee_params = null; + boolean? use_description_hash = null; + u64? expiry = null; + u32? cltv = null; }; dictionary ReceivePaymentResponse { diff --git a/libs/sdk-core/src/breez_services.rs b/libs/sdk-core/src/breez_services.rs index 8d1b65b18..000db3696 100644 --- a/libs/sdk-core/src/breez_services.rs +++ b/libs/sdk-core/src/breez_services.rs @@ -340,6 +340,9 @@ impl BreezServices { description: description.unwrap_or_default(), preimage: None, opening_fee_params: None, + use_description_hash: Some(false), + expiry: None, + cltv: None, }) .await .map_err(|_| anyhow!("Failed to receive payment"))? @@ -1541,11 +1544,14 @@ impl Receiver for PaymentReceiver { destination_invoice_amount_sats, req_data.description, req_data.preimage, + req_data.use_description_hash, + req_data.expiry, + req_data.cltv, ) .await?; - info!("Invoice created {}", invoice.bolt11); + info!("Invoice created {}", invoice); - let mut parsed_invoice = parse_invoice(&invoice.bolt11)?; + let mut parsed_invoice = parse_invoice(invoice)?; // check if the lsp hint already exists info!("Existing routing hints {:?}", parsed_invoice.routing_hints); @@ -1580,7 +1586,7 @@ impl Receiver for PaymentReceiver { if lsp_hint.is_some() || amount_sats != destination_invoice_amount_sats { // create the large amount invoice let raw_invoice_with_hint = - add_lsp_routing_hints(invoice.bolt11.clone(), lsp_hint, amount_sats * 1000)?; + add_lsp_routing_hints(invoice.clone(), lsp_hint, amount_sats * 1000)?; info!("Routing hint added"); let signed_invoice_with_hint = self.node_api.sign_invoice(raw_invoice_with_hint)?; @@ -1836,6 +1842,9 @@ pub(crate) mod tests { description: "should populate lsp hints".to_string(), preimage: None, opening_fee_params: None, + use_description_hash: Some(false), + expiry: None, + cltv: None, }) .await? .ln_invoice; diff --git a/libs/sdk-core/src/bridge_generated.io.rs b/libs/sdk-core/src/bridge_generated.io.rs index b723d2641..ca092c0a4 100644 --- a/libs/sdk-core/src/bridge_generated.io.rs +++ b/libs/sdk-core/src/bridge_generated.io.rs @@ -262,6 +262,11 @@ pub extern "C" fn wire_execute_command(port_: i64, command: *mut wire_uint_8_lis // Section: allocate functions +#[no_mangle] +pub extern "C" fn new_box_autoadd_bool_0(value: bool) -> *mut bool { + support::new_leak_box_ptr(value) +} + #[no_mangle] pub extern "C" fn new_box_autoadd_buy_bitcoin_request_0() -> *mut wire_BuyBitcoinRequest { support::new_leak_box_ptr(wire_BuyBitcoinRequest::new_with_null_ptr()) @@ -339,6 +344,11 @@ pub extern "C" fn new_box_autoadd_sign_message_request_0() -> *mut wire_SignMess support::new_leak_box_ptr(wire_SignMessageRequest::new_with_null_ptr()) } +#[no_mangle] +pub extern "C" fn new_box_autoadd_u32_0(value: u32) -> *mut u32 { + support::new_leak_box_ptr(value) +} + #[no_mangle] pub extern "C" fn new_box_autoadd_u64_0(value: u64) -> *mut u64 { support::new_leak_box_ptr(value) @@ -363,6 +373,12 @@ impl Wire2Api for *mut wire_uint_8_list { String::from_utf8_lossy(&vec).into_owned() } } + +impl Wire2Api for *mut bool { + fn wire2api(self) -> bool { + unsafe { *support::box_from_leak_ptr(self) } + } +} impl Wire2Api for *mut wire_BuyBitcoinRequest { fn wire2api(self) -> BuyBitcoinRequest { let wrap = unsafe { support::box_from_leak_ptr(self) }; @@ -452,6 +468,11 @@ impl Wire2Api for *mut wire_SignMessageRequest { Wire2Api::::wire2api(*wrap).into() } } +impl Wire2Api for *mut u32 { + fn wire2api(self) -> u32 { + unsafe { *support::box_from_leak_ptr(self) } + } +} impl Wire2Api for *mut u64 { fn wire2api(self) -> u64 { unsafe { *support::box_from_leak_ptr(self) } @@ -584,6 +605,9 @@ impl Wire2Api for wire_ReceivePaymentRequest { description: self.description.wire2api(), preimage: self.preimage.wire2api(), opening_fee_params: self.opening_fee_params.wire2api(), + use_description_hash: self.use_description_hash.wire2api(), + expiry: self.expiry.wire2api(), + cltv: self.cltv.wire2api(), } } } @@ -710,6 +734,9 @@ pub struct wire_ReceivePaymentRequest { description: *mut wire_uint_8_list, preimage: *mut wire_uint_8_list, opening_fee_params: *mut wire_OpeningFeeParams, + use_description_hash: *mut bool, + expiry: *mut u64, + cltv: *mut u32, } #[repr(C)] @@ -963,6 +990,9 @@ impl NewWithNullPtr for wire_ReceivePaymentRequest { description: core::ptr::null_mut(), preimage: core::ptr::null_mut(), opening_fee_params: core::ptr::null_mut(), + use_description_hash: core::ptr::null_mut(), + expiry: core::ptr::null_mut(), + cltv: core::ptr::null_mut(), } } } diff --git a/libs/sdk-core/src/bridge_generated.rs b/libs/sdk-core/src/bridge_generated.rs index a24992346..a58704a81 100644 --- a/libs/sdk-core/src/bridge_generated.rs +++ b/libs/sdk-core/src/bridge_generated.rs @@ -691,6 +691,12 @@ where } } +impl Wire2Api for bool { + fn wire2api(self) -> bool { + self + } +} + impl Wire2Api for i32 { fn wire2api(self) -> BuyBitcoinProvider { match self { diff --git a/libs/sdk-core/src/greenlight/node_api.rs b/libs/sdk-core/src/greenlight/node_api.rs index db37ad1f3..1c1b3d49f 100644 --- a/libs/sdk-core/src/greenlight/node_api.rs +++ b/libs/sdk-core/src/greenlight/node_api.rs @@ -16,10 +16,9 @@ use gl_client::pb::cln::{ self, CloseRequest, ListclosedchannelsClosedchannels, ListclosedchannelsRequest, ListpeerchannelsRequest, }; -use gl_client::pb::{ - Amount, Invoice, InvoiceRequest, InvoiceStatus, OffChainPayment, PayStatus, Peer, - WithdrawResponse, -}; +use gl_client::pb::cln::{AmountOrAny, InvoiceRequest}; +use gl_client::pb::{Amount, InvoiceStatus, OffChainPayment, PayStatus, Peer, WithdrawResponse}; + use gl_client::scheduler::Scheduler; use gl_client::signer::Signer; use gl_client::tls::TlsConfig; @@ -243,22 +242,33 @@ impl NodeAPI for Greenlight { amount_sats: u64, description: String, preimage: Option>, - ) -> Result { - let mut client = self.get_client().await?; - + use_description_hash: Option, + expiry: Option, + cltv: Option, + ) -> Result { + let mut client = self.get_node_client().await?; let request = InvoiceRequest { - amount: Some(Amount { - unit: Some(Unit::Satoshi(amount_sats)), + amount_msat: Some(AmountOrAny { + value: Some(gl_client::pb::cln::amount_or_any::Value::Amount( + gl_client::pb::cln::Amount { + msat: amount_sats * 1000, + }, + )), }), label: format!( "breez-{}", SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() ), description, - preimage: preimage.unwrap_or_default(), + preimage, + deschashonly: use_description_hash, + expiry, + fallbacks: vec![], + cltv, }; - Ok(client.create_invoice(request).await?.into_inner()) + let res = client.invoice(request).await?.into_inner(); + Ok(res.bolt11) } // implemenet pull changes from greenlight diff --git a/libs/sdk-core/src/models.rs b/libs/sdk-core/src/models.rs index 3d6026fbf..a7a9be291 100644 --- a/libs/sdk-core/src/models.rs +++ b/libs/sdk-core/src/models.rs @@ -49,7 +49,10 @@ pub trait NodeAPI: Send + Sync { amount_sats: u64, description: String, preimage: Option>, - ) -> Result; + use_description_hash: Option, + expiry: Option, + cltv: Option, + ) -> Result; async fn pull_changed(&self, since_timestamp: i64) -> Result; /// As per the `pb::PayRequest` docs, `amount_sats` is only needed when the invoice doesn't specify an amount async fn send_payment( @@ -667,6 +670,9 @@ pub struct ReceivePaymentRequest { pub description: String, pub preimage: Option>, pub opening_fee_params: Option, + pub use_description_hash: Option, + pub expiry: Option, + pub cltv: Option, } /// Represents a receive payment response. diff --git a/libs/sdk-core/src/swap.rs b/libs/sdk-core/src/swap.rs index ec86af559..f66951ed9 100644 --- a/libs/sdk-core/src/swap.rs +++ b/libs/sdk-core/src/swap.rs @@ -401,6 +401,9 @@ impl BTCReceiveSwap { description: String::from("Bitcoin Transfer"), preimage: Some(swap_info.preimage), opening_fee_params: None, + use_description_hash: Some(false), + expiry: None, + cltv: None, }) .await? .ln_invoice; diff --git a/libs/sdk-core/src/test_utils.rs b/libs/sdk-core/src/test_utils.rs index 26fb0bda8..5eb20b85c 100644 --- a/libs/sdk-core/src/test_utils.rs +++ b/libs/sdk-core/src/test_utils.rs @@ -254,22 +254,12 @@ impl NodeAPI for MockNodeAPI { amount_sats: u64, description: String, preimage: Option>, - ) -> Result { + use_description_hash: Option, + expiry: Option, + cltv: Option, + ) -> Result { let invoice = create_invoice(description.clone(), amount_sats * 1000, vec![], preimage); - Ok(Invoice { - label: "".to_string(), - description, - amount: Some(Amount { - unit: Some(Unit::Satoshi(amount_sats)), - }), - received: None, - status: 0, - payment_time: 0, - expiry_time: invoice.expiry as u32, - bolt11: invoice.bolt11, - payment_hash: hex::decode(invoice.payment_hash).unwrap(), - payment_preimage: vec![], - }) + Ok(invoice.bolt11) } async fn pull_changed(&self, _since_timestamp: i64) -> Result { diff --git a/libs/sdk-flutter/ios/Classes/bridge_generated.h b/libs/sdk-flutter/ios/Classes/bridge_generated.h index af785cedf..a323c0679 100644 --- a/libs/sdk-flutter/ios/Classes/bridge_generated.h +++ b/libs/sdk-flutter/ios/Classes/bridge_generated.h @@ -77,6 +77,9 @@ typedef struct wire_ReceivePaymentRequest { struct wire_uint_8_list *description; struct wire_uint_8_list *preimage; struct wire_OpeningFeeParams *opening_fee_params; + bool *use_description_hash; + uint64_t *expiry; + uint32_t *cltv; } wire_ReceivePaymentRequest; typedef struct wire_LnUrlPayRequestData { @@ -236,6 +239,8 @@ void wire_recommended_fees(int64_t port_); void wire_execute_command(int64_t port_, struct wire_uint_8_list *command); +bool *new_box_autoadd_bool_0(bool value); + struct wire_BuyBitcoinRequest *new_box_autoadd_buy_bitcoin_request_0(void); struct wire_CheckMessageRequest *new_box_autoadd_check_message_request_0(void); @@ -266,6 +271,8 @@ struct wire_ReverseSwapFeesRequest *new_box_autoadd_reverse_swap_fees_request_0( struct wire_SignMessageRequest *new_box_autoadd_sign_message_request_0(void); +uint32_t *new_box_autoadd_u32_0(uint32_t value); + uint64_t *new_box_autoadd_u64_0(uint64_t value); struct wire_uint_8_list *new_uint_8_list_0(int32_t len); @@ -318,6 +325,7 @@ static int64_t dummy_method_to_enforce_bundling(void) { dummy_var ^= ((int64_t) (void*) wire_fetch_reverse_swap_fees); dummy_var ^= ((int64_t) (void*) wire_recommended_fees); dummy_var ^= ((int64_t) (void*) wire_execute_command); + dummy_var ^= ((int64_t) (void*) new_box_autoadd_bool_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_buy_bitcoin_request_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_check_message_request_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_config_0); @@ -333,6 +341,7 @@ static int64_t dummy_method_to_enforce_bundling(void) { dummy_var ^= ((int64_t) (void*) new_box_autoadd_receive_payment_request_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_reverse_swap_fees_request_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_sign_message_request_0); + dummy_var ^= ((int64_t) (void*) new_box_autoadd_u32_0); dummy_var ^= ((int64_t) (void*) new_box_autoadd_u64_0); dummy_var ^= ((int64_t) (void*) new_uint_8_list_0); dummy_var ^= ((int64_t) (void*) inflate_NodeConfig_Greenlight); diff --git a/libs/sdk-flutter/lib/bridge_generated.dart b/libs/sdk-flutter/lib/bridge_generated.dart index 831216c23..eb9fb9c81 100644 --- a/libs/sdk-flutter/lib/bridge_generated.dart +++ b/libs/sdk-flutter/lib/bridge_generated.dart @@ -977,12 +977,18 @@ class ReceivePaymentRequest { final String description; final Uint8List? preimage; final OpeningFeeParams? openingFeeParams; + final bool? useDescriptionHash; + final int? expiry; + final int? cltv; const ReceivePaymentRequest({ required this.amountSats, required this.description, this.preimage, this.openingFeeParams, + this.useDescriptionHash, + this.expiry, + this.cltv, }); } @@ -2887,6 +2893,11 @@ class BreezSdkCoreImpl implements BreezSdkCore { // Section: api2wire +@protected +bool api2wire_bool(bool raw) { + return raw; +} + @protected int api2wire_buy_bitcoin_provider(BuyBitcoinProvider raw) { return api2wire_i32(raw.index); @@ -2944,6 +2955,11 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { return api2wire_uint_8_list(utf8.encoder.convert(raw)); } + @protected + ffi.Pointer api2wire_box_autoadd_bool(bool raw) { + return inner.new_box_autoadd_bool_0(api2wire_bool(raw)); + } + @protected ffi.Pointer api2wire_box_autoadd_buy_bitcoin_request(BuyBitcoinRequest raw) { final ptr = inner.new_box_autoadd_buy_bitcoin_request_0(); @@ -3055,6 +3071,11 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { return ptr; } + @protected + ffi.Pointer api2wire_box_autoadd_u32(int raw) { + return inner.new_box_autoadd_u32_0(api2wire_u32(raw)); + } + @protected ffi.Pointer api2wire_box_autoadd_u64(int raw) { return inner.new_box_autoadd_u64_0(api2wire_u64(raw)); @@ -3070,6 +3091,11 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { return raw == null ? ffi.nullptr : api2wire_String(raw); } + @protected + ffi.Pointer api2wire_opt_box_autoadd_bool(bool? raw) { + return raw == null ? ffi.nullptr : api2wire_box_autoadd_bool(raw); + } + @protected ffi.Pointer api2wire_opt_box_autoadd_greenlight_credentials( GreenlightCredentials? raw) { @@ -3086,6 +3112,11 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { return raw == null ? ffi.nullptr : api2wire_box_autoadd_opening_fee_params(raw); } + @protected + ffi.Pointer api2wire_opt_box_autoadd_u32(int? raw) { + return raw == null ? ffi.nullptr : api2wire_box_autoadd_u32(raw); + } + @protected ffi.Pointer api2wire_opt_box_autoadd_u64(int? raw) { return raw == null ? ffi.nullptr : api2wire_box_autoadd_u64(raw); @@ -3282,6 +3313,9 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { wireObj.description = api2wire_String(apiObj.description); wireObj.preimage = api2wire_opt_uint_8_list(apiObj.preimage); wireObj.opening_fee_params = api2wire_opt_box_autoadd_opening_fee_params(apiObj.openingFeeParams); + wireObj.use_description_hash = api2wire_opt_box_autoadd_bool(apiObj.useDescriptionHash); + wireObj.expiry = api2wire_opt_box_autoadd_u64(apiObj.expiry); + wireObj.cltv = api2wire_opt_box_autoadd_u32(apiObj.cltv); } void _api_fill_to_wire_reverse_swap_fees_request( @@ -4015,6 +4049,19 @@ class BreezSdkCoreWire implements FlutterRustBridgeWireBase { late final _wire_execute_command = _wire_execute_commandPtr.asFunction)>(); + ffi.Pointer new_box_autoadd_bool_0( + bool value, + ) { + return _new_box_autoadd_bool_0( + value, + ); + } + + late final _new_box_autoadd_bool_0Ptr = + _lookup Function(ffi.Bool)>>('new_box_autoadd_bool_0'); + late final _new_box_autoadd_bool_0 = + _new_box_autoadd_bool_0Ptr.asFunction Function(bool)>(); + ffi.Pointer new_box_autoadd_buy_bitcoin_request_0() { return _new_box_autoadd_buy_bitcoin_request_0(); } @@ -4167,6 +4214,19 @@ class BreezSdkCoreWire implements FlutterRustBridgeWireBase { late final _new_box_autoadd_sign_message_request_0 = _new_box_autoadd_sign_message_request_0Ptr .asFunction Function()>(); + ffi.Pointer new_box_autoadd_u32_0( + int value, + ) { + return _new_box_autoadd_u32_0( + value, + ); + } + + late final _new_box_autoadd_u32_0Ptr = + _lookup Function(ffi.Uint32)>>('new_box_autoadd_u32_0'); + late final _new_box_autoadd_u32_0 = + _new_box_autoadd_u32_0Ptr.asFunction Function(int)>(); + ffi.Pointer new_box_autoadd_u64_0( int value, ) { @@ -4313,6 +4373,12 @@ class wire_ReceivePaymentRequest extends ffi.Struct { external ffi.Pointer preimage; external ffi.Pointer opening_fee_params; + + external ffi.Pointer use_description_hash; + + external ffi.Pointer expiry; + + external ffi.Pointer cltv; } class wire_LnUrlPayRequestData extends ffi.Struct { diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index 4bd4ae01c..a7e9a79e6 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -110,8 +110,10 @@ fun asReceivePaymentRequest(reqData: ReadableMap): ReceivePaymentRequest? { if (description != null) { val preimage = reqData.getArray("preimage")?.let { asUByteList(it) } val openingFeeParams = reqData.getMap("openingFeeParams")?.let{ asOpeningFeeParams(it) } - - return ReceivePaymentRequest(amountSats.toULong(), description, preimage, openingFeeParams) + val useDescriptionHash : Boolean? = if (hasNonNullKey(reqData, "useDescriptionHash")) reqData.getBoolean("useDescriptionHash") else null; + val expiry : ULong? = if (hasNonNullKey(reqData, "expiry")) reqData.getInt("expiry").toULong() else null; + val cltv : UInt? = if (hasNonNullKey(reqData, "expiry")) reqData.getInt("cltv").toUInt() else null; + return ReceivePaymentRequest(amountSats.toULong(), description, preimage, openingFeeParams, useDescriptionHash, expiry, cltv) } return null diff --git a/libs/sdk-react-native/example/App.js b/libs/sdk-react-native/example/App.js index 2f4677f66..de32ff2d8 100644 --- a/libs/sdk-react-native/example/App.js +++ b/libs/sdk-react-native/example/App.js @@ -26,7 +26,8 @@ import { backup, backupStatus, signMessage, - checkMessage + checkMessage, + receivePayment, } from "@breeztech/react-native-breez-sdk" import BuildConfig from "react-native-build-config" import { generateMnemonic } from "@dreson4/react-native-quick-bip39" @@ -93,8 +94,8 @@ const App = () => { const nodeState = await nodeInfo() addLine("nodeInfo", JSON.stringify(nodeState)) - const lspInfo = await lspInfo() - addLine("lspInfo", JSON.stringify(lspInfo)) + const lsp = await lspInfo() + addLine("lspInfo", JSON.stringify(lsp)) const fiatCurrencies = await listFiatCurrencies() addLine("listFiatCurrencies", JSON.stringify(fiatCurrencies)) @@ -102,7 +103,7 @@ const App = () => { const fiatRates = await fetchFiatRates() addLine("fetchFiatRates", JSON.stringify(fiatRates)) - const revSwapFees = await fetchReverseSwapFees( { sendAmountSat: null } ) + const revSwapFees = await fetchReverseSwapFees({ sendAmountSat: null }) addLine("revSwapFees", JSON.stringify(revSwapFees)) const inProgressRevSwaps = await inProgressReverseSwaps() @@ -114,7 +115,7 @@ const App = () => { }) addLine("buyBitcoin", JSON.stringify(buyBitcoinResult)) - const signMessageResult = await signMessage({ message: "Hello world"}) + const signMessageResult = await signMessage({ message: "Hello world" }) addLine("signMessage: Hello World", JSON.stringify(signMessageResult)) const verifyMessageResult = await checkMessage({ @@ -124,6 +125,15 @@ const App = () => { }) addLine("verifyMessage:", JSON.stringify(verifyMessageResult)) + const receivePaymentResult = await receivePayment({ + amountSats: 100000, + description: "Hello world", + expiry: 3600, + cltv: 144, + useDescriptionHash: true + }) + addLine("receivePayment", JSON.stringify(receivePaymentResult)) + await backup() addLine("backupStatus", JSON.stringify(await backupStatus())) } catch (e) { diff --git a/libs/sdk-react-native/ios/BreezSDKMapper.swift b/libs/sdk-react-native/ios/BreezSDKMapper.swift index 2d7befd5b..dd654916e 100644 --- a/libs/sdk-react-native/ios/BreezSDKMapper.swift +++ b/libs/sdk-react-native/ios/BreezSDKMapper.swift @@ -224,7 +224,11 @@ class BreezSDKMapper { let preimage = reqData["preimage"] as? [UInt8] let openingFeeParamsMap = reqData["openingFeeParams"] as? [String: Any] let openingFeeParams = (openingFeeParamsMap == nil ? nil : asOpeningFeeParams(reqData: openingFeeParamsMap!)) - return ReceivePaymentRequest(amountSats: amountSats, description: description, preimage: preimage, openingFeeParams: openingFeeParams) + let useDescriptionHash = reqData["useDescriptionHash"] as? Bool; + let expiry = reqData["expiry"] as? UInt64; + let cltv = reqData["cltv"] as? UInt32; + + return ReceivePaymentRequest(amountSats: amountSats, description: description, preimage: preimage, openingFeeParams: openingFeeParams, useDescriptionHash: useDescriptionHash, expiry: expiry, cltv: cltv) } return nil diff --git a/libs/sdk-react-native/src/index.tsx b/libs/sdk-react-native/src/index.tsx index 592172ab3..cee297a53 100644 --- a/libs/sdk-react-native/src/index.tsx +++ b/libs/sdk-react-native/src/index.tsx @@ -112,6 +112,9 @@ export type ReceivePaymentRequest = { description: string preimage?: Uint8Array | number[] openingFeeParams?: OpeningFeeParams + useDescriptionHash?: boolean + expiry?: number + cltv?: number } export type ReceivePaymentResponse = { diff --git a/tools/sdk-cli/src/command_handlers.rs b/tools/sdk-cli/src/command_handlers.rs index 6f27fdf60..23d66f9b3 100644 --- a/tools/sdk-cli/src/command_handlers.rs +++ b/tools/sdk-cli/src/command_handlers.rs @@ -103,6 +103,9 @@ pub(crate) async fn handle_command( Commands::ReceivePayment { amount: amount_sats, description, + use_description_hash, + expiry, + cltv, } => { let recv_payment_response = sdk()? .receive_payment(ReceivePaymentRequest { @@ -110,6 +113,9 @@ pub(crate) async fn handle_command( description, preimage: None, opening_fee_params: None, + use_description_hash, + expiry, + cltv, }) .await?; let mut result = serde_json::to_string(&recv_payment_response)?; diff --git a/tools/sdk-cli/src/commands.rs b/tools/sdk-cli/src/commands.rs index 21d1fba67..0bf85fbaa 100644 --- a/tools/sdk-cli/src/commands.rs +++ b/tools/sdk-cli/src/commands.rs @@ -49,7 +49,16 @@ pub(crate) enum Commands { }, /// Generate a bolt11 invoice - ReceivePayment { amount: u64, description: String }, + ReceivePayment { + amount: u64, + description: String, + #[clap(name = "use_description_hash", short = 's', long = "desc_hash")] + use_description_hash: Option, + #[clap(name = "expiry", short = 'e', long = "expiry")] + expiry: Option, + #[clap(name = "cltv", short = 'c', long = "cltv")] + cltv: Option, + }, /// Pay using lnurl pay LnurlPay { lnurl: String }, From 338549acffb529e842b6d259f813bab1a7a8ba05 Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Sat, 26 Aug 2023 22:29:50 +0300 Subject: [PATCH 2/5] fix clippy --- libs/sdk-core/src/models.rs | 2 +- libs/sdk-core/src/test_utils.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/sdk-core/src/models.rs b/libs/sdk-core/src/models.rs index a7a9be291..b59df653e 100644 --- a/libs/sdk-core/src/models.rs +++ b/libs/sdk-core/src/models.rs @@ -9,7 +9,7 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey}; use bitcoin::{Address, Script}; use chrono::{DateTime, Utc}; -use gl_client::pb::{Invoice, WithdrawResponse}; +use gl_client::pb::WithdrawResponse; use lightning_invoice::RawInvoice; use ripemd::Digest; use ripemd::Ripemd160; diff --git a/libs/sdk-core/src/test_utils.rs b/libs/sdk-core/src/test_utils.rs index 5eb20b85c..639da4c9f 100644 --- a/libs/sdk-core/src/test_utils.rs +++ b/libs/sdk-core/src/test_utils.rs @@ -11,7 +11,7 @@ use bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey}; use bitcoin::Network; use chrono::{SecondsFormat, Utc}; use gl_client::pb::amount::Unit; -use gl_client::pb::{Amount, Invoice, Peer, WithdrawResponse}; +use gl_client::pb::{Amount, Peer, WithdrawResponse}; use lightning::ln::PaymentSecret; use lightning_invoice::{Currency, InvoiceBuilder, RawInvoice}; use rand::distributions::{Alphanumeric, DistString, Standard}; @@ -254,11 +254,11 @@ impl NodeAPI for MockNodeAPI { amount_sats: u64, description: String, preimage: Option>, - use_description_hash: Option, - expiry: Option, - cltv: Option, + _use_description_hash: Option, + _expiry: Option, + _cltv: Option, ) -> Result { - let invoice = create_invoice(description.clone(), amount_sats * 1000, vec![], preimage); + let invoice = create_invoice(description, amount_sats * 1000, vec![], preimage); Ok(invoice.bolt11) } From 92a28cfab7b38c6cfd3c1ace91b4cdff28c87f1e Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Sun, 27 Aug 2023 07:36:18 +0300 Subject: [PATCH 3/5] fix expiry parameter fetching from map --- .../android/src/main/java/com/breezsdk/BreezSDKMapper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index a7e9a79e6..3247ad613 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -112,7 +112,7 @@ fun asReceivePaymentRequest(reqData: ReadableMap): ReceivePaymentRequest? { val openingFeeParams = reqData.getMap("openingFeeParams")?.let{ asOpeningFeeParams(it) } val useDescriptionHash : Boolean? = if (hasNonNullKey(reqData, "useDescriptionHash")) reqData.getBoolean("useDescriptionHash") else null; val expiry : ULong? = if (hasNonNullKey(reqData, "expiry")) reqData.getInt("expiry").toULong() else null; - val cltv : UInt? = if (hasNonNullKey(reqData, "expiry")) reqData.getInt("cltv").toUInt() else null; + val cltv : UInt? = if (hasNonNullKey(reqData, "cltv")) reqData.getInt("cltv").toUInt() else null; return ReceivePaymentRequest(amountSats.toULong(), description, preimage, openingFeeParams, useDescriptionHash, expiry, cltv) } From adddad4e5ceeca704dbc1bcbcafa016fa58e4e71 Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Sun, 27 Aug 2023 10:13:00 +0300 Subject: [PATCH 4/5] properly fetch ULong from ReadableMap --- .../android/src/main/java/com/breezsdk/BreezSDKMapper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index 3247ad613..487ce83f3 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -111,8 +111,8 @@ fun asReceivePaymentRequest(reqData: ReadableMap): ReceivePaymentRequest? { val preimage = reqData.getArray("preimage")?.let { asUByteList(it) } val openingFeeParams = reqData.getMap("openingFeeParams")?.let{ asOpeningFeeParams(it) } val useDescriptionHash : Boolean? = if (hasNonNullKey(reqData, "useDescriptionHash")) reqData.getBoolean("useDescriptionHash") else null; - val expiry : ULong? = if (hasNonNullKey(reqData, "expiry")) reqData.getInt("expiry").toULong() else null; - val cltv : UInt? = if (hasNonNullKey(reqData, "cltv")) reqData.getInt("cltv").toUInt() else null; + val expiry : ULong? = if (hasNonNullKey(reqData, "expiry")) reqData.getDouble("expiry").toULong() else null; + val cltv : UInt? = if (hasNonNullKey(reqData, "cltv")) reqData.getInt("cltv").toUInt() else null; return ReceivePaymentRequest(amountSats.toULong(), description, preimage, openingFeeParams, useDescriptionHash, expiry, cltv) } From dd7864576193dfdd52215b583607ee7fb99be0e5 Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Mon, 28 Aug 2023 11:30:30 +0300 Subject: [PATCH 5/5] Document ReceivePaymentRequest fields --- libs/sdk-core/src/models.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/sdk-core/src/models.rs b/libs/sdk-core/src/models.rs index b59df653e..0c2a0e1fa 100644 --- a/libs/sdk-core/src/models.rs +++ b/libs/sdk-core/src/models.rs @@ -666,12 +666,21 @@ pub struct ReverseSwapFeesRequest { /// Represents a receive payment request. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ReceivePaymentRequest { + /// The amount in satoshis for this payment request pub amount_sats: u64, + /// The description for this payment request. pub description: String, + /// Optional preimage for this payment request. + /// If specified, it will be used instead of generating a new one. pub preimage: Option>, + /// If set and valid, these fess options are used when a new channels is needed. + /// Otherwise the default fee options will be used. pub opening_fee_params: Option, + /// If set to true, then the bolt11 invoice returned includes the description hash. pub use_description_hash: Option, + /// if specified, set the time the invoice is valid for, in seconds. pub expiry: Option, + /// if specified, sets the min_final_cltv_expiry for the invoice pub cltv: Option, }