diff --git a/cli/Cargo.lock b/cli/Cargo.lock index e12051610..e44414c5a 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -3046,7 +3046,7 @@ dependencies = [ [[package]] name = "sdk-common" version = "0.6.2" -source = "git+https://github.com/breez/breez-sdk?rev=e537feb8ed134bc3c7af5196e10a0a189dd36ac7#e537feb8ed134bc3c7af5196e10a0a189dd36ac7" +source = "git+https://github.com/breez/breez-sdk?rev=2208dd5530908d5cf7b607f34f80155669ab299b#2208dd5530908d5cf7b607f34f80155669ab299b" dependencies = [ "aes 0.8.4", "anyhow", diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 2029f6971..c8494ffc5 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -3294,7 +3294,7 @@ dependencies = [ [[package]] name = "sdk-common" version = "0.6.2" -source = "git+https://github.com/breez/breez-sdk?rev=e537feb8ed134bc3c7af5196e10a0a189dd36ac7#e537feb8ed134bc3c7af5196e10a0a189dd36ac7" +source = "git+https://github.com/breez/breez-sdk?rev=2208dd5530908d5cf7b607f34f80155669ab299b#2208dd5530908d5cf7b607f34f80155669ab299b" dependencies = [ "aes 0.8.4", "anyhow", diff --git a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h index effb4b2ea..75b054346 100644 --- a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h +++ b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h @@ -512,6 +512,7 @@ typedef struct wire_cst_config { uint64_t *zero_conf_max_amount_sat; struct wire_cst_list_prim_u_8_strict *breez_api_key; struct wire_cst_list_external_input_parser *external_input_parsers; + bool use_default_external_input_parsers; } wire_cst_config; typedef struct wire_cst_connect_request { diff --git a/lib/bindings/src/breez_sdk_liquid.udl b/lib/bindings/src/breez_sdk_liquid.udl index a06e7ee65..149df52d6 100644 --- a/lib/bindings/src/breez_sdk_liquid.udl +++ b/lib/bindings/src/breez_sdk_liquid.udl @@ -335,6 +335,7 @@ dictionary Config { string? breez_api_key; string? cache_dir; u64? zero_conf_max_amount_sat; + boolean use_default_external_input_parsers = true; sequence? external_input_parsers = null; }; diff --git a/lib/core/Cargo.toml b/lib/core/Cargo.toml index 9c1e1c132..63af0eaa4 100644 --- a/lib/core/Cargo.toml +++ b/lib/core/Cargo.toml @@ -32,7 +32,7 @@ lwk_wollet = { git = "https://github.com/dangeross/lwk", branch = "savage-full-s #lwk_wollet = "0.7.0" rusqlite = { version = "0.31", features = ["backup", "bundled"] } rusqlite_migration = "1.0" -sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "e537feb8ed134bc3c7af5196e10a0a189dd36ac7", features = ["liquid"] } +sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "2208dd5530908d5cf7b607f34f80155669ab299b", features = ["liquid"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.116" strum = "0.25" diff --git a/lib/core/src/frb_generated.rs b/lib/core/src/frb_generated.rs index 57c42a734..0c34a9f73 100644 --- a/lib/core/src/frb_generated.rs +++ b/lib/core/src/frb_generated.rs @@ -2376,6 +2376,7 @@ impl SseDecode for crate::model::Config { let mut var_breezApiKey = >::sse_decode(deserializer); let mut var_externalInputParsers = >>::sse_decode(deserializer); + let mut var_useDefaultExternalInputParsers = ::sse_decode(deserializer); return crate::model::Config { liquid_electrum_url: var_liquidElectrumUrl, bitcoin_electrum_url: var_bitcoinElectrumUrl, @@ -2388,6 +2389,7 @@ impl SseDecode for crate::model::Config { zero_conf_max_amount_sat: var_zeroConfMaxAmountSat, breez_api_key: var_breezApiKey, external_input_parsers: var_externalInputParsers, + use_default_external_input_parsers: var_useDefaultExternalInputParsers, }; } } @@ -4601,6 +4603,9 @@ impl flutter_rust_bridge::IntoDart for crate::model::Config { self.zero_conf_max_amount_sat.into_into_dart().into_dart(), self.breez_api_key.into_into_dart().into_dart(), self.external_input_parsers.into_into_dart().into_dart(), + self.use_default_external_input_parsers + .into_into_dart() + .into_dart(), ] .into_dart() } @@ -6680,6 +6685,7 @@ impl SseEncode for crate::model::Config { self.external_input_parsers, serializer, ); + ::sse_encode(self.use_default_external_input_parsers, serializer); } } @@ -8774,6 +8780,9 @@ mod io { zero_conf_max_amount_sat: self.zero_conf_max_amount_sat.cst_decode(), breez_api_key: self.breez_api_key.cst_decode(), external_input_parsers: self.external_input_parsers.cst_decode(), + use_default_external_input_parsers: self + .use_default_external_input_parsers + .cst_decode(), } } } @@ -10231,6 +10240,7 @@ mod io { zero_conf_max_amount_sat: core::ptr::null_mut(), breez_api_key: core::ptr::null_mut(), external_input_parsers: core::ptr::null_mut(), + use_default_external_input_parsers: Default::default(), } } } @@ -12268,6 +12278,7 @@ mod io { zero_conf_max_amount_sat: *mut u64, breez_api_key: *mut wire_cst_list_prim_u_8_strict, external_input_parsers: *mut wire_cst_list_external_input_parser, + use_default_external_input_parsers: bool, } #[repr(C)] #[derive(Clone, Copy)] diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs index 608ee507a..01266d650 100644 --- a/lib/core/src/model.rs +++ b/lib/core/src/model.rs @@ -57,6 +57,10 @@ pub struct Config { /// is not recognized. See [ExternalInputParser] for more details on how to configure /// external parsing. pub external_input_parsers: Option>, + /// The SDK includes some default external input parsers + /// ([DEFAULT_EXTERNAL_INPUT_PARSERS](crate::sdk::DEFAULT_EXTERNAL_INPUT_PARSERS)). + /// Set this to false in order to prevent their use. + pub use_default_external_input_parsers: bool, } impl Config { @@ -73,6 +77,7 @@ impl Config { zero_conf_max_amount_sat: None, breez_api_key: Some(breez_api_key), external_input_parsers: None, + use_default_external_input_parsers: true, } } @@ -89,6 +94,7 @@ impl Config { zero_conf_max_amount_sat: None, breez_api_key, external_input_parsers: None, + use_default_external_input_parsers: true, } } diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index 17397fa0a..ab6f3f884 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -52,6 +52,14 @@ pub const DEFAULT_DATA_DIR: &str = ".data"; /// Number of blocks to monitor a swap after its timeout block height pub const CHAIN_SWAP_MONITORING_PERIOD_BITCOIN_BLOCKS: u32 = 4320; +/// A list of external input parsers that are used by default. +/// To opt-out, set `use_default_external_input_parsers` in [Config] to false. +pub const DEFAULT_EXTERNAL_INPUT_PARSERS: &[(&str, &str, &str)] = &[( + "picknpay", + "(.*)(za.co.electrum.picknpay)(.*)", + "https://cryptoqr.net/.well-known/lnurlp/", +)]; + pub struct LiquidSdk { pub(crate) config: Config, pub(crate) onchain_wallet: Arc, @@ -72,6 +80,7 @@ pub struct LiquidSdk { pub(crate) receive_swap_handler: ReceiveSwapHandler, pub(crate) chain_swap_handler: Arc, pub(crate) buy_bitcoin_service: Arc, + pub(crate) external_input_parsers: Option>, } impl LiquidSdk { @@ -216,6 +225,8 @@ impl LiquidSdk { let buy_bitcoin_service = Arc::new(BuyBitcoinService::new(config.clone(), breez_server.clone())); + let external_input_parsers = Self::get_all_external_input_parsers(&config); + let sdk = Arc::new(LiquidSdk { config: config.clone(), onchain_wallet, @@ -234,10 +245,34 @@ impl LiquidSdk { receive_swap_handler, chain_swap_handler, buy_bitcoin_service, + external_input_parsers, }); Ok(sdk) } + fn get_all_external_input_parsers(config: &Config) -> Option> { + let external_input_parsers = if config.use_default_external_input_parsers { + let default_parsers = DEFAULT_EXTERNAL_INPUT_PARSERS + .iter() + .map(|(id, regex, url)| ExternalInputParser { + provider_id: id.to_string(), + input_regex: regex.to_string(), + parser_url: url.to_string(), + }) + .collect::>(); + + [ + default_parsers, + config.external_input_parsers.clone().unwrap_or_default(), + ] + .concat() + } else { + config.external_input_parsers.clone().unwrap_or_default() + }; + + (!external_input_parsers.is_empty()).then_some(external_input_parsers) + } + /// Starts an SDK instance. /// /// Internal method. Should only be called once per instance. @@ -2553,8 +2588,8 @@ impl LiquidSdk { SuccessAction::Aes { data } => { let PaymentDetails::Lightning { preimage, .. } = &payment.details else { return Err(LnUrlPayError::Generic { - err: format!("Invalid payment type: expected type `PaymentDetails::Lightning`, got payment details {:?}.", payment.details), - }); + err: format!("Invalid payment type: expected type `PaymentDetails::Lightning`, got payment details {:?}.", payment.details), + }); }; let preimage_str = preimage.clone().ok_or(LnUrlPayError::Generic { @@ -2764,7 +2799,7 @@ impl LiquidSdk { }); } - let external_parsers = &self.config.external_input_parsers; + let external_parsers = &self.external_input_parsers; parse(input, external_parsers.as_deref()) .await .map_err(|e| PaymentError::generic(&e.to_string())) diff --git a/lib/core/src/test_utils/sdk.rs b/lib/core/src/test_utils/sdk.rs index ae34026bb..f4ead6eab 100644 --- a/lib/core/src/test_utils/sdk.rs +++ b/lib/core/src/test_utils/sdk.rs @@ -109,5 +109,6 @@ pub(crate) fn new_liquid_sdk_with_chain_services( receive_swap_handler, chain_swap_handler, buy_bitcoin_service, + external_input_parsers: None, }) } diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart index 9c35c17ce..ad8b5ce89 100644 --- a/packages/dart/lib/src/frb_generated.dart +++ b/packages/dart/lib/src/frb_generated.dart @@ -1693,7 +1693,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { Config dco_decode_config(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 11) throw Exception('unexpected arr length: expect 11 but see ${arr.length}'); + if (arr.length != 12) throw Exception('unexpected arr length: expect 12 but see ${arr.length}'); return Config( liquidElectrumUrl: dco_decode_String(arr[0]), bitcoinElectrumUrl: dco_decode_String(arr[1]), @@ -1706,6 +1706,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { zeroConfMaxAmountSat: dco_decode_opt_box_autoadd_u_64(arr[8]), breezApiKey: dco_decode_opt_String(arr[9]), externalInputParsers: dco_decode_opt_list_external_input_parser(arr[10]), + useDefaultExternalInputParsers: dco_decode_bool(arr[11]), ); } @@ -3615,6 +3616,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { var var_zeroConfMaxAmountSat = sse_decode_opt_box_autoadd_u_64(deserializer); var var_breezApiKey = sse_decode_opt_String(deserializer); var var_externalInputParsers = sse_decode_opt_list_external_input_parser(deserializer); + var var_useDefaultExternalInputParsers = sse_decode_bool(deserializer); return Config( liquidElectrumUrl: var_liquidElectrumUrl, bitcoinElectrumUrl: var_bitcoinElectrumUrl, @@ -3626,7 +3628,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { zeroConfMinFeeRateMsat: var_zeroConfMinFeeRateMsat, zeroConfMaxAmountSat: var_zeroConfMaxAmountSat, breezApiKey: var_breezApiKey, - externalInputParsers: var_externalInputParsers); + externalInputParsers: var_externalInputParsers, + useDefaultExternalInputParsers: var_useDefaultExternalInputParsers); } @protected @@ -5695,6 +5698,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_opt_box_autoadd_u_64(self.zeroConfMaxAmountSat, serializer); sse_encode_opt_String(self.breezApiKey, serializer); sse_encode_opt_list_external_input_parser(self.externalInputParsers, serializer); + sse_encode_bool(self.useDefaultExternalInputParsers, serializer); } @protected diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart index f3fd3ea82..1cf59d54e 100644 --- a/packages/dart/lib/src/frb_generated.io.dart +++ b/packages/dart/lib/src/frb_generated.io.dart @@ -2212,6 +2212,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { wireObj.zero_conf_max_amount_sat = cst_encode_opt_box_autoadd_u_64(apiObj.zeroConfMaxAmountSat); wireObj.breez_api_key = cst_encode_opt_String(apiObj.breezApiKey); wireObj.external_input_parsers = cst_encode_opt_list_external_input_parser(apiObj.externalInputParsers); + wireObj.use_default_external_input_parsers = cst_encode_bool(apiObj.useDefaultExternalInputParsers); } @protected @@ -6070,6 +6071,9 @@ final class wire_cst_config extends ffi.Struct { external ffi.Pointer breez_api_key; external ffi.Pointer external_input_parsers; + + @ffi.Bool() + external bool use_default_external_input_parsers; } final class wire_cst_connect_request extends ffi.Struct { diff --git a/packages/dart/lib/src/model.dart b/packages/dart/lib/src/model.dart index 04e678623..34857b00a 100644 --- a/packages/dart/lib/src/model.dart +++ b/packages/dart/lib/src/model.dart @@ -146,6 +146,11 @@ class Config { /// external parsing. final List? externalInputParsers; + /// The SDK includes some default external input parsers + /// ([DEFAULT_EXTERNAL_INPUT_PARSERS](crate::sdk::DEFAULT_EXTERNAL_INPUT_PARSERS)). + /// Set this to false in order to prevent their use. + final bool useDefaultExternalInputParsers; + const Config({ required this.liquidElectrumUrl, required this.bitcoinElectrumUrl, @@ -158,6 +163,7 @@ class Config { this.zeroConfMaxAmountSat, this.breezApiKey, this.externalInputParsers, + required this.useDefaultExternalInputParsers, }); @override @@ -172,7 +178,8 @@ class Config { zeroConfMinFeeRateMsat.hashCode ^ zeroConfMaxAmountSat.hashCode ^ breezApiKey.hashCode ^ - externalInputParsers.hashCode; + externalInputParsers.hashCode ^ + useDefaultExternalInputParsers.hashCode; @override bool operator ==(Object other) => @@ -189,7 +196,8 @@ class Config { zeroConfMinFeeRateMsat == other.zeroConfMinFeeRateMsat && zeroConfMaxAmountSat == other.zeroConfMaxAmountSat && breezApiKey == other.breezApiKey && - externalInputParsers == other.externalInputParsers; + externalInputParsers == other.externalInputParsers && + useDefaultExternalInputParsers == other.useDefaultExternalInputParsers; } /// An argument when calling [crate::sdk::LiquidSdk::connect]. diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart index 61a89e4f4..8cb82f14c 100644 --- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart +++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart @@ -4570,6 +4570,9 @@ final class wire_cst_config extends ffi.Struct { external ffi.Pointer breez_api_key; external ffi.Pointer external_input_parsers; + + @ffi.Bool() + external bool use_default_external_input_parsers; } final class wire_cst_connect_request extends ffi.Struct { diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt index a0e917e52..cb5f53f34 100644 --- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt @@ -248,6 +248,7 @@ fun asConfig(config: ReadableMap): Config? { "network", "paymentTimeoutSec", "zeroConfMinFeeRateMsat", + "useDefaultExternalInputParsers", ), ) ) { @@ -272,6 +273,7 @@ fun asConfig(config: ReadableMap): Config? { } else { null } + val useDefaultExternalInputParsers = config.getBoolean("useDefaultExternalInputParsers") val externalInputParsers = if (hasNonNullKey(config, "externalInputParsers")) { config.getArray("externalInputParsers")?.let { @@ -291,6 +293,7 @@ fun asConfig(config: ReadableMap): Config? { breezApiKey, cacheDir, zeroConfMaxAmountSat, + useDefaultExternalInputParsers, externalInputParsers, ) } @@ -307,6 +310,7 @@ fun readableMapOf(config: Config): ReadableMap = "breezApiKey" to config.breezApiKey, "cacheDir" to config.cacheDir, "zeroConfMaxAmountSat" to config.zeroConfMaxAmountSat, + "useDefaultExternalInputParsers" to config.useDefaultExternalInputParsers, "externalInputParsers" to config.externalInputParsers?.let { readableArrayOf(it) }, ) diff --git a/packages/react-native/ios/BreezSDKLiquidMapper.swift b/packages/react-native/ios/BreezSDKLiquidMapper.swift index 3c832aeba..e1bdbaaa2 100644 --- a/packages/react-native/ios/BreezSDKLiquidMapper.swift +++ b/packages/react-native/ios/BreezSDKLiquidMapper.swift @@ -328,12 +328,15 @@ enum BreezSDKLiquidMapper { } zeroConfMaxAmountSat = zeroConfMaxAmountSatTmp } + guard let useDefaultExternalInputParsers = config["useDefaultExternalInputParsers"] as? Bool else { + throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "useDefaultExternalInputParsers", typeName: "Config")) + } var externalInputParsers: [ExternalInputParser]? if let externalInputParsersTmp = config["externalInputParsers"] as? [[String: Any?]] { externalInputParsers = try asExternalInputParserList(arr: externalInputParsersTmp) } - return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, breezApiKey: breezApiKey, cacheDir: cacheDir, zeroConfMaxAmountSat: zeroConfMaxAmountSat, externalInputParsers: externalInputParsers) + return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, breezApiKey: breezApiKey, cacheDir: cacheDir, zeroConfMaxAmountSat: zeroConfMaxAmountSat, useDefaultExternalInputParsers: useDefaultExternalInputParsers, externalInputParsers: externalInputParsers) } static func dictionaryOf(config: Config) -> [String: Any?] { @@ -348,6 +351,7 @@ enum BreezSDKLiquidMapper { "breezApiKey": config.breezApiKey == nil ? nil : config.breezApiKey, "cacheDir": config.cacheDir == nil ? nil : config.cacheDir, "zeroConfMaxAmountSat": config.zeroConfMaxAmountSat == nil ? nil : config.zeroConfMaxAmountSat, + "useDefaultExternalInputParsers": config.useDefaultExternalInputParsers, "externalInputParsers": config.externalInputParsers == nil ? nil : arrayOf(externalInputParserList: config.externalInputParsers!), ] } diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 1db41a0fc..a89e816f1 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -68,6 +68,7 @@ export interface Config { breezApiKey?: string cacheDir?: string zeroConfMaxAmountSat?: number + useDefaultExternalInputParsers: boolean externalInputParsers?: ExternalInputParser[] }