Skip to content

Commit

Permalink
Merge pull request #525 from breez/validate-send-amount
Browse files Browse the repository at this point in the history
Validate amount parameter
  • Loading branch information
roeierez authored Oct 18, 2023
2 parents 576c1a8 + 35163ee commit fe05ccc
Show file tree
Hide file tree
Showing 17 changed files with 62 additions and 42 deletions.
2 changes: 1 addition & 1 deletion libs/sdk-bindings/src/breez_sdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ interface BlockingBreezServices {
void disconnect();

[Throws=SdkError]
Payment send_payment(string bolt11, u64? amount_sats);
Payment send_payment(string bolt11, u64? amount_msat);

[Throws=SdkError]
Payment send_spontaneous_payment(string node_id, u64 amount_sats);
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-bindings/src/uniffi_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ impl BlockingBreezServices {
rt().block_on(self.breez_services.disconnect())
}

pub fn send_payment(&self, bolt11: String, amount_sats: Option<u64>) -> SdkResult<Payment> {
rt().block_on(self.breez_services.send_payment(bolt11, amount_sats))
pub fn send_payment(&self, bolt11: String, amount_msat: Option<u64>) -> SdkResult<Payment> {
rt().block_on(self.breez_services.send_payment(bolt11, amount_msat))
}

pub fn send_spontaneous_payment(
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-core/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ pub fn payment_by_hash(hash: String) -> Result<Option<Payment>> {
/* Lightning Payment API's */

/// See [BreezServices::send_payment]
pub fn send_payment(bolt11: String, amount_sats: Option<u64>) -> Result<Payment> {
pub fn send_payment(bolt11: String, amount_msat: Option<u64>) -> Result<Payment> {
block_on(async {
get_breez_services()
.await?
.send_payment(bolt11, amount_sats)
.send_payment(bolt11, amount_msat)
.await
})
.map_err(anyhow::Error::new::<SdkError>)
Expand Down
29 changes: 23 additions & 6 deletions libs/sdk-core/src/breez_services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,36 @@ impl BreezServices {
/// Pay a bolt11 invoice
///
/// Calling `send_payment` ensures that the payment is not already completed, if so it will result in an error.
/// If the invoice doesn't specify an amount, the amount is taken from the `amount_sats` arg.
/// If the invoice doesn't specify an amount, the amount is taken from the `amount_msat` arg.
///
/// # Arguments
///
/// * `bolt11` - The bolt11 invoice
/// * `amount_sats` - The amount to pay in satoshis
/// * `amount_msat` - The amount to pay in millisatoshis
pub async fn send_payment(
&self,
bolt11: String,
amount_sats: Option<u64>,
amount_msat: Option<u64>,
) -> SdkResult<Payment> {
self.start_node().await?;
let parsed_invoice = parse_invoice(bolt11.as_str())?;
let invoice_amount_msat = parsed_invoice.amount_msat.unwrap_or_default();
let provided_amount_msat = amount_msat.unwrap_or_default();

// Ensure amount is provided for zero invoice
if provided_amount_msat == 0 && invoice_amount_msat == 0 {
return Err(SdkError::SendPaymentFailed {
err: "amount must be provided when paying a zero invoice".into(),
});
}

// Ensure amount is not provided for invoice that contains amount
if provided_amount_msat > 0 && invoice_amount_msat > 0 {
return Err(SdkError::SendPaymentFailed {
err: "amount should not be provided when paying a non zero invoice".into(),
});
}

match self
.persister
.get_completed_payment_by_hash(&parsed_invoice.payment_hash)?
Expand All @@ -245,7 +262,7 @@ impl BreezServices {
None => {
let payment_res = self
.node_api
.send_payment(bolt11.clone(), amount_sats)
.send_payment(bolt11.clone(), amount_msat)
.await;
self.on_payment_completed(
parsed_invoice.payee_pubkey.clone(),
Expand Down Expand Up @@ -1185,12 +1202,12 @@ impl BreezServices {
.target(env_logger::Target::Pipe(target_log_file))
.parse_filters(
r#"
info,
debug,
breez_sdk_core::input_parser=warn,
breez_sdk_core::backup=info,
breez_sdk_core::persist::reverseswap=info,
breez_sdk_core::reverseswap=info,
gl_client=warn,
gl_client=debug,
h2=warn,
hyper=warn,
lightning_signer=warn,
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-core/src/bridge_generated.io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ pub extern "C" fn wire_payment_by_hash(port_: i64, hash: *mut wire_uint_8_list)
pub extern "C" fn wire_send_payment(
port_: i64,
bolt11: *mut wire_uint_8_list,
amount_sats: *mut u64,
amount_msat: *mut u64,
) {
wire_send_payment_impl(port_, bolt11, amount_sats)
wire_send_payment_impl(port_, bolt11, amount_msat)
}

#[no_mangle]
Expand Down
6 changes: 3 additions & 3 deletions libs/sdk-core/src/bridge_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ fn wire_payment_by_hash_impl(port_: MessagePort, hash: impl Wire2Api<String> + U
fn wire_send_payment_impl(
port_: MessagePort,
bolt11: impl Wire2Api<String> + UnwindSafe,
amount_sats: impl Wire2Api<Option<u64>> + UnwindSafe,
amount_msat: impl Wire2Api<Option<u64>> + UnwindSafe,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
Expand All @@ -407,8 +407,8 @@ fn wire_send_payment_impl(
},
move || {
let api_bolt11 = bolt11.wire2api();
let api_amount_sats = amount_sats.wire2api();
move |task_callback| send_payment(api_bolt11, api_amount_sats)
let api_amount_msat = amount_msat.wire2api();
move |task_callback| send_payment(api_bolt11, api_amount_msat)
},
)
}
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-core/src/greenlight/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ impl NodeAPI for Greenlight {
async fn send_payment(
&self,
bolt11: String,
amount_sats: Option<u64>,
amount_msat: Option<u64>,
) -> Result<PaymentResponse> {
let mut description = None;
if !bolt11.is_empty() {
Expand All @@ -508,7 +508,7 @@ impl NodeAPI for Greenlight {
let mut client: node::ClnClient = self.get_node_client().await?;
let request = pb::cln::PayRequest {
bolt11,
amount_msat: amount_sats.map(|amt| gl_client::pb::cln::Amount { msat: amt * 1000 }),
amount_msat: amount_msat.map(|amt| gl_client::pb::cln::Amount { msat: amt }),
maxfeepercent: Some(self.sdk_config.maxfee_percent),
retry_for: Some(self.sdk_config.payment_timeout_sec),
label: None,
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk-core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub trait NodeAPI: Send + Sync {
async fn send_payment(
&self,
bolt11: String,
amount_sats: Option<u64>,
amount_msat: Option<u64>,
) -> Result<crate::models::PaymentResponse>;
async fn send_spontaneous_payment(
&self,
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk-core/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ impl NodeAPI for MockNodeAPI {
async fn send_payment(
&self,
bolt11: String,
_amount_sats: Option<u64>,
_amount_msat: Option<u64>,
) -> Result<PaymentResponse> {
let payment = self.add_dummy_payment_for(bolt11, None, None).await?;
payment.try_into()
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk-flutter/ios/Classes/bridge_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ void wire_list_payments(int64_t port_, struct wire_ListPaymentsRequest *request)

void wire_payment_by_hash(int64_t port_, struct wire_uint_8_list *hash);

void wire_send_payment(int64_t port_, struct wire_uint_8_list *bolt11, uint64_t *amount_sats);
void wire_send_payment(int64_t port_, struct wire_uint_8_list *bolt11, uint64_t *amount_msat);

void wire_send_spontaneous_payment(int64_t port_,
struct wire_uint_8_list *node_id,
Expand Down
14 changes: 7 additions & 7 deletions libs/sdk-flutter/lib/bridge_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ abstract class BreezSdkCore {
FlutterRustBridgeTaskConstMeta get kPaymentByHashConstMeta;

/// See [BreezServices::send_payment]
Future<Payment> sendPayment({required String bolt11, int? amountSats, dynamic hint});
Future<Payment> sendPayment({required String bolt11, int? amountMsat, dynamic hint});

FlutterRustBridgeTaskConstMeta get kSendPaymentConstMeta;

Expand Down Expand Up @@ -1861,21 +1861,21 @@ class BreezSdkCoreImpl implements BreezSdkCore {
argNames: ["hash"],
);

Future<Payment> sendPayment({required String bolt11, int? amountSats, dynamic hint}) {
Future<Payment> sendPayment({required String bolt11, int? amountMsat, dynamic hint}) {
var arg0 = _platform.api2wire_String(bolt11);
var arg1 = _platform.api2wire_opt_box_autoadd_u64(amountSats);
var arg1 = _platform.api2wire_opt_box_autoadd_u64(amountMsat);
return _platform.executeNormal(FlutterRustBridgeTask(
callFfi: (port_) => _platform.inner.wire_send_payment(port_, arg0, arg1),
parseSuccessData: _wire2api_payment,
constMeta: kSendPaymentConstMeta,
argValues: [bolt11, amountSats],
argValues: [bolt11, amountMsat],
hint: hint,
));
}

FlutterRustBridgeTaskConstMeta get kSendPaymentConstMeta => const FlutterRustBridgeTaskConstMeta(
debugName: "send_payment",
argNames: ["bolt11", "amountSats"],
argNames: ["bolt11", "amountMsat"],
);

Future<Payment> sendSpontaneousPayment({required String nodeId, required int amountSats, dynamic hint}) {
Expand Down Expand Up @@ -4096,12 +4096,12 @@ class BreezSdkCoreWire implements FlutterRustBridgeWireBase {
void wire_send_payment(
int port_,
ffi.Pointer<wire_uint_8_list> bolt11,
ffi.Pointer<ffi.Uint64> amount_sats,
ffi.Pointer<ffi.Uint64> amount_msat,
) {
return _wire_send_payment(
port_,
bolt11,
amount_sats,
amount_msat,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,13 @@ class BreezSDKModule(reactContext: ReactApplicationContext) : ReactContextBaseJa
@ReactMethod
fun sendPayment(
bolt11: String,
amountSats: Double,
amountMsat: Double,
promise: Promise,
) {
executor.execute {
try {
val amountSatsTmp = amountSats.toULong().takeUnless { it == 0UL }
val res = getBreezServices().sendPayment(bolt11, amountSatsTmp)
val amountMsatTmp = amountMsat.toULong().takeUnless { it == 0UL }
val res = getBreezServices().sendPayment(bolt11, amountMsatTmp)
promise.resolve(readableMapOf(res))
} catch (e: SdkException) {
promise.reject(e.javaClass.simpleName, e.message, e)
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk-react-native/ios/RNBreezSDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ @interface RCT_EXTERN_MODULE(RNBreezSDK, RCTEventEmitter)

RCT_EXTERN_METHOD(
sendPayment: (NSString*)bolt11
amountSats: (NSUInteger*)amountSats
amountMsat: (NSUInteger*)amountMsat
resolve: (RCTPromiseResolveBlock)resolve
reject: (RCTPromiseRejectBlock)reject
)
Expand Down
8 changes: 4 additions & 4 deletions libs/sdk-react-native/ios/RNBreezSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ class RNBreezSDK: RCTEventEmitter {
}
}

@objc(sendPayment:amountSats:resolve:reject:)
func sendPayment(_ bolt11: String, amountSats: UInt64, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
@objc(sendPayment:amountMsat:resolve:reject:)
func sendPayment(_ bolt11: String, amountMsat: UInt64, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
do {
let amountSatsTmp = amountSats == 0 ? nil : amountSats
var res = try getBreezServices().sendPayment(bolt11: bolt11, amountSats: amountSatsTmp)
let amountMsatTmp = amountMsat == 0 ? nil : amountMsat
var res = try getBreezServices().sendPayment(bolt11: bolt11, amountMsat: amountMsatTmp)
resolve(BreezSDKMapper.dictionaryOf(payment: res))
} catch let err {
rejectErr(err: err, reject: reject)
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-react-native/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,8 @@ export const disconnect = async (): Promise<void> => {
await BreezSDK.disconnect()
}

export const sendPayment = async (bolt11: string, amountSats: number = 0): Promise<Payment> => {
const response = await BreezSDK.sendPayment(bolt11, amountSats)
export const sendPayment = async (bolt11: string, amountMsat: number = 0): Promise<Payment> => {
const response = await BreezSDK.sendPayment(bolt11, amountMsat)
return response
}

Expand Down
7 changes: 5 additions & 2 deletions tools/sdk-cli/src/command_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,11 @@ pub(crate) async fn handle_command(
}
serde_json::to_string_pretty(&res).map_err(|e| e.into())
}
Commands::SendPayment { bolt11, amount } => {
let payment = sdk()?.send_payment(bolt11, amount).await?;
Commands::SendPayment {
bolt11,
amount_msat,
} => {
let payment = sdk()?.send_payment(bolt11, amount_msat).await?;
serde_json::to_string_pretty(&payment).map_err(|e| e.into())
}
Commands::SendSpontaneousPayment { node_id, amount } => {
Expand Down
4 changes: 2 additions & 2 deletions tools/sdk-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ pub(crate) enum Commands {
SendPayment {
bolt11: String,

#[clap(name = "amount", short = 'a', long = "amt")]
amount: Option<u64>,
#[clap(name = "amount_msat", short = 'a', long = "amt")]
amount_msat: Option<u64>,
},

/// Send a spontaneous (keysend) payment
Expand Down

0 comments on commit fe05ccc

Please sign in to comment.