feat: require Breez API key globally on mainnet (#520)

This commit is contained in:
yse
2024-10-08 16:17:34 +02:00
committed by GitHub
parent 046e7ab1c8
commit 42f4ca0129
34 changed files with 535 additions and 105 deletions

198
cli/Cargo.lock generated
View File

@@ -194,6 +194,45 @@ dependencies = [
"backtrace",
]
[[package]]
name = "asn1-rs"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.75",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.75",
]
[[package]]
name = "async-stream"
version = "0.3.5"
@@ -569,6 +608,7 @@ dependencies = [
"tokio-stream",
"tokio-tungstenite",
"url",
"x509-parser",
"zbase32",
]
@@ -849,6 +889,29 @@ dependencies = [
"syn 2.0.75",
]
[[package]]
name = "der-parser"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "digest"
version = "0.10.7"
@@ -860,6 +923,17 @@ dependencies = [
"subtle",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.75",
]
[[package]]
name = "either"
version = "1.13.0"
@@ -1892,6 +1966,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniscript"
version = "11.2.0"
@@ -1976,6 +2056,41 @@ dependencies = [
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -2004,6 +2119,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "oid-registry"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9"
dependencies = [
"asn1-rs",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -2178,6 +2302,12 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@@ -2577,6 +2707,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]]
name = "rustix"
version = "0.38.34"
@@ -3115,6 +3254,17 @@ dependencies = [
"futures-core",
]
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.75",
]
[[package]]
name = "system-configuration"
version = "0.6.0"
@@ -3204,6 +3354,37 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.8.0"
@@ -3977,6 +4158,23 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "x509-parser"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
dependencies = [
"asn1-rs",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "zbase32"
version = "0.1.2"

View File

@@ -71,10 +71,10 @@ async fn main() -> Result<()> {
let mnemonic = persistence.get_or_create_mnemonic()?;
let network = args.network.unwrap_or(LiquidNetwork::Testnet);
let mut config = LiquidSdk::default_config(network);
let breez_api_key = std::env::var_os("BREEZ_API_KEY")
.map(|var| var.into_string().expect("Expected valid API key string"));
let mut config = LiquidSdk::default_config(network, breez_api_key)?;
config.working_dir = data_dir_str;
config.breez_api_key = std::env::var_os("BREEZ_API_KEY")
.map(|var| var.into_string().expect("Invalid API key provided"));
let sdk = LiquidSdk::connect(ConnectRequest {
mnemonic: mnemonic.to_string(),
config,

182
lib/Cargo.lock generated
View File

@@ -268,6 +268,45 @@ dependencies = [
"toml",
]
[[package]]
name = "asn1-rs"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
]
[[package]]
name = "async-stream"
version = "0.3.5"
@@ -671,6 +710,7 @@ dependencies = [
"tokio-tungstenite",
"url",
"uuid",
"x509-parser",
"zbase32",
]
@@ -1030,6 +1070,29 @@ dependencies = [
"syn 2.0.77",
]
[[package]]
name = "der-parser"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "digest"
version = "0.10.7"
@@ -1041,6 +1104,17 @@ dependencies = [
"subtle",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
]
[[package]]
name = "either"
version = "1.13.0"
@@ -2176,6 +2250,31 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -2204,6 +2303,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "oid-registry"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9"
dependencies = [
"asn1-rs",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -2425,6 +2533,12 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@@ -2887,6 +3001,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]]
name = "rustix"
version = "0.38.36"
@@ -3441,6 +3564,17 @@ dependencies = [
"futures-core",
]
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
@@ -3546,6 +3680,37 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.8.0"
@@ -4614,6 +4779,23 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "x509-parser"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
dependencies = [
"asn1-rs",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "zbase32"
version = "0.1.2"

View File

@@ -37,7 +37,6 @@ once_cell = "1.19"
thiserror = "1.0"
# Version must match that used by uniffi-bindgen-go
uniffi = "0.25.0"
uniffi_macros = "0.25.0"
[patch.crates-io]
# https://github.com/BlockstreamResearch/rust-secp256k1-zkp/pull/48/commits

View File

@@ -1022,7 +1022,8 @@ void frbgen_breez_liquid_wire__crate__bindings__breez_log_stream(int64_t port_,
void frbgen_breez_liquid_wire__crate__bindings__connect(int64_t port_,
struct wire_cst_connect_request *req);
WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__default_config(int32_t network);
WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__default_config(int32_t network,
struct wire_cst_list_prim_u_8_strict *breez_api_key);
void frbgen_breez_liquid_wire__crate__bindings__parse(int64_t port_,
struct wire_cst_list_prim_u_8_strict *input);

View File

@@ -305,8 +305,8 @@ dictionary Config {
LiquidNetwork network;
u64 payment_timeout_sec;
u32 zero_conf_min_fee_rate_msat;
u64? zero_conf_max_amount_sat;
string? breez_api_key;
u64? zero_conf_max_amount_sat;
};
enum LiquidNetwork {
@@ -569,7 +569,8 @@ namespace breez_sdk_liquid {
[Throws=SdkError]
void set_logger(Logger logger);
Config default_config(LiquidNetwork network);
[Throws=SdkError]
Config default_config(LiquidNetwork network, string? breez_api_key);
[Throws=PaymentError]
InputType parse(string input);

View File

@@ -54,8 +54,11 @@ pub fn connect(req: ConnectRequest) -> Result<Arc<BindingLiquidSdk>, SdkError> {
})
}
pub fn default_config(network: LiquidNetwork) -> Config {
LiquidSdk::default_config(network)
pub fn default_config(
network: LiquidNetwork,
breez_api_key: Option<String>,
) -> Result<Config, SdkError> {
LiquidSdk::default_config(network, breez_api_key)
}
pub fn parse(input: String) -> Result<InputType, PaymentError> {

View File

@@ -4,8 +4,7 @@ using Breez.Sdk.Liquid;
try
{
var mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
var config = BreezSdkLiquidMethods.DefaultConfig(LiquidNetwork.Testnet);
var config = BreezSdkLiquidMethods.DefaultConfig(LiquidNetwork.Testnet, null);
var connectReq = new ConnectRequest(config, mnemonic);
BindingLiquidSdk sdk = BreezSdkLiquidMethods.Connect(connectReq);

View File

@@ -8,8 +8,11 @@ import (
func main() {
mnemonic := "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
config, err := breez_sdk_liquid.DefaultConfig(breez_sdk_liquid.LiquidNetworkTestnet, nil)
config := breez_sdk_liquid.DefaultConfig(breez_sdk_liquid.LiquidNetworkTestnet)
if err != nil {
log.Fatalf("Config creation failed: %#v", err)
}
sdk, err := breez_sdk_liquid.Connect(breez_sdk_liquid.ConnectRequest{
Config: config,

View File

@@ -4,8 +4,7 @@ using breez_sdk_liquid.breez_sdk_liquid;
try
{
var mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
var config = BreezSdkLiquidMethods.DefaultConfig(LiquidNetwork.Testnet);
var config = BreezSdkLiquidMethods.DefaultConfig(LiquidNetwork.Testnet, null);
var connectReq = new ConnectRequest(config, mnemonic);
BindingLiquidSdk sdk = BreezSdkLiquidMethods.Connect(connectReq);

View File

@@ -7,7 +7,7 @@ class SDKListener: breez_sdk_liquid.EventListener {
try {
var mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
var config = breez_sdk_liquid.defaultConfig(breez_sdk_liquid.LiquidNetwork.TESTNET)
var config = breez_sdk_liquid.defaultConfig(breez_sdk_liquid.LiquidNetwork.TESTNET, null)
var connectRequest = breez_sdk_liquid.ConnectRequest(config, mnemonic)
var sdk = breez_sdk_liquid.connect(connectRequest)
@@ -21,4 +21,4 @@ try {
assert(nodeInfo.pubkey.equals("03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494"))
} catch (ex: Exception) {
throw RuntimeException(ex.toString())
}
}

View File

@@ -8,7 +8,7 @@ class SDKListener(breez_sdk_liquid.EventListener):
def test():
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
config = breez_sdk_liquid.default_config(breez_sdk_liquid.LiquidNetwork.TESTNET)
config = breez_sdk_liquid.default_config(breez_sdk_liquid.LiquidNetwork.TESTNET, None)
connect_request = breez_sdk_liquid.ConnectRequest(config=config, mnemonic=mnemonic)
sdk = breez_sdk_liquid.connect(connect_request)
@@ -21,4 +21,4 @@ def test():
print(node_info)
assert node_info.pubkey == "03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494"
test()
test()

View File

@@ -7,7 +7,7 @@ class SDKListener: EventListener {
}
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
let config = breez_sdk_liquid.defaultConfig(network: .testnet);
let config = try breez_sdk_liquid.defaultConfig(network: .testnet, breezApiKey: nil);
let connectRequest = breez_sdk_liquid.ConnectRequest(config: config, mnemonic: mnemonic);
let sdk = try breez_sdk_liquid.connect(req: connectRequest);
@@ -18,4 +18,4 @@ let nodeInfo = try sdk.getInfo();
try sdk.removeEventListener(id: listenerId);
print(nodeInfo);
assert(nodeInfo.pubkey == "03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494", "nodeInfo.pubkey");
assert(nodeInfo.pubkey == "03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494", "nodeInfo.pubkey");

View File

@@ -49,6 +49,7 @@ hex = "0.4"
reqwest = { version = "=0.11.20", features = ["json"] }
electrum-client = { version = "0.19.0" }
zbase32 = "0.1.2"
x509-parser = { version = "0.16.0" }
[dev-dependencies]
lazy_static = "1.5.0"

View File

@@ -59,8 +59,11 @@ pub fn breez_log_stream(s: StreamSink<LogEntry>) -> Result<()> {
}
#[frb(sync)]
pub fn default_config(network: LiquidNetwork) -> Config {
LiquidSdk::default_config(network)
pub fn default_config(
network: LiquidNetwork,
breez_api_key: Option<String>,
) -> Result<Config, SdkError> {
LiquidSdk::default_config(network, breez_api_key)
}
pub async fn parse(input: String) -> Result<InputType, PaymentError> {

View File

@@ -108,19 +108,17 @@ impl LiquidChainService for HybridLiquidChainService {
LiquidNetwork::Mainnet => {
let tx_bytes = tx.serialize();
info!("Broadcasting Liquid tx: {}", tx_bytes.to_hex());
let authorization = self
.api_key
.clone()
.map(|key| format!("Bearer {key}"))
.unwrap_or_default();
let client = reqwest::Client::new();
let response = client
let mut req = client
.post(format!("{LIQUID_ESPLORA_URL}/tx"))
.header("Swap-ID", swap_id.unwrap_or_default())
.header("Authorization", authorization)
.body(tx_bytes.to_hex())
.send()
.await?;
.body(tx_bytes.to_hex());
if let Some(api_key) = &self.api_key {
req = req.header("Authorization", format!("Bearer {}", api_key));
};
let response = req.send().await?;
let txid = Txid::from_str(&response.text().await?)?;
Ok(txid)
}

View File

@@ -1582,6 +1582,7 @@ fn wire__crate__bindings__connect_impl(
}
fn wire__crate__bindings__default_config_impl(
network: impl CstDecode<crate::model::LiquidNetwork>,
breez_api_key: impl CstDecode<Option<String>>,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::DcoCodec, _>(
flutter_rust_bridge::for_generated::TaskInfo {
@@ -1591,8 +1592,9 @@ fn wire__crate__bindings__default_config_impl(
},
move || {
let api_network = network.cst_decode();
transform_result_dco::<_, _, ()>((move || {
let output_ok = Result::<_, ()>::Ok(crate::bindings::default_config(api_network))?;
let api_breez_api_key = breez_api_key.cst_decode();
transform_result_dco::<_, _, crate::error::SdkError>((move || {
let output_ok = crate::bindings::default_config(api_network, api_breez_api_key)?;
Ok(output_ok)
})())
},
@@ -10134,8 +10136,9 @@ mod io {
#[no_mangle]
pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__default_config(
network: i32,
breez_api_key: *mut wire_cst_list_prim_u_8_strict,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
wire__crate__bindings__default_config_impl(network)
wire__crate__bindings__default_config_impl(network, breez_api_key)
}
#[no_mangle]

View File

@@ -54,7 +54,7 @@ pub struct Config {
}
impl Config {
pub fn mainnet() -> Self {
pub fn mainnet(breez_api_key: String) -> Self {
Config {
liquid_electrum_url: "elements-mainnet.blockstream.info:50002".to_string(),
bitcoin_electrum_url: "bitcoin-mainnet.blockstream.info:50002".to_string(),
@@ -64,11 +64,11 @@ impl Config {
payment_timeout_sec: 15,
zero_conf_min_fee_rate_msat: DEFAULT_ZERO_CONF_MIN_FEE_RATE_MAINNET,
zero_conf_max_amount_sat: None,
breez_api_key: None,
breez_api_key: Some(breez_api_key),
}
}
pub fn testnet() -> Self {
pub fn testnet(breez_api_key: Option<String>) -> Self {
Config {
liquid_electrum_url: "elements-testnet.blockstream.info:50002".to_string(),
bitcoin_electrum_url: "bitcoin-testnet.blockstream.info:50002".to_string(),
@@ -78,7 +78,7 @@ impl Config {
payment_timeout_sec: 15,
zero_conf_min_fee_rate_msat: DEFAULT_ZERO_CONF_MIN_FEE_RATE_TESTNET,
zero_conf_max_amount_sat: None,
breez_api_key: None,
breez_api_key,
}
}

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::time::Instant;
use std::{fs, path::PathBuf, str::FromStr, sync::Arc, time::Duration};
use anyhow::Result;
use anyhow::{anyhow, Result};
use boltz_client::{swaps::boltz::*, util::secrets::Preimage};
use buy::{BuyBitcoinApi, BuyBitcoinService};
use chain::bitcoin::HybridBitcoinChainService;
@@ -12,6 +12,7 @@ use futures_util::stream::select_all;
use futures_util::StreamExt;
use futures_util::TryFutureExt;
use log::{debug, error, info, warn};
use lwk_wollet::bitcoin::base64::Engine as _;
use lwk_wollet::elements::{AssetId, Txid};
use lwk_wollet::hashes::{sha256, Hash};
use lwk_wollet::secp256k1::ThirtyTwoByteHash;
@@ -25,6 +26,7 @@ use tokio::sync::{watch, Mutex, RwLock};
use tokio::time::MissedTickBehavior;
use tokio_stream::wrappers::BroadcastStream;
use url::Url;
use x509_parser::parse_x509_certificate;
use crate::chain::bitcoin::BitcoinChainService;
use crate::chain_swap::ChainSwapHandler;
@@ -95,11 +97,44 @@ impl LiquidSdk {
Ok(sdk)
}
fn validate_api_key(api_key: &str) -> Result<()> {
let api_key_decoded = lwk_wollet::bitcoin::base64::engine::general_purpose::STANDARD
.decode(api_key.as_bytes())
.map_err(|err| anyhow!("Could not base64 decode the Breez API key: {err:?}"))?;
let (_rem, cert) = parse_x509_certificate(&api_key_decoded)
.map_err(|err| anyhow!("Invaid certificate for Breez API key: {err:?}"))?;
let issuer = cert
.issuer()
.iter_common_name()
.next()
.and_then(|cn| cn.as_str().ok());
match issuer {
Some(common_name) => ensure_sdk!(
common_name.starts_with("Breez"),
anyhow!("Invalid certificate found for Breez API key: issuer mismatch. Please confirm that the certificate's origin is trusted")
),
_ => {
return Err(anyhow!("Could not parse Breez API key certificate: issuer is invalid or not found."))
}
}
Ok(())
}
fn new(
config: Config,
swapper_proxy_url: Option<String>,
mnemonic: String,
) -> Result<Arc<Self>> {
match (config.network, &config.breez_api_key) {
(_, Some(api_key)) => Self::validate_api_key(api_key)?,
(LiquidNetwork::Mainnet, None) => {
return Err(anyhow!("Breez API key must be provided on mainnet."));
}
(LiquidNetwork::Testnet, None) => {}
};
fs::create_dir_all(&config.working_dir)?;
let onchain_wallet = Arc::new(LiquidOnchainWallet::new(mnemonic, config.clone())?);
@@ -683,12 +718,6 @@ impl LiquidSdk {
InputType::LiquidAddress {
address: mut liquid_address_data,
} => {
if self.config.breez_api_key.is_none() {
return Err(PaymentError::Generic {
err: "Cannot execute direct payments without `breez_api_key` specified in the SDK configuration. To receive one, please fill out the form at https://breez.technology/request-api-key/#contact-us-form-sdk".to_string()
});
}
let amount_sat = match (liquid_address_data.amount_sat, req.amount_sat) {
(None, None) => {
return Err(PaymentError::AmountMissing { err: "`amount_sat` must be present when paying to a `SendDestination::LiquidAddress`".to_string() });
@@ -737,12 +766,6 @@ impl LiquidSdk {
fees_sat = match self.swapper.check_for_mrh(&invoice.bolt11)? {
Some((lbtc_address, _)) => {
if self.config.breez_api_key.is_none() {
return Err(PaymentError::Generic {
err: "Cannot execute direct payments without `breez_api_key` specified in the SDK configuration. To receive one, please fill out the form at https://breez.technology/request-api-key/#contact-us-form-sdk".to_string()
});
}
self.estimate_onchain_tx_fee(receiver_amount_sat, &lbtc_address)
.await?
}
@@ -888,12 +911,6 @@ impl LiquidSdk {
receiver_amount_sat: u64,
fees_sat: u64,
) -> Result<SendPaymentResponse, PaymentError> {
if self.config.breez_api_key.is_none() {
return Err(PaymentError::Generic {
err: "Cannot execute direct payments without `breez_api_key` specified in the SDK configuration. To receive one, please fill out the form at https://breez.technology/request-api-key/#contact-us-form-sdk".to_string()
});
}
let tx = self
.onchain_wallet
.build_tx(
@@ -2288,11 +2305,22 @@ impl LiquidSdk {
}
/// Get the full default [Config] for specific [LiquidNetwork].
pub fn default_config(network: LiquidNetwork) -> Config {
match network {
LiquidNetwork::Mainnet => Config::mainnet(),
LiquidNetwork::Testnet => Config::testnet(),
}
pub fn default_config(
network: LiquidNetwork,
breez_api_key: Option<String>,
) -> Result<Config, SdkError> {
let config = match network {
LiquidNetwork::Mainnet => {
let Some(breez_api_key) = breez_api_key else {
return Err(SdkError::Generic {
err: "Breez API key must be provided on mainnet.".to_string(),
});
};
Config::mainnet(breez_api_key)
}
LiquidNetwork::Testnet => Config::testnet(breez_api_key),
};
Ok(config)
}
/// Parses a string into an [InputType]. See [input_parser::parse].

View File

@@ -27,7 +27,7 @@ lazy_static! {
}
pub(crate) fn new_chain_swap_handler(persister: Arc<Persister>) -> Result<ChainSwapHandler> {
let config = Config::testnet();
let config = Config::testnet(None);
let onchain_wallet = Arc::new(MockWallet::new());
let swapper = Arc::new(BoltzSwapper::new(config.clone(), None));
let liquid_chain_service = Arc::new(Mutex::new(MockLiquidChainService::new()));

View File

@@ -10,7 +10,7 @@ use crate::{model::Config, persist::Persister, receive_swap::ReceiveSwapHandler}
use super::{chain::MockLiquidChainService, swapper::MockSwapper, wallet::MockWallet};
pub(crate) fn new_receive_swap_handler(persister: Arc<Persister>) -> Result<ReceiveSwapHandler> {
let config = Config::testnet();
let config = Config::testnet(None);
let onchain_wallet = Arc::new(MockWallet::new());
let swapper = Arc::new(MockSwapper::new());
let liquid_chain_service = Arc::new(Mutex::new(MockLiquidChainService::new()));

View File

@@ -43,7 +43,7 @@ pub(crate) fn new_liquid_sdk_with_chain_services(
liquid_chain_service: Arc<Mutex<MockLiquidChainService>>,
bitcoin_chain_service: Arc<Mutex<MockBitcoinChainService>>,
) -> Result<LiquidSdk> {
let mut config = Config::testnet();
let mut config = Config::testnet(None);
config.working_dir = persister
.get_database_dir()
.to_str()

View File

@@ -9,7 +9,7 @@ use tokio::sync::Mutex;
use super::{chain::MockLiquidChainService, swapper::MockSwapper, wallet::MockWallet};
pub(crate) fn new_send_swap_handler(persister: Arc<Persister>) -> Result<SendSwapHandler> {
let config = Config::testnet();
let config = Config::testnet(None);
let onchain_wallet = Arc::new(MockWallet::new());
let swapper = Arc::new(MockSwapper::new());
let chain_service = Arc::new(Mutex::new(MockLiquidChainService::new()));

View File

@@ -21,8 +21,8 @@ Future<BindingLiquidSdk> connect({required ConnectRequest req}) =>
/// If used, this must be called before `connect`. It can only be called once.
Stream<LogEntry> breezLogStream() => RustLib.instance.api.crateBindingsBreezLogStream();
Config defaultConfig({required LiquidNetwork network}) =>
RustLib.instance.api.crateBindingsDefaultConfig(network: network);
Config defaultConfig({required LiquidNetwork network, String? breezApiKey}) =>
RustLib.instance.api.crateBindingsDefaultConfig(network: network, breezApiKey: breezApiKey);
Future<InputType> parse({required String input}) => RustLib.instance.api.crateBindingsParse(input: input);

View File

@@ -166,7 +166,7 @@ abstract class RustLibApi extends BaseApi {
Future<BindingLiquidSdk> crateBindingsConnect({required ConnectRequest req});
Config crateBindingsDefaultConfig({required LiquidNetwork network});
Config crateBindingsDefaultConfig({required LiquidNetwork network, String? breezApiKey});
Future<InputType> crateBindingsParse({required String input});
@@ -1070,25 +1070,26 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
@override
Config crateBindingsDefaultConfig({required LiquidNetwork network}) {
Config crateBindingsDefaultConfig({required LiquidNetwork network, String? breezApiKey}) {
return handler.executeSync(SyncTask(
callFfi: () {
var arg0 = cst_encode_liquid_network(network);
return wire.wire__crate__bindings__default_config(arg0);
var arg1 = cst_encode_opt_String(breezApiKey);
return wire.wire__crate__bindings__default_config(arg0, arg1);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_config,
decodeErrorData: null,
decodeErrorData: dco_decode_sdk_error,
),
constMeta: kCrateBindingsDefaultConfigConstMeta,
argValues: [network],
argValues: [network, breezApiKey],
apiImpl: this,
));
}
TaskConstMeta get kCrateBindingsDefaultConfigConstMeta => const TaskConstMeta(
debugName: "default_config",
argNames: ["network"],
argNames: ["network", "breezApiKey"],
);
@override

View File

@@ -3943,17 +3943,20 @@ class RustLibWire implements BaseWire {
WireSyncRust2DartDco wire__crate__bindings__default_config(
int network,
ffi.Pointer<wire_cst_list_prim_u_8_strict> breez_api_key,
) {
return _wire__crate__bindings__default_config(
network,
breez_api_key,
);
}
late final _wire__crate__bindings__default_configPtr =
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function(ffi.Int32)>>(
'frbgen_breez_liquid_wire__crate__bindings__default_config');
late final _wire__crate__bindings__default_config =
_wire__crate__bindings__default_configPtr.asFunction<WireSyncRust2DartDco Function(int)>();
late final _wire__crate__bindings__default_configPtr = _lookup<
ffi.NativeFunction<
WireSyncRust2DartDco Function(ffi.Int32, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
'frbgen_breez_liquid_wire__crate__bindings__default_config');
late final _wire__crate__bindings__default_config = _wire__crate__bindings__default_configPtr
.asFunction<WireSyncRust2DartDco Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
void wire__crate__bindings__parse(
int port_,

View File

@@ -9,8 +9,9 @@ void main() {
group('main', () {
setUpAll(() async {
await initApi();
ConnectRequest connectRequest =
ConnectRequest(mnemonic: "", config: defaultConfig(network: LiquidNetwork.testnet));
ConnectRequest connectRequest = ConnectRequest(
mnemonic: "",
config: defaultConfig(network: LiquidNetwork.testnet, breezApiKey: "<breez-api-key>"));
sdk = await connect(req: connectRequest);
});

View File

@@ -690,18 +690,21 @@ class FlutterBreezLiquidBindings {
WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__default_config(
int network,
ffi.Pointer<wire_cst_list_prim_u_8_strict> breez_api_key,
) {
return _frbgen_breez_liquid_wire__crate__bindings__default_config(
network,
breez_api_key,
);
}
late final _frbgen_breez_liquid_wire__crate__bindings__default_configPtr =
_lookup<ffi.NativeFunction<WireSyncRust2DartDco Function(ffi.Int32)>>(
'frbgen_breez_liquid_wire__crate__bindings__default_config');
late final _frbgen_breez_liquid_wire__crate__bindings__default_configPtr = _lookup<
ffi.NativeFunction<
WireSyncRust2DartDco Function(ffi.Int32, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
'frbgen_breez_liquid_wire__crate__bindings__default_config');
late final _frbgen_breez_liquid_wire__crate__bindings__default_config =
_frbgen_breez_liquid_wire__crate__bindings__default_configPtr
.asFunction<WireSyncRust2DartDco Function(int)>();
.asFunction<WireSyncRust2DartDco Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
void frbgen_breez_liquid_wire__crate__bindings__parse(
int port_,

View File

@@ -224,6 +224,7 @@ fun asConfig(config: ReadableMap): Config? {
val network = config.getString("network")?.let { asLiquidNetwork(it) }!!
val paymentTimeoutSec = config.getDouble("paymentTimeoutSec").toULong()
val zeroConfMinFeeRateMsat = config.getInt("zeroConfMinFeeRateMsat").toUInt()
val breezApiKey = if (hasNonNullKey(config, "breezApiKey")) config.getString("breezApiKey") else null
val zeroConfMaxAmountSat =
if (hasNonNullKey(
config,
@@ -234,7 +235,6 @@ fun asConfig(config: ReadableMap): Config? {
} else {
null
}
val breezApiKey = if (hasNonNullKey(config, "breezApiKey")) config.getString("breezApiKey") else null
return Config(
liquidElectrumUrl,
bitcoinElectrumUrl,
@@ -243,8 +243,8 @@ fun asConfig(config: ReadableMap): Config? {
network,
paymentTimeoutSec,
zeroConfMinFeeRateMsat,
zeroConfMaxAmountSat,
breezApiKey,
zeroConfMaxAmountSat,
)
}
@@ -257,8 +257,8 @@ fun readableMapOf(config: Config): ReadableMap =
"network" to config.network.name.lowercase(),
"paymentTimeoutSec" to config.paymentTimeoutSec,
"zeroConfMinFeeRateMsat" to config.zeroConfMinFeeRateMsat,
"zeroConfMaxAmountSat" to config.zeroConfMaxAmountSat,
"breezApiKey" to config.breezApiKey,
"zeroConfMaxAmountSat" to config.zeroConfMaxAmountSat,
)
fun asConfigList(arr: ReadableArray): List<Config> {

View File

@@ -57,12 +57,14 @@ class BreezSDKLiquidModule(
@ReactMethod
fun defaultConfig(
network: String,
breezApiKey: String,
promise: Promise,
) {
executor.execute {
try {
val networkTmp = asLiquidNetwork(network)
val res = defaultConfig(networkTmp)
val breezApiKeyTmp = breezApiKey.takeUnless { it.isEmpty() }
val res = defaultConfig(networkTmp, breezApiKeyTmp)
val workingDir = File(reactApplicationContext.filesDir.toString() + "/breezSdkLiquid")
res.workingDir = workingDir.absolutePath

View File

@@ -268,13 +268,6 @@ enum BreezSDKLiquidMapper {
guard let zeroConfMinFeeRateMsat = config["zeroConfMinFeeRateMsat"] as? UInt32 else {
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "zeroConfMinFeeRateMsat", typeName: "Config"))
}
var zeroConfMaxAmountSat: UInt64?
if hasNonNilKey(data: config, key: "zeroConfMaxAmountSat") {
guard let zeroConfMaxAmountSatTmp = config["zeroConfMaxAmountSat"] as? UInt64 else {
throw SdkError.Generic(message: errUnexpectedValue(fieldName: "zeroConfMaxAmountSat"))
}
zeroConfMaxAmountSat = zeroConfMaxAmountSatTmp
}
var breezApiKey: String?
if hasNonNilKey(data: config, key: "breezApiKey") {
guard let breezApiKeyTmp = config["breezApiKey"] as? String else {
@@ -282,8 +275,15 @@ enum BreezSDKLiquidMapper {
}
breezApiKey = breezApiKeyTmp
}
var zeroConfMaxAmountSat: UInt64?
if hasNonNilKey(data: config, key: "zeroConfMaxAmountSat") {
guard let zeroConfMaxAmountSatTmp = config["zeroConfMaxAmountSat"] as? UInt64 else {
throw SdkError.Generic(message: errUnexpectedValue(fieldName: "zeroConfMaxAmountSat"))
}
zeroConfMaxAmountSat = zeroConfMaxAmountSatTmp
}
return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, zeroConfMaxAmountSat: zeroConfMaxAmountSat, breezApiKey: breezApiKey)
return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, breezApiKey: breezApiKey, zeroConfMaxAmountSat: zeroConfMaxAmountSat)
}
static func dictionaryOf(config: Config) -> [String: Any?] {
@@ -295,8 +295,8 @@ enum BreezSDKLiquidMapper {
"network": valueOf(liquidNetwork: config.network),
"paymentTimeoutSec": config.paymentTimeoutSec,
"zeroConfMinFeeRateMsat": config.zeroConfMinFeeRateMsat,
"zeroConfMaxAmountSat": config.zeroConfMaxAmountSat == nil ? nil : config.zeroConfMaxAmountSat,
"breezApiKey": config.breezApiKey == nil ? nil : config.breezApiKey,
"zeroConfMaxAmountSat": config.zeroConfMaxAmountSat == nil ? nil : config.zeroConfMaxAmountSat,
]
}

View File

@@ -5,6 +5,7 @@
RCT_EXTERN_METHOD(
defaultConfig: (NSString*)network
breezApiKey: (NSString*)breezApiKey
resolve: (RCTPromiseResolveBlock)resolve
reject: (RCTPromiseRejectBlock)reject
)

View File

@@ -71,11 +71,12 @@ class RNBreezSDKLiquid: RCTEventEmitter {
}
}
@objc(defaultConfig:resolve:reject:)
func defaultConfig(_ network: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
@objc(defaultConfig:breezApiKey:resolve:reject:)
func defaultConfig(_ network: String, breezApiKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
do {
let networkTmp = try BreezSDKLiquidMapper.asLiquidNetwork(liquidNetwork: network)
var res = BreezSDKLiquid.defaultConfig(network: networkTmp)
let breezApiKeyTmp = breezApiKey.isEmpty ? nil : breezApiKey
var res = try BreezSDKLiquid.defaultConfig(network: networkTmp, breezApiKey: breezApiKeyTmp)
res.workingDir = RNBreezSDKLiquid.breezSdkLiquidDirectory.path
resolve(BreezSDKLiquidMapper.dictionaryOf(config: res))
} catch let err {

View File

@@ -59,8 +59,8 @@ export interface Config {
network: LiquidNetwork
paymentTimeoutSec: number
zeroConfMinFeeRateMsat: number
zeroConfMaxAmountSat?: number
breezApiKey?: string
zeroConfMaxAmountSat?: number
}
export interface ConnectRequest {
@@ -637,8 +637,8 @@ export const setLogger = async (logger: Logger): Promise<EmitterSubscription> =>
return subscription
}
export const defaultConfig = async (network: LiquidNetwork): Promise<Config> => {
const response = await BreezSDKLiquid.defaultConfig(network)
export const defaultConfig = async (network: LiquidNetwork, breezApiKey: string = ""): Promise<Config> => {
const response = await BreezSDKLiquid.defaultConfig(network, breezApiKey)
return response
}