mirror of
https://github.com/aljazceru/breez-sdk-liquid.git
synced 2026-01-04 06:44:21 +01:00
Implement Chain Swaps for sending (#298)
This commit is contained in:
176
cli/Cargo.lock
generated
176
cli/Cargo.lock
generated
@@ -381,7 +381,7 @@ checksum = "829a082bd3761fde7476dc2ed85ca56c11628948460ece621e4f56fef5046567"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "boltz-client"
|
name = "boltz-client"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "git+https://github.com/hydra-yse/boltz-rust?branch=yse-breez-latest#66cdf65ba889a25a5274af3d27f5f52a2d4e3cc9"
|
source = "git+https://github.com/dangeross/boltz-rust?rev=cb2cb02d44fb81cc8ce5d8000346f52cc26b3fc1#cb2cb02d44fb81cc8ce5d8000346f52cc26b3fc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bip39",
|
"bip39",
|
||||||
"bitcoin 0.31.2",
|
"bitcoin 0.31.2",
|
||||||
@@ -423,15 +423,18 @@ dependencies = [
|
|||||||
"bip39",
|
"bip39",
|
||||||
"boltz-client",
|
"boltz-client",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"electrum-client",
|
||||||
"env_logger 0.11.3",
|
"env_logger 0.11.3",
|
||||||
"flutter_rust_bridge",
|
"flutter_rust_bridge",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"glob",
|
"glob",
|
||||||
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"lwk_common",
|
"lwk_common",
|
||||||
"lwk_signer",
|
"lwk_signer",
|
||||||
"lwk_wollet",
|
"lwk_wollet",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
"reqwest 0.11.20",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rusqlite_migration",
|
"rusqlite_migration",
|
||||||
"security-framework",
|
"security-framework",
|
||||||
@@ -1041,6 +1044,25 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http 0.2.12",
|
||||||
|
"indexmap",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@@ -1052,7 +1074,7 @@ dependencies = [
|
|||||||
"fnv",
|
"fnv",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1133,6 +1155,17 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -1144,6 +1177,17 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 0.2.12",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body"
|
name = "http-body"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -1151,7 +1195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1162,8 +1206,8 @@ checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1173,6 +1217,12 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -1188,6 +1238,30 @@ version = "2.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.26",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@@ -1197,9 +1271,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.5",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1215,8 +1289,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.22.4",
|
"rustls 0.22.4",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -1225,6 +1299,19 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"hyper 0.14.29",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -1234,9 +1321,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1428,7 +1515,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"lwk_common",
|
"lwk_common",
|
||||||
"rand",
|
"rand",
|
||||||
"reqwest",
|
"reqwest 0.12.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
@@ -1469,7 +1556,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"reqwest",
|
"reqwest 0.12.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -1882,6 +1969,43 @@ version = "0.8.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.26",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"hyper 0.14.29",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg 0.50.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
@@ -1894,11 +2018,11 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.5",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
@@ -1924,7 +2048,7 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots 0.26.1",
|
"webpki-roots 0.26.1",
|
||||||
"winreg",
|
"winreg 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2579,7 +2703,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
@@ -3000,6 +3124,16 @@ version = "0.52.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use serde_json::to_string_pretty;
|
|||||||
|
|
||||||
#[derive(Parser, Debug, Clone, PartialEq)]
|
#[derive(Parser, Debug, Clone, PartialEq)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Send lbtc and receive btc through a swap
|
/// Send lbtc and receive btc lightning through a swap
|
||||||
SendPayment {
|
SendPayment {
|
||||||
/// Invoice which has to be paid
|
/// Invoice which has to be paid
|
||||||
bolt11: String,
|
bolt11: String,
|
||||||
@@ -29,6 +29,14 @@ pub(crate) enum Command {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
delay: Option<u64>,
|
delay: Option<u64>,
|
||||||
},
|
},
|
||||||
|
/// Send lbtc and receive btc onchain through a swap
|
||||||
|
SendOnchainPayment {
|
||||||
|
/// Btc onchain address to send to
|
||||||
|
address: String,
|
||||||
|
|
||||||
|
/// Amount that will be received, in satoshi
|
||||||
|
amount_sat: u64,
|
||||||
|
},
|
||||||
/// Receive lbtc and send btc through a swap
|
/// Receive lbtc and send btc through a swap
|
||||||
ReceivePayment {
|
ReceivePayment {
|
||||||
/// Amount the payer will send, in satoshi
|
/// Amount the payer will send, in satoshi
|
||||||
@@ -150,6 +158,30 @@ pub(crate) async fn handle_command(
|
|||||||
command_result!(response)
|
command_result!(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Command::SendOnchainPayment {
|
||||||
|
address,
|
||||||
|
amount_sat,
|
||||||
|
} => {
|
||||||
|
let prepare_res = sdk
|
||||||
|
.prepare_pay_onchain(&PreparePayOnchainRequest { amount_sat })
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
wait_confirmation!(
|
||||||
|
format!(
|
||||||
|
"Fees: {} sat. Are the fees acceptable? (y/N) ",
|
||||||
|
prepare_res.fees_sat
|
||||||
|
),
|
||||||
|
"Payment send halted"
|
||||||
|
);
|
||||||
|
|
||||||
|
let response = sdk
|
||||||
|
.pay_onchain(&PayOnchainRequest {
|
||||||
|
address,
|
||||||
|
prepare_res,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
command_result!(response)
|
||||||
|
}
|
||||||
Command::GetInfo => {
|
Command::GetInfo => {
|
||||||
command_result!(sdk.get_info().await?)
|
command_result!(sdk.get_info().await?)
|
||||||
}
|
}
|
||||||
|
|||||||
176
lib/Cargo.lock
generated
176
lib/Cargo.lock
generated
@@ -501,7 +501,7 @@ checksum = "829a082bd3761fde7476dc2ed85ca56c11628948460ece621e4f56fef5046567"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "boltz-client"
|
name = "boltz-client"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "git+https://github.com/hydra-yse/boltz-rust?branch=yse-breez-latest#66cdf65ba889a25a5274af3d27f5f52a2d4e3cc9"
|
source = "git+https://github.com/dangeross/boltz-rust?rev=cb2cb02d44fb81cc8ce5d8000346f52cc26b3fc1#cb2cb02d44fb81cc8ce5d8000346f52cc26b3fc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bip39",
|
"bip39",
|
||||||
"bitcoin 0.31.2",
|
"bitcoin 0.31.2",
|
||||||
@@ -527,15 +527,18 @@ dependencies = [
|
|||||||
"bip39",
|
"bip39",
|
||||||
"boltz-client",
|
"boltz-client",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"electrum-client",
|
||||||
"env_logger 0.11.3",
|
"env_logger 0.11.3",
|
||||||
"flutter_rust_bridge",
|
"flutter_rust_bridge",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"glob",
|
"glob",
|
||||||
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"lwk_common",
|
"lwk_common",
|
||||||
"lwk_signer",
|
"lwk_signer",
|
||||||
"lwk_wollet",
|
"lwk_wollet",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
"reqwest 0.11.20",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"rusqlite_migration",
|
"rusqlite_migration",
|
||||||
"security-framework",
|
"security-framework",
|
||||||
@@ -1240,6 +1243,25 @@ dependencies = [
|
|||||||
"scroll 0.12.0",
|
"scroll 0.12.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http 0.2.12",
|
||||||
|
"indexmap 2.2.6",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@@ -1251,7 +1273,7 @@ dependencies = [
|
|||||||
"fnv",
|
"fnv",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1335,6 +1357,17 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
|
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -1346,6 +1379,17 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 0.2.12",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body"
|
name = "http-body"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -1353,7 +1397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1364,8 +1408,8 @@ checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1375,6 +1419,12 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -1390,6 +1440,30 @@ version = "2.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.26",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@@ -1399,9 +1473,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.5",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1417,8 +1491,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.22.4",
|
"rustls 0.22.4",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -1427,6 +1501,19 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"hyper 0.14.29",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -1436,9 +1523,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1659,7 +1746,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"lwk_common",
|
"lwk_common",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest",
|
"reqwest 0.12.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
@@ -1700,7 +1787,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"reqwest",
|
"reqwest 0.12.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -2229,6 +2316,43 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2 0.3.26",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"hyper 0.14.29",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg 0.50.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
@@ -2241,11 +2365,11 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2 0.4.5",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"http-body",
|
"http-body 1.0.0",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper 1.3.1",
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
@@ -2271,7 +2395,7 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots 0.26.1",
|
"webpki-roots 0.26.1",
|
||||||
"winreg",
|
"winreg 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3017,7 +3141,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"http",
|
"http 1.1.0",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
@@ -3814,6 +3938,16 @@ version = "0.52.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|||||||
@@ -35,6 +35,20 @@ typedef struct wire_cst_backup_request {
|
|||||||
struct wire_cst_list_prim_u_8_strict *backup_path;
|
struct wire_cst_list_prim_u_8_strict *backup_path;
|
||||||
} wire_cst_backup_request;
|
} wire_cst_backup_request;
|
||||||
|
|
||||||
|
typedef struct wire_cst_prepare_pay_onchain_response {
|
||||||
|
uint64_t amount_sat;
|
||||||
|
uint64_t fees_sat;
|
||||||
|
} wire_cst_prepare_pay_onchain_response;
|
||||||
|
|
||||||
|
typedef struct wire_cst_pay_onchain_request {
|
||||||
|
struct wire_cst_list_prim_u_8_strict *address;
|
||||||
|
struct wire_cst_prepare_pay_onchain_response prepare_res;
|
||||||
|
} wire_cst_pay_onchain_request;
|
||||||
|
|
||||||
|
typedef struct wire_cst_prepare_pay_onchain_request {
|
||||||
|
uint64_t amount_sat;
|
||||||
|
} wire_cst_prepare_pay_onchain_request;
|
||||||
|
|
||||||
typedef struct wire_cst_prepare_receive_request {
|
typedef struct wire_cst_prepare_receive_request {
|
||||||
uint64_t payer_amount_sat;
|
uint64_t payer_amount_sat;
|
||||||
} wire_cst_prepare_receive_request;
|
} wire_cst_prepare_receive_request;
|
||||||
@@ -115,7 +129,8 @@ typedef struct wire_cst_liquid_sdk_event {
|
|||||||
|
|
||||||
typedef struct wire_cst_config {
|
typedef struct wire_cst_config {
|
||||||
struct wire_cst_list_prim_u_8_strict *boltz_url;
|
struct wire_cst_list_prim_u_8_strict *boltz_url;
|
||||||
struct wire_cst_list_prim_u_8_strict *electrum_url;
|
struct wire_cst_list_prim_u_8_strict *liquid_electrum_url;
|
||||||
|
struct wire_cst_list_prim_u_8_strict *bitcoin_electrum_url;
|
||||||
struct wire_cst_list_prim_u_8_strict *working_dir;
|
struct wire_cst_list_prim_u_8_strict *working_dir;
|
||||||
int32_t network;
|
int32_t network;
|
||||||
uint64_t payment_timeout_sec;
|
uint64_t payment_timeout_sec;
|
||||||
@@ -168,8 +183,13 @@ typedef struct wire_cst_LiquidSdkError_Generic {
|
|||||||
struct wire_cst_list_prim_u_8_strict *err;
|
struct wire_cst_list_prim_u_8_strict *err;
|
||||||
} wire_cst_LiquidSdkError_Generic;
|
} wire_cst_LiquidSdkError_Generic;
|
||||||
|
|
||||||
|
typedef struct wire_cst_LiquidSdkError_ServiceConnectivity {
|
||||||
|
struct wire_cst_list_prim_u_8_strict *err;
|
||||||
|
} wire_cst_LiquidSdkError_ServiceConnectivity;
|
||||||
|
|
||||||
typedef union LiquidSdkErrorKind {
|
typedef union LiquidSdkErrorKind {
|
||||||
struct wire_cst_LiquidSdkError_Generic Generic;
|
struct wire_cst_LiquidSdkError_Generic Generic;
|
||||||
|
struct wire_cst_LiquidSdkError_ServiceConnectivity ServiceConnectivity;
|
||||||
} LiquidSdkErrorKind;
|
} LiquidSdkErrorKind;
|
||||||
|
|
||||||
typedef struct wire_cst_liquid_sdk_error {
|
typedef struct wire_cst_liquid_sdk_error {
|
||||||
@@ -268,6 +288,14 @@ void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_get_info(int64_
|
|||||||
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_payments(int64_t port_,
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_payments(int64_t port_,
|
||||||
uintptr_t that);
|
uintptr_t that);
|
||||||
|
|
||||||
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(int64_t port_,
|
||||||
|
uintptr_t that,
|
||||||
|
struct wire_cst_pay_onchain_request *req);
|
||||||
|
|
||||||
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(int64_t port_,
|
||||||
|
uintptr_t that,
|
||||||
|
struct wire_cst_prepare_pay_onchain_request *req);
|
||||||
|
|
||||||
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(int64_t port_,
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(int64_t port_,
|
||||||
uintptr_t that,
|
uintptr_t that,
|
||||||
struct wire_cst_prepare_receive_request *req);
|
struct wire_cst_prepare_receive_request *req);
|
||||||
@@ -316,8 +344,12 @@ struct wire_cst_connect_request *frbgen_breez_liquid_cst_new_box_autoadd_connect
|
|||||||
|
|
||||||
struct wire_cst_liquid_sdk_event *frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_event(void);
|
struct wire_cst_liquid_sdk_event *frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_event(void);
|
||||||
|
|
||||||
|
struct wire_cst_pay_onchain_request *frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request(void);
|
||||||
|
|
||||||
struct wire_cst_payment *frbgen_breez_liquid_cst_new_box_autoadd_payment(void);
|
struct wire_cst_payment *frbgen_breez_liquid_cst_new_box_autoadd_payment(void);
|
||||||
|
|
||||||
|
struct wire_cst_prepare_pay_onchain_request *frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request(void);
|
||||||
|
|
||||||
struct wire_cst_prepare_receive_request *frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request(void);
|
struct wire_cst_prepare_receive_request *frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request(void);
|
||||||
|
|
||||||
struct wire_cst_prepare_receive_response *frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_response(void);
|
struct wire_cst_prepare_receive_response *frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_response(void);
|
||||||
@@ -343,7 +375,9 @@ static int64_t dummy_method_to_enforce_bundling(void) {
|
|||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_binding_event_listener);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_binding_event_listener);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_connect_request);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_connect_request);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_event);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_event);
|
||||||
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_payment);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_payment);
|
||||||
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_response);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_response);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_send_request);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_send_request);
|
||||||
@@ -362,6 +396,8 @@ static int64_t dummy_method_to_enforce_bundling(void) {
|
|||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_empty_wallet_cache);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_empty_wallet_cache);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_get_info);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_get_info);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_payments);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_payments);
|
||||||
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain);
|
||||||
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_send_payment);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_send_payment);
|
||||||
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_receive_payment);
|
dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_receive_payment);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ enum LiquidSdkError {
|
|||||||
"AlreadyStarted",
|
"AlreadyStarted",
|
||||||
"Generic",
|
"Generic",
|
||||||
"NotStarted",
|
"NotStarted",
|
||||||
|
"ServiceConnectivity",
|
||||||
};
|
};
|
||||||
|
|
||||||
[Error]
|
[Error]
|
||||||
@@ -29,7 +30,8 @@ enum PaymentError {
|
|||||||
|
|
||||||
dictionary Config {
|
dictionary Config {
|
||||||
string boltz_url;
|
string boltz_url;
|
||||||
string electrum_url;
|
string liquid_electrum_url;
|
||||||
|
string bitcoin_electrum_url;
|
||||||
string working_dir;
|
string working_dir;
|
||||||
Network network;
|
Network network;
|
||||||
u64 payment_timeout_sec;
|
u64 payment_timeout_sec;
|
||||||
@@ -81,6 +83,20 @@ dictionary ReceivePaymentResponse {
|
|||||||
string invoice;
|
string invoice;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary PreparePayOnchainRequest {
|
||||||
|
u64 amount_sat;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary PreparePayOnchainResponse {
|
||||||
|
u64 amount_sat;
|
||||||
|
u64 fees_sat;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary PayOnchainRequest {
|
||||||
|
string address;
|
||||||
|
PreparePayOnchainResponse prepare_res;
|
||||||
|
};
|
||||||
|
|
||||||
dictionary BackupRequest {
|
dictionary BackupRequest {
|
||||||
string? backup_path = null;
|
string? backup_path = null;
|
||||||
};
|
};
|
||||||
@@ -204,6 +220,12 @@ interface BindingLiquidSdk {
|
|||||||
[Throws=PaymentError]
|
[Throws=PaymentError]
|
||||||
ReceivePaymentResponse receive_payment(PrepareReceiveResponse req);
|
ReceivePaymentResponse receive_payment(PrepareReceiveResponse req);
|
||||||
|
|
||||||
|
[Throws=PaymentError]
|
||||||
|
PreparePayOnchainResponse prepare_pay_onchain(PreparePayOnchainRequest req);
|
||||||
|
|
||||||
|
[Throws=PaymentError]
|
||||||
|
SendPaymentResponse pay_onchain(PayOnchainRequest req);
|
||||||
|
|
||||||
[Throws=PaymentError]
|
[Throws=PaymentError]
|
||||||
sequence<Payment> list_payments();
|
sequence<Payment> list_payments();
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,17 @@ impl BindingLiquidSdk {
|
|||||||
rt().block_on(self.sdk.receive_payment(&req))
|
rt().block_on(self.sdk.receive_payment(&req))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn prepare_pay_onchain(
|
||||||
|
&self,
|
||||||
|
req: PreparePayOnchainRequest,
|
||||||
|
) -> Result<PreparePayOnchainResponse, PaymentError> {
|
||||||
|
rt().block_on(self.sdk.prepare_pay_onchain(&req))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pay_onchain(&self, req: PayOnchainRequest) -> Result<SendPaymentResponse, PaymentError> {
|
||||||
|
rt().block_on(self.sdk.pay_onchain(&req))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn list_payments(&self) -> Result<Vec<Payment>, PaymentError> {
|
pub fn list_payments(&self) -> Result<Vec<Payment>, PaymentError> {
|
||||||
rt().block_on(self.sdk.list_payments())
|
rt().block_on(self.sdk.list_payments())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ frb = ["dep:flutter_rust_bridge"]
|
|||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
bip39 = { version = "2.0.0", features = ["serde"] }
|
bip39 = { version = "2.0.0", features = ["serde"] }
|
||||||
#boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", rev = "a05731cc33030ada9ae14afcafe0cded22842ba6" }
|
#boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", rev = "a05731cc33030ada9ae14afcafe0cded22842ba6" }
|
||||||
boltz-client = { git = "https://github.com/hydra-yse/boltz-rust", branch = "yse-breez-latest" }
|
boltz-client = { git = "https://github.com/dangeross/boltz-rust", rev = "cb2cb02d44fb81cc8ce5d8000346f52cc26b3fc1" }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
flutter_rust_bridge = { version = "=2.0.0-dev.38", features = ["chrono"], optional = true }
|
flutter_rust_bridge = { version = "=2.0.0-dev.38", features = ["chrono"], optional = true }
|
||||||
@@ -37,6 +37,9 @@ tokio-stream = { version = "0.1.14", features = ["sync"] }
|
|||||||
url = "2.5.0"
|
url = "2.5.0"
|
||||||
futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] }
|
futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] }
|
||||||
async-trait = "0.1.80"
|
async-trait = "0.1.80"
|
||||||
|
hex = "0.4"
|
||||||
|
reqwest = { version = "=0.11.20", features = ["json"] }
|
||||||
|
electrum-client = { version = "0.19.0" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
|||||||
@@ -115,6 +115,20 @@ impl BindingLiquidSdk {
|
|||||||
self.sdk.receive_payment(&req).await
|
self.sdk.receive_payment(&req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn prepare_pay_onchain(
|
||||||
|
&self,
|
||||||
|
req: PreparePayOnchainRequest,
|
||||||
|
) -> Result<PreparePayOnchainResponse, PaymentError> {
|
||||||
|
self.sdk.prepare_pay_onchain(&req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pay_onchain(
|
||||||
|
&self,
|
||||||
|
req: PayOnchainRequest,
|
||||||
|
) -> Result<SendPaymentResponse, PaymentError> {
|
||||||
|
self.sdk.pay_onchain(&req).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn list_payments(&self) -> Result<Vec<Payment>, PaymentError> {
|
pub async fn list_payments(&self) -> Result<Vec<Payment>, PaymentError> {
|
||||||
self.sdk.list_payments().await
|
self.sdk.list_payments().await
|
||||||
}
|
}
|
||||||
|
|||||||
116
lib/core/src/chain/bitcoin.rs
Normal file
116
lib/core/src/chain/bitcoin.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use electrum_client::{Client, ElectrumApi, HeaderNotification};
|
||||||
|
use lwk_wollet::{
|
||||||
|
bitcoin::{
|
||||||
|
self,
|
||||||
|
block::Header,
|
||||||
|
consensus::{deserialize, serialize},
|
||||||
|
BlockHash, Script, Transaction, Txid,
|
||||||
|
},
|
||||||
|
ElectrumUrl, History,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Height = u32;
|
||||||
|
|
||||||
|
/// Trait implemented by types that can fetch data from a blockchain data source.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub trait BitcoinChainService: Send + Sync {
|
||||||
|
/// Get the blockchain latest block
|
||||||
|
fn tip(&mut self) -> Result<HeaderNotification>;
|
||||||
|
|
||||||
|
/// Broadcast a transaction
|
||||||
|
fn broadcast(&self, tx: &Transaction) -> Result<Txid>;
|
||||||
|
|
||||||
|
/// Get a list of transactions
|
||||||
|
fn get_transactions(&self, txids: &[Txid]) -> Result<Vec<Transaction>>;
|
||||||
|
|
||||||
|
/// Get a list of block headers
|
||||||
|
///
|
||||||
|
/// Optionally pass the blockhash if already known
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
heights: &[Height],
|
||||||
|
height_blockhash: &HashMap<Height, BlockHash>,
|
||||||
|
) -> Result<Vec<Header>>;
|
||||||
|
|
||||||
|
/// Get the transactions involved in a list of scripts
|
||||||
|
fn get_scripts_history(&self, scripts: &[&Script]) -> Result<Vec<Vec<History>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ElectrumClient {
|
||||||
|
client: Client,
|
||||||
|
tip: HeaderNotification,
|
||||||
|
}
|
||||||
|
impl ElectrumClient {
|
||||||
|
pub fn new(url: &ElectrumUrl) -> Result<Self> {
|
||||||
|
let client = url.build_client()?;
|
||||||
|
let header = client.block_headers_subscribe_raw()?;
|
||||||
|
let tip: HeaderNotification = header.try_into()?;
|
||||||
|
|
||||||
|
Ok(Self { client, tip })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitcoinChainService for ElectrumClient {
|
||||||
|
fn tip(&mut self) -> Result<HeaderNotification> {
|
||||||
|
let mut maybe_popped_header = None;
|
||||||
|
while let Some(header) = self.client.block_headers_pop_raw()? {
|
||||||
|
maybe_popped_header = Some(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(popped_header) = maybe_popped_header {
|
||||||
|
let tip: HeaderNotification = popped_header.try_into()?;
|
||||||
|
self.tip = tip;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(self.tip.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn broadcast(&self, tx: &Transaction) -> Result<Txid> {
|
||||||
|
let txid = self.client.transaction_broadcast_raw(&serialize(tx))?;
|
||||||
|
Ok(Txid::from_raw_hash(txid.to_raw_hash()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_transactions(&self, txids: &[Txid]) -> Result<Vec<Transaction>> {
|
||||||
|
let txids: Vec<bitcoin::Txid> = txids
|
||||||
|
.iter()
|
||||||
|
.map(|t| bitcoin::Txid::from_raw_hash(t.to_raw_hash()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut result = vec![];
|
||||||
|
for tx in self.client.batch_transaction_get_raw(&txids)? {
|
||||||
|
let tx: Transaction = deserialize(&tx)?;
|
||||||
|
result.push(tx);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_headers(
|
||||||
|
&self,
|
||||||
|
heights: &[Height],
|
||||||
|
_: &HashMap<Height, BlockHash>,
|
||||||
|
) -> Result<Vec<Header>> {
|
||||||
|
let mut result = vec![];
|
||||||
|
for header in self.client.batch_block_header_raw(heights)? {
|
||||||
|
let header: Header = deserialize(&header)?;
|
||||||
|
result.push(header);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scripts_history(&self, scripts: &[&Script]) -> Result<Vec<Vec<History>>> {
|
||||||
|
let scripts: Vec<&bitcoin::Script> = scripts
|
||||||
|
.iter()
|
||||||
|
.map(|t| bitcoin::Script::from_bytes(t.as_bytes()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(self
|
||||||
|
.client
|
||||||
|
.batch_script_get_history(&scripts)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| e.into_iter().map(Into::into).collect())
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
6
lib/core/src/chain/mod.rs
Normal file
6
lib/core/src/chain/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub(crate) mod bitcoin;
|
||||||
|
|
||||||
|
use lwk_wollet::{BlockchainBackend, ElectrumClient};
|
||||||
|
|
||||||
|
pub(crate) trait ChainService: Send + Sync + BlockchainBackend {}
|
||||||
|
impl ChainService for ElectrumClient {}
|
||||||
568
lib/core/src/chain_swap.rs
Normal file
568
lib/core/src/chain_swap.rs
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
use std::{str::FromStr, sync::Arc};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use boltz_client::swaps::boltzv2;
|
||||||
|
use boltz_client::swaps::{boltz::ChainSwapStates, boltzv2::CreateChainResponse};
|
||||||
|
use log::{debug, error, info, warn};
|
||||||
|
use lwk_wollet::elements::Transaction;
|
||||||
|
use lwk_wollet::ElectrumUrl;
|
||||||
|
use tokio::sync::{broadcast, Mutex};
|
||||||
|
|
||||||
|
use crate::chain::bitcoin::{BitcoinChainService, ElectrumClient};
|
||||||
|
use crate::chain::ChainService;
|
||||||
|
use crate::model::PaymentState::{Complete, Created, Failed, Pending, TimedOut};
|
||||||
|
use crate::model::{ChainSwap, Config, Direction, PaymentTxData, PaymentType};
|
||||||
|
use crate::swapper::Swapper;
|
||||||
|
use crate::wallet::OnchainWallet;
|
||||||
|
use crate::{error::PaymentError, model::PaymentState, persist::Persister};
|
||||||
|
|
||||||
|
pub(crate) struct ChainSwapStateHandler {
|
||||||
|
onchain_wallet: Arc<dyn OnchainWallet>,
|
||||||
|
persister: Arc<Persister>,
|
||||||
|
swapper: Arc<dyn Swapper>,
|
||||||
|
liquid_chain_service: Arc<Mutex<dyn ChainService>>,
|
||||||
|
bitcoin_chain_service: Arc<Mutex<dyn BitcoinChainService>>,
|
||||||
|
subscription_notifier: broadcast::Sender<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainSwapStateHandler {
|
||||||
|
pub(crate) fn new(
|
||||||
|
config: Config,
|
||||||
|
onchain_wallet: Arc<dyn OnchainWallet>,
|
||||||
|
persister: Arc<Persister>,
|
||||||
|
swapper: Arc<dyn Swapper>,
|
||||||
|
liquid_chain_service: Arc<Mutex<dyn ChainService>>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let (subscription_notifier, _) = broadcast::channel::<String>(30);
|
||||||
|
let bitcoin_chain_service = Arc::new(Mutex::new(ElectrumClient::new(&ElectrumUrl::new(
|
||||||
|
&config.bitcoin_electrum_url,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
))?));
|
||||||
|
Ok(Self {
|
||||||
|
onchain_wallet,
|
||||||
|
persister,
|
||||||
|
swapper,
|
||||||
|
liquid_chain_service,
|
||||||
|
bitcoin_chain_service,
|
||||||
|
subscription_notifier,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn subscribe_payment_updates(&self) -> broadcast::Receiver<String> {
|
||||||
|
self.subscription_notifier.subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles status updates from Boltz for Chain swaps
|
||||||
|
pub(crate) async fn on_new_status(&self, update: &boltzv2::Update) -> Result<()> {
|
||||||
|
let id = &update.id;
|
||||||
|
let swap = self
|
||||||
|
.persister
|
||||||
|
.fetch_chain_swap_by_id(id)?
|
||||||
|
.ok_or(anyhow!("No ongoing Chain Swap found for ID {id}"))?;
|
||||||
|
|
||||||
|
match swap.direction {
|
||||||
|
Direction::Incoming => self.on_new_incoming_status(&swap, update).await,
|
||||||
|
Direction::Outgoing => self.on_new_outgoing_status(&swap, update).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_new_incoming_status(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
update: &boltzv2::Update,
|
||||||
|
) -> Result<()> {
|
||||||
|
let id = &update.id;
|
||||||
|
let status = &update.status;
|
||||||
|
let swap_state = ChainSwapStates::from_str(status)
|
||||||
|
.map_err(|_| anyhow!("Invalid ChainSwapState for Chain Swap {id}: {status}"))?;
|
||||||
|
|
||||||
|
info!("Handling incoming Chain Swap transition to {status:?} for swap {id}");
|
||||||
|
// See https://docs.boltz.exchange/v/api/lifecycle#chain-swaps
|
||||||
|
match swap_state {
|
||||||
|
// Boltz announced the user lockup tx is in the mempool or has been confirmed.
|
||||||
|
ChainSwapStates::TransactionMempool | ChainSwapStates::TransactionConfirmed => {
|
||||||
|
if let Some(zero_conf_rejected) = update.zero_conf_rejected {
|
||||||
|
info!("Is zero conf rejected for Chain Swap {id}: {zero_conf_rejected}");
|
||||||
|
self.persister
|
||||||
|
.update_chain_swap_accept_zero_conf(id, !zero_conf_rejected)?;
|
||||||
|
}
|
||||||
|
if let Some(transaction) = update.transaction.clone() {
|
||||||
|
self.update_swap_info(id, Pending, None, Some(&transaction.id), None, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boltz announced the server lockup tx is in the mempool or has been confirmed.
|
||||||
|
// If it's a zero conf swap or confirmed, proceed to cooperative claim
|
||||||
|
ChainSwapStates::TransactionServerMempool
|
||||||
|
| ChainSwapStates::TransactionServerConfirmed => {
|
||||||
|
match swap.claim_tx_id.clone() {
|
||||||
|
None => match (swap.accept_zero_conf, swap_state) {
|
||||||
|
(true, _) | (_, ChainSwapStates::TransactionServerConfirmed) => {
|
||||||
|
if let Some(transaction) = update.transaction.clone() {
|
||||||
|
self.update_swap_info(
|
||||||
|
id,
|
||||||
|
Pending,
|
||||||
|
Some(&transaction.id),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
self.claim(swap).await.map_err(|e| {
|
||||||
|
error!("Could not cooperate Chain Swap {id} claim: {e}");
|
||||||
|
anyhow!("Could not post claim details. Err: {e:?}")
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
_ => info!("Waiting for server lockup confirmation for Chain Swap {id}"),
|
||||||
|
},
|
||||||
|
Some(claim_tx_id) => {
|
||||||
|
warn!("Claim tx for Chain Swap {id} was already broadcast: txid {claim_tx_id}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// If swap state is unrecoverable, either:
|
||||||
|
// 1. The transaction failed
|
||||||
|
// 2. Lockup failed (too little funds were sent)
|
||||||
|
// 3. The claim lockup was refunded
|
||||||
|
// 4. The swap has expired (>24h)
|
||||||
|
// We initiate a cooperative refund, and then fallback to a regular one
|
||||||
|
ChainSwapStates::TransactionFailed
|
||||||
|
| ChainSwapStates::TransactionLockupFailed
|
||||||
|
| ChainSwapStates::TransactionRefunded
|
||||||
|
| ChainSwapStates::SwapExpired => {
|
||||||
|
match swap.refund_tx_id.clone() {
|
||||||
|
None => {
|
||||||
|
warn!("Chain Swap {id} is in an unrecoverable state: {swap_state:?}");
|
||||||
|
match swap.user_lockup_tx_id.clone() {
|
||||||
|
// If there is a lockup tx when receiving we need to refund to a sender address
|
||||||
|
// TODO: Set the chain swap to refundable
|
||||||
|
Some(_) => {}
|
||||||
|
|
||||||
|
// No user lockup tx was broadcast when sending or receiving
|
||||||
|
None => {
|
||||||
|
warn!("Chain Swap {id} user lockup tx was never broadcast. Resolving payment as failed.");
|
||||||
|
self.update_swap_info(id, Failed, None, None, None, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(refund_tx_id) => warn!(
|
||||||
|
"Refund tx for Chain Swap {id} was already broadcast: txid {refund_tx_id}"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
debug!("Unhandled state for Chain Swap {id}: {swap_state:?}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn on_new_outgoing_status(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
update: &boltzv2::Update,
|
||||||
|
) -> Result<()> {
|
||||||
|
let id = &update.id;
|
||||||
|
let status = &update.status;
|
||||||
|
let swap_state = ChainSwapStates::from_str(status)
|
||||||
|
.map_err(|_| anyhow!("Invalid ChainSwapState for Chain Swap {id}: {status}"))?;
|
||||||
|
|
||||||
|
info!("Handling outgoing Chain Swap transition to {status:?} for swap {id}");
|
||||||
|
// See https://docs.boltz.exchange/v/api/lifecycle#chain-swaps
|
||||||
|
match swap_state {
|
||||||
|
// The swap is created
|
||||||
|
ChainSwapStates::Created => {
|
||||||
|
match swap.user_lockup_tx_id.clone() {
|
||||||
|
// Create the user lockup tx when sending
|
||||||
|
None => {
|
||||||
|
let create_response = swap.get_boltz_create_response()?;
|
||||||
|
let user_lockup_tx = self.lockup_funds(id, &create_response).await?;
|
||||||
|
let lockup_tx_id = user_lockup_tx.txid().to_string();
|
||||||
|
let lockup_tx_fees_sat: u64 = user_lockup_tx.all_fees().values().sum();
|
||||||
|
|
||||||
|
// We insert a pseudo-lockup-tx in case LWK fails to pick up the new mempool tx for a while
|
||||||
|
// This makes the tx known to the SDK (get_info, list_payments) instantly
|
||||||
|
self.persister.insert_or_update_payment(PaymentTxData {
|
||||||
|
tx_id: lockup_tx_id.clone(),
|
||||||
|
timestamp: None,
|
||||||
|
amount_sat: swap.receiver_amount_sat,
|
||||||
|
// This should be: boltz fee + lockup fee + claim fee
|
||||||
|
fees_sat: lockup_tx_fees_sat + swap.claim_fees_sat,
|
||||||
|
payment_type: PaymentType::Send,
|
||||||
|
is_confirmed: false,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.update_swap_info(id, Pending, None, Some(&lockup_tx_id), None, None)
|
||||||
|
.await?;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Lockup tx already exists when sending
|
||||||
|
Some(lockup_tx_id) => warn!("User lockup tx for Chain Swap {id} was already broadcast: txid {lockup_tx_id}"),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boltz announced the user lockup tx is in the mempool or has been confirmed.
|
||||||
|
ChainSwapStates::TransactionMempool | ChainSwapStates::TransactionConfirmed => {
|
||||||
|
if let Some(zero_conf_rejected) = update.zero_conf_rejected {
|
||||||
|
info!("Is zero conf rejected for Chain Swap {id}: {zero_conf_rejected}");
|
||||||
|
self.persister
|
||||||
|
.update_chain_swap_accept_zero_conf(id, !zero_conf_rejected)?;
|
||||||
|
}
|
||||||
|
if let Some(transaction) = update.transaction.clone() {
|
||||||
|
self.update_swap_info(id, Pending, None, Some(&transaction.id), None, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boltz announced the server lockup tx is in the mempool or has been confirmed.
|
||||||
|
// If it's a zero conf swap or confirmed, proceed to cooperative claim
|
||||||
|
ChainSwapStates::TransactionServerMempool
|
||||||
|
| ChainSwapStates::TransactionServerConfirmed => {
|
||||||
|
match swap.claim_tx_id.clone() {
|
||||||
|
None => match (swap.accept_zero_conf, swap_state) {
|
||||||
|
(true, _) | (_, ChainSwapStates::TransactionServerConfirmed) => {
|
||||||
|
if let Some(transaction) = update.transaction.clone() {
|
||||||
|
self.update_swap_info(
|
||||||
|
id,
|
||||||
|
Pending,
|
||||||
|
Some(&transaction.id),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
self.claim(swap).await.map_err(|e| {
|
||||||
|
error!("Could not cooperate Chain Swap {id} claim: {e}");
|
||||||
|
anyhow!("Could not post claim details. Err: {e:?}")
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
_ => info!("Waiting for server lockup confirmation for Chain Swap {id}"),
|
||||||
|
},
|
||||||
|
Some(claim_tx_id) => {
|
||||||
|
warn!("Claim tx for Chain Swap {id} was already broadcast: txid {claim_tx_id}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// If swap state is unrecoverable, either:
|
||||||
|
// 1. The transaction failed
|
||||||
|
// 2. Lockup failed (too little funds were sent)
|
||||||
|
// 3. The claim lockup was refunded
|
||||||
|
// 4. The swap has expired (>24h)
|
||||||
|
// We initiate a cooperative refund, and then fallback to a regular one
|
||||||
|
ChainSwapStates::TransactionFailed
|
||||||
|
| ChainSwapStates::TransactionLockupFailed
|
||||||
|
| ChainSwapStates::TransactionRefunded
|
||||||
|
| ChainSwapStates::SwapExpired => {
|
||||||
|
match swap.refund_tx_id.clone() {
|
||||||
|
None => {
|
||||||
|
warn!("Chain Swap {id} is in an unrecoverable state: {swap_state:?}");
|
||||||
|
match swap.user_lockup_tx_id.clone() {
|
||||||
|
Some(_) => {
|
||||||
|
warn!("Chain Swap {id} user lockup tx has been broadcast. Attempting refund.");
|
||||||
|
let refund_tx_id = self.refund(swap).await?;
|
||||||
|
info!("Broadcast refund tx for Chain Swap {id}. Tx id: {refund_tx_id}");
|
||||||
|
self.update_swap_info(
|
||||||
|
id,
|
||||||
|
Pending,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some(&refund_tx_id),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
warn!("Chain Swap {id} user lockup tx was never broadcast. Resolving payment as failed.");
|
||||||
|
self.update_swap_info(id, Failed, None, None, None, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(refund_tx_id) => warn!(
|
||||||
|
"Refund tx for Chain Swap {id} was already broadcast: txid {refund_tx_id}"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
debug!("Unhandled state for Chain Swap {id}: {swap_state:?}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn lockup_funds(
|
||||||
|
&self,
|
||||||
|
swap_id: &str,
|
||||||
|
create_response: &CreateChainResponse,
|
||||||
|
) -> Result<Transaction, PaymentError> {
|
||||||
|
let lockup_details = create_response.lockup_details.clone();
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Initiated Chain Swap: send {} sats to liquid address {}",
|
||||||
|
lockup_details.amount, lockup_details.lockup_address
|
||||||
|
);
|
||||||
|
|
||||||
|
let lockup_tx = self
|
||||||
|
.onchain_wallet
|
||||||
|
.build_tx(
|
||||||
|
None,
|
||||||
|
&lockup_details.lockup_address,
|
||||||
|
lockup_details.amount as u64,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let lockup_tx_id = self
|
||||||
|
.liquid_chain_service
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.broadcast(&lockup_tx)?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Successfully broadcast lockup transaction for Chain Swap {swap_id}. Lockup tx id: {lockup_tx_id}"
|
||||||
|
);
|
||||||
|
Ok(lockup_tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transitions a Chain swap to a new state
|
||||||
|
pub(crate) async fn update_swap_info(
|
||||||
|
&self,
|
||||||
|
swap_id: &str,
|
||||||
|
to_state: PaymentState,
|
||||||
|
server_lockup_tx_id: Option<&str>,
|
||||||
|
user_lockup_tx_id: Option<&str>,
|
||||||
|
claim_tx_id: Option<&str>,
|
||||||
|
refund_tx_id: Option<&str>,
|
||||||
|
) -> Result<(), PaymentError> {
|
||||||
|
info!("Transitioning Chain swap {swap_id} to {to_state:?} (server_lockup_tx_id = {:?}, user_lockup_tx_id = {:?}, claim_tx_id = {:?}), refund_tx_id = {:?})", server_lockup_tx_id, user_lockup_tx_id, claim_tx_id, refund_tx_id);
|
||||||
|
|
||||||
|
let swap: ChainSwap = self
|
||||||
|
.persister
|
||||||
|
.fetch_chain_swap_by_id(swap_id)
|
||||||
|
.map_err(|_| PaymentError::PersistError)?
|
||||||
|
.ok_or(PaymentError::Generic {
|
||||||
|
err: format!("Chain Swap not found {swap_id}"),
|
||||||
|
})?;
|
||||||
|
let payment_id = user_lockup_tx_id
|
||||||
|
.map(|c| c.to_string())
|
||||||
|
.or(swap.user_lockup_tx_id);
|
||||||
|
|
||||||
|
Self::validate_state_transition(swap.state, to_state)?;
|
||||||
|
self.persister.try_handle_chain_swap_update(
|
||||||
|
swap_id,
|
||||||
|
to_state,
|
||||||
|
server_lockup_tx_id,
|
||||||
|
user_lockup_tx_id,
|
||||||
|
claim_tx_id,
|
||||||
|
refund_tx_id,
|
||||||
|
)?;
|
||||||
|
if let Some(payment_id) = payment_id {
|
||||||
|
let _ = self.subscription_notifier.send(payment_id);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn claim(&self, chain_swap: &ChainSwap) -> Result<(), PaymentError> {
|
||||||
|
debug!("Initiating claim for Chain Swap {}", &chain_swap.id);
|
||||||
|
let refund_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
let claim_tx_id = self.swapper.claim_chain_swap(chain_swap, refund_address)?;
|
||||||
|
|
||||||
|
if chain_swap.direction == Direction::Incoming {
|
||||||
|
// We insert a pseudo-claim-tx in case LWK fails to pick up the new mempool tx for a while
|
||||||
|
// This makes the tx known to the SDK (get_info, list_payments) instantly
|
||||||
|
self.persister.insert_or_update_payment(PaymentTxData {
|
||||||
|
tx_id: claim_tx_id.clone(),
|
||||||
|
timestamp: None,
|
||||||
|
amount_sat: chain_swap.receiver_amount_sat,
|
||||||
|
fees_sat: 0,
|
||||||
|
payment_type: PaymentType::Receive,
|
||||||
|
is_confirmed: false,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_swap_info(
|
||||||
|
&chain_swap.id,
|
||||||
|
Complete,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Some(&claim_tx_id),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refund(&self, swap: &ChainSwap) -> Result<String, PaymentError> {
|
||||||
|
let amount_sat = swap.receiver_amount_sat;
|
||||||
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
|
||||||
|
let fee = self
|
||||||
|
.onchain_wallet
|
||||||
|
.build_tx(None, &output_address, amount_sat)
|
||||||
|
.await?
|
||||||
|
.all_fees()
|
||||||
|
.values()
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
let refund_res = self
|
||||||
|
.swapper
|
||||||
|
.refund_chain_swap_cooperative(swap, &output_address, fee);
|
||||||
|
match refund_res {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Cooperative refund failed: {:?}", e);
|
||||||
|
self.refund_non_cooperative(swap, fee).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refund_non_cooperative(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
info!(
|
||||||
|
"Initiating non-cooperative refund for Chain Swap {}",
|
||||||
|
&swap.id
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_height = match swap.direction {
|
||||||
|
Direction::Incoming => self.bitcoin_chain_service.lock().await.tip()?.height as u32,
|
||||||
|
Direction::Outgoing => self.liquid_chain_service.lock().await.tip()?.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
let refund_tx_id = self.swapper.refund_chain_swap_non_cooperative(
|
||||||
|
swap,
|
||||||
|
broadcast_fees_sat,
|
||||||
|
&output_address,
|
||||||
|
current_height,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Successfully broadcast non-cooperative refund for Chain Swap {}, tx: {}",
|
||||||
|
swap.id, refund_tx_id
|
||||||
|
);
|
||||||
|
Ok(refund_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_state_transition(
|
||||||
|
from_state: PaymentState,
|
||||||
|
to_state: PaymentState,
|
||||||
|
) -> Result<(), PaymentError> {
|
||||||
|
match (from_state, to_state) {
|
||||||
|
(_, Created) => Err(PaymentError::Generic {
|
||||||
|
err: "Cannot transition to Created state".to_string(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
(Created | Pending, Pending) => Ok(()),
|
||||||
|
(Complete | Failed | TimedOut, Pending) => Err(PaymentError::Generic {
|
||||||
|
err: format!("Cannot transition from {from_state:?} to Pending state"),
|
||||||
|
}),
|
||||||
|
|
||||||
|
(Created | Pending, Complete) => Ok(()),
|
||||||
|
(Complete | Failed | TimedOut, Complete) => Err(PaymentError::Generic {
|
||||||
|
err: format!("Cannot transition from {from_state:?} to Complete state"),
|
||||||
|
}),
|
||||||
|
|
||||||
|
(Created, TimedOut) => Ok(()),
|
||||||
|
(_, TimedOut) => Err(PaymentError::Generic {
|
||||||
|
err: format!("Cannot transition from {from_state:?} to TimedOut state"),
|
||||||
|
}),
|
||||||
|
|
||||||
|
(Complete, Failed) => Err(PaymentError::Generic {
|
||||||
|
err: format!("Cannot transition from {from_state:?} to Failed state"),
|
||||||
|
}),
|
||||||
|
(_, Failed) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
model::PaymentState::{self, *},
|
||||||
|
test_utils::{new_chain_swap, new_chain_swap_state_handler, new_persister},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_chain_swap_state_transitions() -> Result<()> {
|
||||||
|
let (_temp_dir, storage) = new_persister()?;
|
||||||
|
let storage = Arc::new(storage);
|
||||||
|
|
||||||
|
let chain_swap_state_handler = new_chain_swap_state_handler(storage.clone())?;
|
||||||
|
|
||||||
|
// Test valid combinations of states
|
||||||
|
let all_states = HashSet::from([Created, Pending, Complete, TimedOut, Failed]);
|
||||||
|
let valid_combinations = HashMap::from([
|
||||||
|
(
|
||||||
|
Created,
|
||||||
|
HashSet::from([Pending, Complete, TimedOut, Failed]),
|
||||||
|
),
|
||||||
|
(Pending, HashSet::from([Pending, Complete, Failed])),
|
||||||
|
(TimedOut, HashSet::from([Failed])),
|
||||||
|
(Complete, HashSet::from([])),
|
||||||
|
(Failed, HashSet::from([Failed])),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (first_state, allowed_states) in valid_combinations.iter() {
|
||||||
|
for allowed_state in allowed_states {
|
||||||
|
let chain_swap = new_chain_swap(Some(*first_state));
|
||||||
|
storage.insert_chain_swap(&chain_swap)?;
|
||||||
|
|
||||||
|
assert!(chain_swap_state_handler
|
||||||
|
.update_swap_info(&chain_swap.id, *allowed_state, None, None, None, None)
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test invalid combinations of states
|
||||||
|
let invalid_combinations: HashMap<PaymentState, HashSet<PaymentState>> = valid_combinations
|
||||||
|
.iter()
|
||||||
|
.map(|(first_state, allowed_states)| {
|
||||||
|
(
|
||||||
|
*first_state,
|
||||||
|
all_states.difference(allowed_states).cloned().collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for (first_state, disallowed_states) in invalid_combinations.iter() {
|
||||||
|
for disallowed_state in disallowed_states {
|
||||||
|
let chain_swap = new_chain_swap(Some(*first_state));
|
||||||
|
storage.insert_chain_swap(&chain_swap)?;
|
||||||
|
|
||||||
|
assert!(chain_swap_state_handler
|
||||||
|
.update_swap_info(&chain_swap.id, *disallowed_state, None, None, None, None)
|
||||||
|
.await
|
||||||
|
.is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,9 @@ pub enum LiquidSdkError {
|
|||||||
|
|
||||||
#[error("Liquid SDK instance is not running")]
|
#[error("Liquid SDK instance is not running")]
|
||||||
NotStarted,
|
NotStarted,
|
||||||
|
|
||||||
|
#[error("Service connectivity: {err}")]
|
||||||
|
ServiceConnectivity { err: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<anyhow::Error> for LiquidSdkError {
|
impl From<anyhow::Error> for LiquidSdkError {
|
||||||
@@ -41,7 +44,7 @@ pub enum PaymentError {
|
|||||||
#[error("The payment is already in progress")]
|
#[error("The payment is already in progress")]
|
||||||
PaymentInProgress,
|
PaymentInProgress,
|
||||||
|
|
||||||
#[error("Invoice amount is out of range")]
|
#[error("Amount is out of range")]
|
||||||
AmountOutOfRange,
|
AmountOutOfRange,
|
||||||
|
|
||||||
#[error("Generic error: {err}")]
|
#[error("Generic error: {err}")]
|
||||||
@@ -107,24 +110,26 @@ impl From<boltz_client::error::Error> for PaymentError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::match_single_binding)]
|
impl From<boltz_client::bitcoin::hex::HexToArrayError> for PaymentError {
|
||||||
impl From<lwk_wollet::Error> for PaymentError {
|
fn from(err: boltz_client::bitcoin::hex::HexToArrayError) -> Self {
|
||||||
fn from(err: lwk_wollet::Error) -> Self {
|
PaymentError::Generic {
|
||||||
match err {
|
err: format!("{err:?}"),
|
||||||
_ => PaymentError::LwkError {
|
}
|
||||||
err: format!("{err:?}"),
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
|
impl From<lwk_wollet::Error> for PaymentError {
|
||||||
|
fn from(err: lwk_wollet::Error) -> Self {
|
||||||
|
PaymentError::LwkError {
|
||||||
|
err: format!("{err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::match_single_binding)]
|
|
||||||
impl From<lwk_signer::SignerError> for PaymentError {
|
impl From<lwk_signer::SignerError> for PaymentError {
|
||||||
fn from(err: lwk_signer::SignerError) -> Self {
|
fn from(err: lwk_signer::SignerError) -> Self {
|
||||||
match err {
|
PaymentError::SignerError {
|
||||||
_ => PaymentError::SignerError {
|
err: format!("{err:?}"),
|
||||||
err: format!("{err:?}"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,13 @@ impl CstDecode<crate::model::LiquidSdkEvent> for *mut wire_cst_liquid_sdk_event
|
|||||||
CstDecode::<crate::model::LiquidSdkEvent>::cst_decode(*wrap).into()
|
CstDecode::<crate::model::LiquidSdkEvent>::cst_decode(*wrap).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CstDecode<crate::model::PayOnchainRequest> for *mut wire_cst_pay_onchain_request {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PayOnchainRequest {
|
||||||
|
let wrap = unsafe { flutter_rust_bridge::for_generated::box_from_leak_ptr(self) };
|
||||||
|
CstDecode::<crate::model::PayOnchainRequest>::cst_decode(*wrap).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl CstDecode<crate::model::Payment> for *mut wire_cst_payment {
|
impl CstDecode<crate::model::Payment> for *mut wire_cst_payment {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::Payment {
|
fn cst_decode(self) -> crate::model::Payment {
|
||||||
@@ -132,6 +139,15 @@ impl CstDecode<crate::model::Payment> for *mut wire_cst_payment {
|
|||||||
CstDecode::<crate::model::Payment>::cst_decode(*wrap).into()
|
CstDecode::<crate::model::Payment>::cst_decode(*wrap).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CstDecode<crate::model::PreparePayOnchainRequest>
|
||||||
|
for *mut wire_cst_prepare_pay_onchain_request
|
||||||
|
{
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PreparePayOnchainRequest {
|
||||||
|
let wrap = unsafe { flutter_rust_bridge::for_generated::box_from_leak_ptr(self) };
|
||||||
|
CstDecode::<crate::model::PreparePayOnchainRequest>::cst_decode(*wrap).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl CstDecode<crate::model::PrepareReceiveRequest> for *mut wire_cst_prepare_receive_request {
|
impl CstDecode<crate::model::PrepareReceiveRequest> for *mut wire_cst_prepare_receive_request {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::PrepareReceiveRequest {
|
fn cst_decode(self) -> crate::model::PrepareReceiveRequest {
|
||||||
@@ -178,7 +194,8 @@ impl CstDecode<crate::model::Config> for wire_cst_config {
|
|||||||
fn cst_decode(self) -> crate::model::Config {
|
fn cst_decode(self) -> crate::model::Config {
|
||||||
crate::model::Config {
|
crate::model::Config {
|
||||||
boltz_url: self.boltz_url.cst_decode(),
|
boltz_url: self.boltz_url.cst_decode(),
|
||||||
electrum_url: self.electrum_url.cst_decode(),
|
liquid_electrum_url: self.liquid_electrum_url.cst_decode(),
|
||||||
|
bitcoin_electrum_url: self.bitcoin_electrum_url.cst_decode(),
|
||||||
working_dir: self.working_dir.cst_decode(),
|
working_dir: self.working_dir.cst_decode(),
|
||||||
network: self.network.cst_decode(),
|
network: self.network.cst_decode(),
|
||||||
payment_timeout_sec: self.payment_timeout_sec.cst_decode(),
|
payment_timeout_sec: self.payment_timeout_sec.cst_decode(),
|
||||||
@@ -219,6 +236,12 @@ impl CstDecode<crate::error::LiquidSdkError> for wire_cst_liquid_sdk_error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
2 => crate::error::LiquidSdkError::NotStarted,
|
2 => crate::error::LiquidSdkError::NotStarted,
|
||||||
|
3 => {
|
||||||
|
let ans = unsafe { self.kind.ServiceConnectivity };
|
||||||
|
crate::error::LiquidSdkError::ServiceConnectivity {
|
||||||
|
err: ans.err.cst_decode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,6 +358,15 @@ impl CstDecode<crate::model::LogEntry> for wire_cst_log_entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CstDecode<crate::model::PayOnchainRequest> for wire_cst_pay_onchain_request {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PayOnchainRequest {
|
||||||
|
crate::model::PayOnchainRequest {
|
||||||
|
address: self.address.cst_decode(),
|
||||||
|
prepare_res: self.prepare_res.cst_decode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl CstDecode<crate::model::Payment> for wire_cst_payment {
|
impl CstDecode<crate::model::Payment> for wire_cst_payment {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::Payment {
|
fn cst_decode(self) -> crate::model::Payment {
|
||||||
@@ -415,6 +447,23 @@ impl CstDecode<crate::error::PaymentError> for wire_cst_payment_error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CstDecode<crate::model::PreparePayOnchainRequest> for wire_cst_prepare_pay_onchain_request {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PreparePayOnchainRequest {
|
||||||
|
crate::model::PreparePayOnchainRequest {
|
||||||
|
amount_sat: self.amount_sat.cst_decode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl CstDecode<crate::model::PreparePayOnchainResponse> for wire_cst_prepare_pay_onchain_response {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PreparePayOnchainResponse {
|
||||||
|
crate::model::PreparePayOnchainResponse {
|
||||||
|
amount_sat: self.amount_sat.cst_decode(),
|
||||||
|
fees_sat: self.fees_sat.cst_decode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl CstDecode<crate::model::PrepareReceiveRequest> for wire_cst_prepare_receive_request {
|
impl CstDecode<crate::model::PrepareReceiveRequest> for wire_cst_prepare_receive_request {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::PrepareReceiveRequest {
|
fn cst_decode(self) -> crate::model::PrepareReceiveRequest {
|
||||||
@@ -524,7 +573,8 @@ impl NewWithNullPtr for wire_cst_config {
|
|||||||
fn new_with_null_ptr() -> Self {
|
fn new_with_null_ptr() -> Self {
|
||||||
Self {
|
Self {
|
||||||
boltz_url: core::ptr::null_mut(),
|
boltz_url: core::ptr::null_mut(),
|
||||||
electrum_url: core::ptr::null_mut(),
|
liquid_electrum_url: core::ptr::null_mut(),
|
||||||
|
bitcoin_electrum_url: core::ptr::null_mut(),
|
||||||
working_dir: core::ptr::null_mut(),
|
working_dir: core::ptr::null_mut(),
|
||||||
network: Default::default(),
|
network: Default::default(),
|
||||||
payment_timeout_sec: Default::default(),
|
payment_timeout_sec: Default::default(),
|
||||||
@@ -628,6 +678,19 @@ impl Default for wire_cst_log_entry {
|
|||||||
Self::new_with_null_ptr()
|
Self::new_with_null_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl NewWithNullPtr for wire_cst_pay_onchain_request {
|
||||||
|
fn new_with_null_ptr() -> Self {
|
||||||
|
Self {
|
||||||
|
address: core::ptr::null_mut(),
|
||||||
|
prepare_res: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for wire_cst_pay_onchain_request {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new_with_null_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl NewWithNullPtr for wire_cst_payment {
|
impl NewWithNullPtr for wire_cst_payment {
|
||||||
fn new_with_null_ptr() -> Self {
|
fn new_with_null_ptr() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -663,6 +726,31 @@ impl Default for wire_cst_payment_error {
|
|||||||
Self::new_with_null_ptr()
|
Self::new_with_null_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl NewWithNullPtr for wire_cst_prepare_pay_onchain_request {
|
||||||
|
fn new_with_null_ptr() -> Self {
|
||||||
|
Self {
|
||||||
|
amount_sat: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for wire_cst_prepare_pay_onchain_request {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new_with_null_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl NewWithNullPtr for wire_cst_prepare_pay_onchain_response {
|
||||||
|
fn new_with_null_ptr() -> Self {
|
||||||
|
Self {
|
||||||
|
amount_sat: Default::default(),
|
||||||
|
fees_sat: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for wire_cst_prepare_pay_onchain_response {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new_with_null_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl NewWithNullPtr for wire_cst_prepare_receive_request {
|
impl NewWithNullPtr for wire_cst_prepare_receive_request {
|
||||||
fn new_with_null_ptr() -> Self {
|
fn new_with_null_ptr() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -829,6 +917,24 @@ pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_li
|
|||||||
wire__crate__bindings__BindingLiquidSdk_list_payments_impl(port_, that)
|
wire__crate__bindings__BindingLiquidSdk_list_payments_impl(port_, that)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(
|
||||||
|
port_: i64,
|
||||||
|
that: usize,
|
||||||
|
req: *mut wire_cst_pay_onchain_request,
|
||||||
|
) {
|
||||||
|
wire__crate__bindings__BindingLiquidSdk_pay_onchain_impl(port_, that, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(
|
||||||
|
port_: i64,
|
||||||
|
that: usize,
|
||||||
|
req: *mut wire_cst_prepare_pay_onchain_request,
|
||||||
|
) {
|
||||||
|
wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain_impl(port_, that, req)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
||||||
port_: i64,
|
port_: i64,
|
||||||
@@ -970,11 +1076,27 @@ pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_event(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request(
|
||||||
|
) -> *mut wire_cst_pay_onchain_request {
|
||||||
|
flutter_rust_bridge::for_generated::new_leak_box_ptr(
|
||||||
|
wire_cst_pay_onchain_request::new_with_null_ptr(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_payment() -> *mut wire_cst_payment {
|
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_payment() -> *mut wire_cst_payment {
|
||||||
flutter_rust_bridge::for_generated::new_leak_box_ptr(wire_cst_payment::new_with_null_ptr())
|
flutter_rust_bridge::for_generated::new_leak_box_ptr(wire_cst_payment::new_with_null_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request(
|
||||||
|
) -> *mut wire_cst_prepare_pay_onchain_request {
|
||||||
|
flutter_rust_bridge::for_generated::new_leak_box_ptr(
|
||||||
|
wire_cst_prepare_pay_onchain_request::new_with_null_ptr(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request(
|
pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request(
|
||||||
) -> *mut wire_cst_prepare_receive_request {
|
) -> *mut wire_cst_prepare_receive_request {
|
||||||
@@ -1085,7 +1207,8 @@ pub struct wire_cst_binding_event_listener {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_config {
|
pub struct wire_cst_config {
|
||||||
boltz_url: *mut wire_cst_list_prim_u_8_strict,
|
boltz_url: *mut wire_cst_list_prim_u_8_strict,
|
||||||
electrum_url: *mut wire_cst_list_prim_u_8_strict,
|
liquid_electrum_url: *mut wire_cst_list_prim_u_8_strict,
|
||||||
|
bitcoin_electrum_url: *mut wire_cst_list_prim_u_8_strict,
|
||||||
working_dir: *mut wire_cst_list_prim_u_8_strict,
|
working_dir: *mut wire_cst_list_prim_u_8_strict,
|
||||||
network: i32,
|
network: i32,
|
||||||
payment_timeout_sec: u64,
|
payment_timeout_sec: u64,
|
||||||
@@ -1116,6 +1239,7 @@ pub struct wire_cst_liquid_sdk_error {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub union LiquidSdkErrorKind {
|
pub union LiquidSdkErrorKind {
|
||||||
Generic: wire_cst_LiquidSdkError_Generic,
|
Generic: wire_cst_LiquidSdkError_Generic,
|
||||||
|
ServiceConnectivity: wire_cst_LiquidSdkError_ServiceConnectivity,
|
||||||
nil__: (),
|
nil__: (),
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -1125,6 +1249,11 @@ pub struct wire_cst_LiquidSdkError_Generic {
|
|||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_LiquidSdkError_ServiceConnectivity {
|
||||||
|
err: *mut wire_cst_list_prim_u_8_strict,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_liquid_sdk_event {
|
pub struct wire_cst_liquid_sdk_event {
|
||||||
tag: i32,
|
tag: i32,
|
||||||
kind: LiquidSdkEventKind,
|
kind: LiquidSdkEventKind,
|
||||||
@@ -1218,6 +1347,12 @@ pub struct wire_cst_log_entry {
|
|||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_pay_onchain_request {
|
||||||
|
address: *mut wire_cst_list_prim_u_8_strict,
|
||||||
|
prepare_res: wire_cst_prepare_pay_onchain_response,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_payment {
|
pub struct wire_cst_payment {
|
||||||
tx_id: *mut wire_cst_list_prim_u_8_strict,
|
tx_id: *mut wire_cst_list_prim_u_8_strict,
|
||||||
swap_id: *mut wire_cst_list_prim_u_8_strict,
|
swap_id: *mut wire_cst_list_prim_u_8_strict,
|
||||||
@@ -1287,6 +1422,17 @@ pub struct wire_cst_PaymentError_SignerError {
|
|||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_prepare_pay_onchain_request {
|
||||||
|
amount_sat: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_prepare_pay_onchain_response {
|
||||||
|
amount_sat: u64,
|
||||||
|
fees_sat: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_prepare_receive_request {
|
pub struct wire_cst_prepare_receive_request {
|
||||||
payer_amount_sat: u64,
|
payer_amount_sat: u64,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
|
|||||||
default_rust_auto_opaque = RustAutoOpaqueNom,
|
default_rust_auto_opaque = RustAutoOpaqueNom,
|
||||||
);
|
);
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.0.0-dev.38";
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.0.0-dev.38";
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 308302012;
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -107248138;
|
||||||
|
|
||||||
// Section: executor
|
// Section: executor
|
||||||
|
|
||||||
@@ -287,6 +287,95 @@ fn wire__crate__bindings__BindingLiquidSdk_list_payments_impl(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn wire__crate__bindings__BindingLiquidSdk_pay_onchain_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
that: impl CstDecode<
|
||||||
|
RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<BindingLiquidSdk>>,
|
||||||
|
>,
|
||||||
|
req: impl CstDecode<crate::model::PayOnchainRequest>,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "BindingLiquidSdk_pay_onchain",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let api_that = that.cst_decode();
|
||||||
|
let api_req = req.cst_decode();
|
||||||
|
move |context| async move {
|
||||||
|
transform_result_dco(
|
||||||
|
(move || async move {
|
||||||
|
let mut api_that_decoded = None;
|
||||||
|
let decode_indices_ =
|
||||||
|
flutter_rust_bridge::for_generated::lockable_compute_decode_order(
|
||||||
|
vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||||
|
&api_that, 0, false,
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
for i in decode_indices_ {
|
||||||
|
match i {
|
||||||
|
0 => {
|
||||||
|
api_that_decoded =
|
||||||
|
Some(api_that.lockable_decode_async_ref().await)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let api_that = &*api_that_decoded.unwrap();
|
||||||
|
crate::bindings::BindingLiquidSdk::pay_onchain(api_that, api_req).await
|
||||||
|
})()
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
that: impl CstDecode<
|
||||||
|
RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<BindingLiquidSdk>>,
|
||||||
|
>,
|
||||||
|
req: impl CstDecode<crate::model::PreparePayOnchainRequest>,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "BindingLiquidSdk_prepare_pay_onchain",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let api_that = that.cst_decode();
|
||||||
|
let api_req = req.cst_decode();
|
||||||
|
move |context| async move {
|
||||||
|
transform_result_dco(
|
||||||
|
(move || async move {
|
||||||
|
let mut api_that_decoded = None;
|
||||||
|
let decode_indices_ =
|
||||||
|
flutter_rust_bridge::for_generated::lockable_compute_decode_order(
|
||||||
|
vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||||
|
&api_that, 0, false,
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
for i in decode_indices_ {
|
||||||
|
match i {
|
||||||
|
0 => {
|
||||||
|
api_that_decoded =
|
||||||
|
Some(api_that.lockable_decode_async_ref().await)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let api_that = &*api_that_decoded.unwrap();
|
||||||
|
crate::bindings::BindingLiquidSdk::prepare_pay_onchain(api_that, api_req)
|
||||||
|
.await
|
||||||
|
})()
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment_impl(
|
fn wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
that: impl CstDecode<
|
that: impl CstDecode<
|
||||||
@@ -783,7 +872,8 @@ impl SseDecode for crate::model::Config {
|
|||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
let mut var_boltzUrl = <String>::sse_decode(deserializer);
|
let mut var_boltzUrl = <String>::sse_decode(deserializer);
|
||||||
let mut var_electrumUrl = <String>::sse_decode(deserializer);
|
let mut var_liquidElectrumUrl = <String>::sse_decode(deserializer);
|
||||||
|
let mut var_bitcoinElectrumUrl = <String>::sse_decode(deserializer);
|
||||||
let mut var_workingDir = <String>::sse_decode(deserializer);
|
let mut var_workingDir = <String>::sse_decode(deserializer);
|
||||||
let mut var_network = <crate::model::Network>::sse_decode(deserializer);
|
let mut var_network = <crate::model::Network>::sse_decode(deserializer);
|
||||||
let mut var_paymentTimeoutSec = <u64>::sse_decode(deserializer);
|
let mut var_paymentTimeoutSec = <u64>::sse_decode(deserializer);
|
||||||
@@ -791,7 +881,8 @@ impl SseDecode for crate::model::Config {
|
|||||||
let mut var_zeroConfMaxAmountSat = <Option<u64>>::sse_decode(deserializer);
|
let mut var_zeroConfMaxAmountSat = <Option<u64>>::sse_decode(deserializer);
|
||||||
return crate::model::Config {
|
return crate::model::Config {
|
||||||
boltz_url: var_boltzUrl,
|
boltz_url: var_boltzUrl,
|
||||||
electrum_url: var_electrumUrl,
|
liquid_electrum_url: var_liquidElectrumUrl,
|
||||||
|
bitcoin_electrum_url: var_bitcoinElectrumUrl,
|
||||||
working_dir: var_workingDir,
|
working_dir: var_workingDir,
|
||||||
network: var_network,
|
network: var_network,
|
||||||
payment_timeout_sec: var_paymentTimeoutSec,
|
payment_timeout_sec: var_paymentTimeoutSec,
|
||||||
@@ -858,6 +949,10 @@ impl SseDecode for crate::error::LiquidSdkError {
|
|||||||
2 => {
|
2 => {
|
||||||
return crate::error::LiquidSdkError::NotStarted;
|
return crate::error::LiquidSdkError::NotStarted;
|
||||||
}
|
}
|
||||||
|
3 => {
|
||||||
|
let mut var_err = <String>::sse_decode(deserializer);
|
||||||
|
return crate::error::LiquidSdkError::ServiceConnectivity { err: var_err };
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unimplemented!("");
|
unimplemented!("");
|
||||||
}
|
}
|
||||||
@@ -1042,6 +1137,19 @@ impl SseDecode for Option<u64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseDecode for crate::model::PayOnchainRequest {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut var_address = <String>::sse_decode(deserializer);
|
||||||
|
let mut var_prepareRes =
|
||||||
|
<crate::model::PreparePayOnchainResponse>::sse_decode(deserializer);
|
||||||
|
return crate::model::PayOnchainRequest {
|
||||||
|
address: var_address,
|
||||||
|
prepare_res: var_prepareRes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseDecode for crate::model::Payment {
|
impl SseDecode for crate::model::Payment {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
@@ -1176,6 +1284,28 @@ impl SseDecode for crate::model::PaymentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseDecode for crate::model::PreparePayOnchainRequest {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut var_amountSat = <u64>::sse_decode(deserializer);
|
||||||
|
return crate::model::PreparePayOnchainRequest {
|
||||||
|
amount_sat: var_amountSat,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseDecode for crate::model::PreparePayOnchainResponse {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
|
let mut var_amountSat = <u64>::sse_decode(deserializer);
|
||||||
|
let mut var_feesSat = <u64>::sse_decode(deserializer);
|
||||||
|
return crate::model::PreparePayOnchainResponse {
|
||||||
|
amount_sat: var_amountSat,
|
||||||
|
fees_sat: var_feesSat,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseDecode for crate::model::PrepareReceiveRequest {
|
impl SseDecode for crate::model::PrepareReceiveRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
@@ -1400,7 +1530,8 @@ impl flutter_rust_bridge::IntoDart for crate::model::Config {
|
|||||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
[
|
[
|
||||||
self.boltz_url.into_into_dart().into_dart(),
|
self.boltz_url.into_into_dart().into_dart(),
|
||||||
self.electrum_url.into_into_dart().into_dart(),
|
self.liquid_electrum_url.into_into_dart().into_dart(),
|
||||||
|
self.bitcoin_electrum_url.into_into_dart().into_dart(),
|
||||||
self.working_dir.into_into_dart().into_dart(),
|
self.working_dir.into_into_dart().into_dart(),
|
||||||
self.network.into_into_dart().into_dart(),
|
self.network.into_into_dart().into_dart(),
|
||||||
self.payment_timeout_sec.into_into_dart().into_dart(),
|
self.payment_timeout_sec.into_into_dart().into_dart(),
|
||||||
@@ -1463,6 +1594,9 @@ impl flutter_rust_bridge::IntoDart for crate::error::LiquidSdkError {
|
|||||||
[1.into_dart(), err.into_into_dart().into_dart()].into_dart()
|
[1.into_dart(), err.into_into_dart().into_dart()].into_dart()
|
||||||
}
|
}
|
||||||
crate::error::LiquidSdkError::NotStarted => [2.into_dart()].into_dart(),
|
crate::error::LiquidSdkError::NotStarted => [2.into_dart()].into_dart(),
|
||||||
|
crate::error::LiquidSdkError::ServiceConnectivity { err } => {
|
||||||
|
[3.into_dart(), err.into_into_dart().into_dart()].into_dart()
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unimplemented!("");
|
unimplemented!("");
|
||||||
}
|
}
|
||||||
@@ -1575,6 +1709,27 @@ impl flutter_rust_bridge::IntoIntoDart<crate::model::Network> for crate::model::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
impl flutter_rust_bridge::IntoDart for crate::model::PayOnchainRequest {
|
||||||
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
|
[
|
||||||
|
self.address.into_into_dart().into_dart(),
|
||||||
|
self.prepare_res.into_into_dart().into_dart(),
|
||||||
|
]
|
||||||
|
.into_dart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||||
|
for crate::model::PayOnchainRequest
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::IntoIntoDart<crate::model::PayOnchainRequest>
|
||||||
|
for crate::model::PayOnchainRequest
|
||||||
|
{
|
||||||
|
fn into_into_dart(self) -> crate::model::PayOnchainRequest {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
impl flutter_rust_bridge::IntoDart for crate::model::Payment {
|
impl flutter_rust_bridge::IntoDart for crate::model::Payment {
|
||||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
[
|
[
|
||||||
@@ -1686,6 +1841,44 @@ impl flutter_rust_bridge::IntoIntoDart<crate::model::PaymentType> for crate::mod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
impl flutter_rust_bridge::IntoDart for crate::model::PreparePayOnchainRequest {
|
||||||
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
|
[self.amount_sat.into_into_dart().into_dart()].into_dart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||||
|
for crate::model::PreparePayOnchainRequest
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::IntoIntoDart<crate::model::PreparePayOnchainRequest>
|
||||||
|
for crate::model::PreparePayOnchainRequest
|
||||||
|
{
|
||||||
|
fn into_into_dart(self) -> crate::model::PreparePayOnchainRequest {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
impl flutter_rust_bridge::IntoDart for crate::model::PreparePayOnchainResponse {
|
||||||
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
|
[
|
||||||
|
self.amount_sat.into_into_dart().into_dart(),
|
||||||
|
self.fees_sat.into_into_dart().into_dart(),
|
||||||
|
]
|
||||||
|
.into_dart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||||
|
for crate::model::PreparePayOnchainResponse
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::IntoIntoDart<crate::model::PreparePayOnchainResponse>
|
||||||
|
for crate::model::PreparePayOnchainResponse
|
||||||
|
{
|
||||||
|
fn into_into_dart(self) -> crate::model::PreparePayOnchainResponse {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
impl flutter_rust_bridge::IntoDart for crate::model::PrepareReceiveRequest {
|
impl flutter_rust_bridge::IntoDart for crate::model::PrepareReceiveRequest {
|
||||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
[self.payer_amount_sat.into_into_dart().into_dart()].into_dart()
|
[self.payer_amount_sat.into_into_dart().into_dart()].into_dart()
|
||||||
@@ -1917,7 +2110,8 @@ impl SseEncode for crate::model::Config {
|
|||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
<String>::sse_encode(self.boltz_url, serializer);
|
<String>::sse_encode(self.boltz_url, serializer);
|
||||||
<String>::sse_encode(self.electrum_url, serializer);
|
<String>::sse_encode(self.liquid_electrum_url, serializer);
|
||||||
|
<String>::sse_encode(self.bitcoin_electrum_url, serializer);
|
||||||
<String>::sse_encode(self.working_dir, serializer);
|
<String>::sse_encode(self.working_dir, serializer);
|
||||||
<crate::model::Network>::sse_encode(self.network, serializer);
|
<crate::model::Network>::sse_encode(self.network, serializer);
|
||||||
<u64>::sse_encode(self.payment_timeout_sec, serializer);
|
<u64>::sse_encode(self.payment_timeout_sec, serializer);
|
||||||
@@ -1972,6 +2166,10 @@ impl SseEncode for crate::error::LiquidSdkError {
|
|||||||
crate::error::LiquidSdkError::NotStarted => {
|
crate::error::LiquidSdkError::NotStarted => {
|
||||||
<i32>::sse_encode(2, serializer);
|
<i32>::sse_encode(2, serializer);
|
||||||
}
|
}
|
||||||
|
crate::error::LiquidSdkError::ServiceConnectivity { err } => {
|
||||||
|
<i32>::sse_encode(3, serializer);
|
||||||
|
<String>::sse_encode(err, serializer);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unimplemented!("");
|
unimplemented!("");
|
||||||
}
|
}
|
||||||
@@ -2119,6 +2317,14 @@ impl SseEncode for Option<u64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseEncode for crate::model::PayOnchainRequest {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<String>::sse_encode(self.address, serializer);
|
||||||
|
<crate::model::PreparePayOnchainResponse>::sse_encode(self.prepare_res, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseEncode for crate::model::Payment {
|
impl SseEncode for crate::model::Payment {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
@@ -2244,6 +2450,21 @@ impl SseEncode for crate::model::PaymentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseEncode for crate::model::PreparePayOnchainRequest {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<u64>::sse_encode(self.amount_sat, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SseEncode for crate::model::PreparePayOnchainResponse {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
<u64>::sse_encode(self.amount_sat, serializer);
|
||||||
|
<u64>::sse_encode(self.fees_sat, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseEncode for crate::model::PrepareReceiveRequest {
|
impl SseEncode for crate::model::PrepareReceiveRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#[cfg(feature = "frb")]
|
#[cfg(feature = "frb")]
|
||||||
pub(crate) mod bindings;
|
pub(crate) mod bindings;
|
||||||
|
pub(crate) mod chain;
|
||||||
|
pub(crate) mod chain_swap;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub(crate) mod event;
|
pub(crate) mod event;
|
||||||
#[cfg(feature = "frb")]
|
#[cfg(feature = "frb")]
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use boltz_client::network::Chain;
|
use boltz_client::network::Chain;
|
||||||
use boltz_client::swaps::boltzv2::{
|
use boltz_client::swaps::boltzv2::{
|
||||||
CreateReverseResponse, CreateSubmarineResponse, Leaf, SwapTree, BOLTZ_MAINNET_URL_V2,
|
CreateChainResponse, CreateReverseResponse, CreateSubmarineResponse, Leaf, Side, SwapTree,
|
||||||
BOLTZ_TESTNET_URL_V2,
|
BOLTZ_MAINNET_URL_V2, BOLTZ_TESTNET_URL_V2,
|
||||||
};
|
};
|
||||||
use boltz_client::{Keypair, LBtcSwapScriptV2, ToHex};
|
use boltz_client::{BtcSwapScriptV2, BtcSwapTxV2, Keypair, LBtcSwapScriptV2, LBtcSwapTxV2, ToHex};
|
||||||
use lwk_wollet::ElementsNetwork;
|
use lwk_wollet::ElementsNetwork;
|
||||||
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef};
|
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef};
|
||||||
use rusqlite::ToSql;
|
use rusqlite::ToSql;
|
||||||
@@ -21,7 +21,8 @@ use crate::utils;
|
|||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub boltz_url: String,
|
pub boltz_url: String,
|
||||||
pub electrum_url: String,
|
pub liquid_electrum_url: String,
|
||||||
|
pub bitcoin_electrum_url: String,
|
||||||
/// Directory in which all SDK files (DB, log, cache) are stored.
|
/// Directory in which all SDK files (DB, log, cache) are stored.
|
||||||
///
|
///
|
||||||
/// Prefix can be a relative or absolute path to this directory.
|
/// Prefix can be a relative or absolute path to this directory.
|
||||||
@@ -40,7 +41,8 @@ impl Config {
|
|||||||
pub fn mainnet() -> Self {
|
pub fn mainnet() -> Self {
|
||||||
Config {
|
Config {
|
||||||
boltz_url: BOLTZ_MAINNET_URL_V2.to_owned(),
|
boltz_url: BOLTZ_MAINNET_URL_V2.to_owned(),
|
||||||
electrum_url: "blockstream.info:995".to_string(),
|
liquid_electrum_url: "blockstream.info:995".to_string(),
|
||||||
|
bitcoin_electrum_url: "blockstream.info:700".to_string(),
|
||||||
working_dir: ".".to_string(),
|
working_dir: ".".to_string(),
|
||||||
network: Network::Mainnet,
|
network: Network::Mainnet,
|
||||||
payment_timeout_sec: 15,
|
payment_timeout_sec: 15,
|
||||||
@@ -52,7 +54,8 @@ impl Config {
|
|||||||
pub fn testnet() -> Self {
|
pub fn testnet() -> Self {
|
||||||
Config {
|
Config {
|
||||||
boltz_url: BOLTZ_TESTNET_URL_V2.to_owned(),
|
boltz_url: BOLTZ_TESTNET_URL_V2.to_owned(),
|
||||||
electrum_url: "blockstream.info:465".to_string(),
|
liquid_electrum_url: "blockstream.info:465".to_string(),
|
||||||
|
bitcoin_electrum_url: "blockstream.info:993".to_string(),
|
||||||
working_dir: ".".to_string(),
|
working_dir: ".".to_string(),
|
||||||
network: Network::Testnet,
|
network: Network::Testnet,
|
||||||
payment_timeout_sec: 15,
|
payment_timeout_sec: 15,
|
||||||
@@ -74,6 +77,14 @@ pub enum Network {
|
|||||||
/// Testnet Bitcoin and Liquid chains
|
/// Testnet Bitcoin and Liquid chains
|
||||||
Testnet,
|
Testnet,
|
||||||
}
|
}
|
||||||
|
impl Network {
|
||||||
|
pub fn as_bitcoin_chain(&self) -> Chain {
|
||||||
|
match self {
|
||||||
|
Network::Mainnet => Chain::Bitcoin,
|
||||||
|
Network::Testnet => Chain::BitcoinTestnet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Network> for ElementsNetwork {
|
impl From<Network> for ElementsNetwork {
|
||||||
fn from(value: Network) -> Self {
|
fn from(value: Network) -> Self {
|
||||||
@@ -176,6 +187,23 @@ pub struct SendPaymentResponse {
|
|||||||
pub payment: Payment,
|
pub payment: Payment,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
pub struct PreparePayOnchainRequest {
|
||||||
|
pub amount_sat: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
pub struct PreparePayOnchainResponse {
|
||||||
|
pub amount_sat: u64,
|
||||||
|
pub fees_sat: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct PayOnchainRequest {
|
||||||
|
pub address: String,
|
||||||
|
pub prepare_res: PreparePayOnchainResponse,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct GetInfoResponse {
|
pub struct GetInfoResponse {
|
||||||
/// Usable balance. This is the confirmed onchain balance minus `pending_send_sat`.
|
/// Usable balance. This is the confirmed onchain balance minus `pending_send_sat`.
|
||||||
@@ -201,19 +229,193 @@ pub struct RestoreRequest {
|
|||||||
pub backup_path: Option<String>,
|
pub backup_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A swap enum variant
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) enum Swap {
|
pub(crate) enum Swap {
|
||||||
|
Chain(ChainSwap),
|
||||||
Send(SendSwap),
|
Send(SendSwap),
|
||||||
Receive(ReceiveSwap),
|
Receive(ReceiveSwap),
|
||||||
}
|
}
|
||||||
impl Swap {
|
impl Swap {
|
||||||
pub(crate) fn id(&self) -> String {
|
pub(crate) fn id(&self) -> String {
|
||||||
match &self {
|
match &self {
|
||||||
Swap::Send(SendSwap { id, .. }) | Swap::Receive(ReceiveSwap { id, .. }) => id.clone(),
|
Swap::Chain(ChainSwap { id, .. })
|
||||||
|
| Swap::Send(SendSwap { id, .. })
|
||||||
|
| Swap::Receive(ReceiveSwap { id, .. }) => id.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) enum SwapScriptV2 {
|
||||||
|
Bitcoin(BtcSwapScriptV2),
|
||||||
|
Liquid(LBtcSwapScriptV2),
|
||||||
|
}
|
||||||
|
impl SwapScriptV2 {
|
||||||
|
pub(crate) fn as_bitcoin_script(&self) -> Result<BtcSwapScriptV2> {
|
||||||
|
match self {
|
||||||
|
SwapScriptV2::Bitcoin(script) => Ok(script.clone()),
|
||||||
|
_ => Err(anyhow!("Invalid chain")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_liquid_script(&self) -> Result<LBtcSwapScriptV2> {
|
||||||
|
match self {
|
||||||
|
SwapScriptV2::Liquid(script) => Ok(script.clone()),
|
||||||
|
_ => Err(anyhow!("Invalid chain")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
pub(crate) enum SwapTxV2 {
|
||||||
|
Bitcoin(BtcSwapTxV2),
|
||||||
|
Liquid(LBtcSwapTxV2),
|
||||||
|
}
|
||||||
|
impl SwapTxV2 {
|
||||||
|
pub(crate) fn as_bitcoin_tx(&self) -> Result<BtcSwapTxV2> {
|
||||||
|
match self {
|
||||||
|
SwapTxV2::Bitcoin(tx) => Ok(tx.clone()),
|
||||||
|
_ => Err(anyhow!("Invalid chain")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_liquid_tx(&self) -> Result<LBtcSwapTxV2> {
|
||||||
|
match self {
|
||||||
|
SwapTxV2::Liquid(tx) => Ok(tx.clone()),
|
||||||
|
_ => Err(anyhow!("Invalid chain")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize)]
|
||||||
|
pub enum Direction {
|
||||||
|
Incoming = 0,
|
||||||
|
Outgoing = 1,
|
||||||
|
}
|
||||||
|
impl ToSql for Direction {
|
||||||
|
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
|
||||||
|
Ok(rusqlite::types::ToSqlOutput::from(*self as i8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromSql for Direction {
|
||||||
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||||
|
match value {
|
||||||
|
ValueRef::Integer(i) => match i as u8 {
|
||||||
|
0 => Ok(Direction::Incoming),
|
||||||
|
1 => Ok(Direction::Outgoing),
|
||||||
|
_ => Err(FromSqlError::OutOfRange(i)),
|
||||||
|
},
|
||||||
|
_ => Err(FromSqlError::InvalidType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A chain swap
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) struct ChainSwap {
|
||||||
|
pub(crate) id: String,
|
||||||
|
pub(crate) direction: Direction,
|
||||||
|
pub(crate) address: String,
|
||||||
|
pub(crate) preimage: String,
|
||||||
|
pub(crate) payer_amount_sat: u64,
|
||||||
|
pub(crate) receiver_amount_sat: u64,
|
||||||
|
pub(crate) claim_fees_sat: u64,
|
||||||
|
pub(crate) accept_zero_conf: bool,
|
||||||
|
/// JSON representation of [crate::persist::send::InternalCreateChainResponse]
|
||||||
|
pub(crate) create_response_json: String,
|
||||||
|
/// Persisted only when the server lockup tx is successfully broadcast
|
||||||
|
pub(crate) server_lockup_tx_id: Option<String>,
|
||||||
|
/// Persisted only when the user lockup tx is successfully broadcast
|
||||||
|
pub(crate) user_lockup_tx_id: Option<String>,
|
||||||
|
/// Persisted as soon as a claim tx is broadcast
|
||||||
|
pub(crate) claim_tx_id: Option<String>,
|
||||||
|
/// Persisted as soon as a refund tx is broadcast
|
||||||
|
pub(crate) refund_tx_id: Option<String>,
|
||||||
|
pub(crate) created_at: u32,
|
||||||
|
pub(crate) state: PaymentState,
|
||||||
|
pub(crate) claim_private_key: String,
|
||||||
|
pub(crate) refund_private_key: String,
|
||||||
|
}
|
||||||
|
impl ChainSwap {
|
||||||
|
pub(crate) fn get_claim_keypair(&self) -> Result<Keypair, PaymentError> {
|
||||||
|
utils::decode_keypair(&self.claim_private_key).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_refund_keypair(&self) -> Result<Keypair, PaymentError> {
|
||||||
|
utils::decode_keypair(&self.refund_private_key).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_boltz_create_response(&self) -> Result<CreateChainResponse> {
|
||||||
|
let internal_create_response: crate::persist::chain::InternalCreateChainResponse =
|
||||||
|
serde_json::from_str(&self.create_response_json).map_err(|e| {
|
||||||
|
anyhow!("Failed to deserialize InternalCreateSubmarineResponse: {e:?}")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(CreateChainResponse {
|
||||||
|
id: self.id.clone(),
|
||||||
|
claim_details: internal_create_response.claim_details,
|
||||||
|
lockup_details: internal_create_response.lockup_details,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_claim_swap_script(&self) -> Result<SwapScriptV2, PaymentError> {
|
||||||
|
let chain_swap_details = self.get_boltz_create_response()?.claim_details;
|
||||||
|
let our_pubkey = self.get_claim_keypair()?.public_key();
|
||||||
|
let swap_script = match self.direction {
|
||||||
|
Direction::Incoming => SwapScriptV2::Liquid(LBtcSwapScriptV2::chain_from_swap_resp(
|
||||||
|
Side::To,
|
||||||
|
chain_swap_details,
|
||||||
|
our_pubkey.into(),
|
||||||
|
)?),
|
||||||
|
Direction::Outgoing => SwapScriptV2::Bitcoin(BtcSwapScriptV2::chain_from_swap_resp(
|
||||||
|
Side::To,
|
||||||
|
chain_swap_details,
|
||||||
|
our_pubkey.into(),
|
||||||
|
)?),
|
||||||
|
};
|
||||||
|
Ok(swap_script)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_lockup_swap_script(&self) -> Result<SwapScriptV2, PaymentError> {
|
||||||
|
let chain_swap_details = self.get_boltz_create_response()?.lockup_details;
|
||||||
|
let our_pubkey = self.get_refund_keypair()?.public_key();
|
||||||
|
let swap_script = match self.direction {
|
||||||
|
Direction::Incoming => SwapScriptV2::Bitcoin(BtcSwapScriptV2::chain_from_swap_resp(
|
||||||
|
Side::From,
|
||||||
|
chain_swap_details,
|
||||||
|
our_pubkey.into(),
|
||||||
|
)?),
|
||||||
|
Direction::Outgoing => SwapScriptV2::Liquid(LBtcSwapScriptV2::chain_from_swap_resp(
|
||||||
|
Side::From,
|
||||||
|
chain_swap_details,
|
||||||
|
our_pubkey.into(),
|
||||||
|
)?),
|
||||||
|
};
|
||||||
|
Ok(swap_script)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_boltz_struct_to_json(
|
||||||
|
create_response: &CreateChainResponse,
|
||||||
|
expected_swap_id: &str,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let internal_create_response =
|
||||||
|
crate::persist::chain::InternalCreateChainResponse::try_convert_from_boltz(
|
||||||
|
create_response,
|
||||||
|
expected_swap_id,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let create_response_json =
|
||||||
|
serde_json::to_string(&internal_create_response).map_err(|e| {
|
||||||
|
PaymentError::Generic {
|
||||||
|
err: format!("Failed to serialize InternalCreateChainResponse: {e:?}"),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(create_response_json)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A submarine swap, used for Send
|
/// A submarine swap, used for Send
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct SendSwap {
|
pub(crate) struct SendSwap {
|
||||||
@@ -461,6 +663,14 @@ pub enum PaymentType {
|
|||||||
Receive = 0,
|
Receive = 0,
|
||||||
Send = 1,
|
Send = 1,
|
||||||
}
|
}
|
||||||
|
impl From<Direction> for PaymentType {
|
||||||
|
fn from(value: Direction) -> Self {
|
||||||
|
match value {
|
||||||
|
Direction::Incoming => Self::Receive,
|
||||||
|
Direction::Outgoing => Self::Send,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl ToSql for PaymentType {
|
impl ToSql for PaymentType {
|
||||||
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
|
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
|
||||||
Ok(rusqlite::types::ToSqlOutput::from(*self as i8))
|
Ok(rusqlite::types::ToSqlOutput::from(*self as i8))
|
||||||
@@ -533,7 +743,7 @@ pub struct PaymentSwapData {
|
|||||||
|
|
||||||
pub preimage: Option<String>,
|
pub preimage: Option<String>,
|
||||||
|
|
||||||
pub bolt11: String,
|
pub bolt11: Option<String>,
|
||||||
|
|
||||||
/// Amount sent by the swap payer
|
/// Amount sent by the swap payer
|
||||||
pub payer_amount_sat: u64,
|
pub payer_amount_sat: u64,
|
||||||
@@ -622,7 +832,7 @@ impl Payment {
|
|||||||
amount_sat,
|
amount_sat,
|
||||||
fees_sat: swap.payer_amount_sat - swap.receiver_amount_sat,
|
fees_sat: swap.payer_amount_sat - swap.receiver_amount_sat,
|
||||||
preimage: swap.preimage,
|
preimage: swap.preimage,
|
||||||
bolt11: Some(swap.bolt11),
|
bolt11: swap.bolt11,
|
||||||
refund_tx_id: swap.refund_tx_id,
|
refund_tx_id: swap.refund_tx_id,
|
||||||
refund_tx_amount_sat: swap.refund_tx_amount_sat,
|
refund_tx_amount_sat: swap.refund_tx_amount_sat,
|
||||||
payment_type,
|
payment_type,
|
||||||
@@ -647,7 +857,7 @@ impl Payment {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
preimage: swap.as_ref().and_then(|s| s.preimage.clone()),
|
preimage: swap.as_ref().and_then(|s| s.preimage.clone()),
|
||||||
bolt11: swap.as_ref().map(|s| s.bolt11.clone()),
|
bolt11: swap.as_ref().and_then(|s| s.bolt11.clone()),
|
||||||
refund_tx_id: swap.as_ref().and_then(|s| s.refund_tx_id.clone()),
|
refund_tx_id: swap.as_ref().and_then(|s| s.refund_tx_id.clone()),
|
||||||
refund_tx_amount_sat: swap.as_ref().and_then(|s| s.refund_tx_amount_sat),
|
refund_tx_amount_sat: swap.as_ref().and_then(|s| s.refund_tx_amount_sat),
|
||||||
payment_type: tx.payment_type,
|
payment_type: tx.payment_type,
|
||||||
|
|||||||
298
lib/core/src/persist/chain.rs
Normal file
298
lib/core/src/persist/chain.rs
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use boltz_client::swaps::boltzv2::{ChainSwapDetails, CreateChainResponse};
|
||||||
|
use rusqlite::{named_params, params, Connection, Row};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::ensure_sdk;
|
||||||
|
use crate::error::PaymentError;
|
||||||
|
use crate::model::*;
|
||||||
|
use crate::persist::Persister;
|
||||||
|
|
||||||
|
impl Persister {
|
||||||
|
pub(crate) fn insert_chain_swap(&self, chain_swap: &ChainSwap) -> Result<()> {
|
||||||
|
let con = self.get_connection()?;
|
||||||
|
|
||||||
|
// There is a limit of 16 param elements in a single tuple in rusqlite,
|
||||||
|
// so we split up the insert into two statements.
|
||||||
|
let mut stmt = con.prepare(
|
||||||
|
"
|
||||||
|
INSERT INTO chain_swaps (
|
||||||
|
id,
|
||||||
|
direction,
|
||||||
|
address,
|
||||||
|
preimage,
|
||||||
|
payer_amount_sat,
|
||||||
|
receiver_amount_sat,
|
||||||
|
accept_zero_conf,
|
||||||
|
create_response_json,
|
||||||
|
claim_private_key,
|
||||||
|
refund_private_key,
|
||||||
|
claim_fees_sat,
|
||||||
|
created_at,
|
||||||
|
state
|
||||||
|
)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
)?;
|
||||||
|
_ = stmt.execute((
|
||||||
|
&chain_swap.id,
|
||||||
|
&chain_swap.direction,
|
||||||
|
&chain_swap.address,
|
||||||
|
&chain_swap.preimage,
|
||||||
|
&chain_swap.payer_amount_sat,
|
||||||
|
&chain_swap.receiver_amount_sat,
|
||||||
|
&chain_swap.accept_zero_conf,
|
||||||
|
&chain_swap.create_response_json,
|
||||||
|
&chain_swap.claim_private_key,
|
||||||
|
&chain_swap.refund_private_key,
|
||||||
|
&chain_swap.claim_fees_sat,
|
||||||
|
&chain_swap.created_at,
|
||||||
|
&chain_swap.state,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
con.execute(
|
||||||
|
"UPDATE chain_swaps
|
||||||
|
SET
|
||||||
|
server_lockup_tx_id = :server_lockup_tx_id,
|
||||||
|
user_lockup_tx_id = :user_lockup_tx_id,
|
||||||
|
claim_tx_id = :claim_tx_id,
|
||||||
|
refund_tx_id = :refund_tx_id
|
||||||
|
WHERE
|
||||||
|
id = :id",
|
||||||
|
named_params! {
|
||||||
|
":id": &chain_swap.id,
|
||||||
|
":server_lockup_tx_id": &chain_swap.server_lockup_tx_id,
|
||||||
|
":user_lockup_tx_id": &chain_swap.user_lockup_tx_id,
|
||||||
|
":claim_tx_id": &chain_swap.claim_tx_id,
|
||||||
|
":refund_tx_id": &chain_swap.refund_tx_id,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_chain_swaps_query(where_clauses: Vec<String>) -> String {
|
||||||
|
let mut where_clause_str = String::new();
|
||||||
|
if !where_clauses.is_empty() {
|
||||||
|
where_clause_str = String::from("WHERE ");
|
||||||
|
where_clause_str.push_str(where_clauses.join(" AND ").as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
direction,
|
||||||
|
address,
|
||||||
|
preimage,
|
||||||
|
payer_amount_sat,
|
||||||
|
receiver_amount_sat,
|
||||||
|
accept_zero_conf,
|
||||||
|
create_response_json,
|
||||||
|
claim_private_key,
|
||||||
|
refund_private_key,
|
||||||
|
server_lockup_tx_id,
|
||||||
|
user_lockup_tx_id,
|
||||||
|
claim_fees_sat,
|
||||||
|
claim_tx_id,
|
||||||
|
refund_tx_id,
|
||||||
|
created_at,
|
||||||
|
state
|
||||||
|
FROM chain_swaps
|
||||||
|
{where_clause_str}
|
||||||
|
ORDER BY created_at
|
||||||
|
"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fetch_chain_swap_by_id(&self, id: &str) -> Result<Option<ChainSwap>> {
|
||||||
|
let con: Connection = self.get_connection()?;
|
||||||
|
let query = Self::list_chain_swaps_query(vec!["id = ?1".to_string()]);
|
||||||
|
let res = con.query_row(&query, [id], Self::sql_row_to_chain_swap);
|
||||||
|
|
||||||
|
Ok(res.ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sql_row_to_chain_swap(row: &Row) -> rusqlite::Result<ChainSwap> {
|
||||||
|
Ok(ChainSwap {
|
||||||
|
id: row.get(0)?,
|
||||||
|
direction: row.get(1)?,
|
||||||
|
address: row.get(2)?,
|
||||||
|
preimage: row.get(3)?,
|
||||||
|
payer_amount_sat: row.get(4)?,
|
||||||
|
receiver_amount_sat: row.get(5)?,
|
||||||
|
accept_zero_conf: row.get(6)?,
|
||||||
|
create_response_json: row.get(7)?,
|
||||||
|
claim_private_key: row.get(8)?,
|
||||||
|
refund_private_key: row.get(9)?,
|
||||||
|
server_lockup_tx_id: row.get(10)?,
|
||||||
|
user_lockup_tx_id: row.get(11)?,
|
||||||
|
claim_fees_sat: row.get(12)?,
|
||||||
|
claim_tx_id: row.get(13)?,
|
||||||
|
refund_tx_id: row.get(14)?,
|
||||||
|
created_at: row.get(15)?,
|
||||||
|
state: row.get(16)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn list_chain_swaps(
|
||||||
|
&self,
|
||||||
|
con: &Connection,
|
||||||
|
where_clauses: Vec<String>,
|
||||||
|
) -> rusqlite::Result<Vec<ChainSwap>> {
|
||||||
|
let query = Self::list_chain_swaps_query(where_clauses);
|
||||||
|
let chain_swaps = con
|
||||||
|
.prepare(&query)?
|
||||||
|
.query_map(params![], Self::sql_row_to_chain_swap)?
|
||||||
|
.map(|i| i.unwrap())
|
||||||
|
.collect();
|
||||||
|
Ok(chain_swaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn list_ongoing_chain_swaps(
|
||||||
|
&self,
|
||||||
|
con: &Connection,
|
||||||
|
) -> rusqlite::Result<Vec<ChainSwap>> {
|
||||||
|
let mut where_clause: Vec<String> = Vec::new();
|
||||||
|
where_clause.push(format!(
|
||||||
|
"state in ({})",
|
||||||
|
[PaymentState::Created, PaymentState::Pending]
|
||||||
|
.iter()
|
||||||
|
.map(|t| format!("'{}'", *t as i8))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
));
|
||||||
|
|
||||||
|
self.list_chain_swaps(con, where_clause)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn list_pending_chain_swaps(&self) -> Result<Vec<ChainSwap>> {
|
||||||
|
let con: Connection = self.get_connection()?;
|
||||||
|
let query = Self::list_chain_swaps_query(vec!["state = ?1".to_string()]);
|
||||||
|
let res = con
|
||||||
|
.prepare(&query)?
|
||||||
|
.query_map(params![PaymentState::Pending], Self::sql_row_to_chain_swap)?
|
||||||
|
.map(|i| i.unwrap())
|
||||||
|
.collect();
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pending Chain swaps, indexed by refund tx id
|
||||||
|
pub(crate) fn list_pending_chain_swaps_by_refund_tx_id(
|
||||||
|
&self,
|
||||||
|
) -> Result<HashMap<String, ChainSwap>> {
|
||||||
|
let res: HashMap<String, ChainSwap> = self
|
||||||
|
.list_pending_chain_swaps()?
|
||||||
|
.iter()
|
||||||
|
.filter_map(|pending_chain_swap| {
|
||||||
|
pending_chain_swap
|
||||||
|
.refund_tx_id
|
||||||
|
.as_ref()
|
||||||
|
.map(|refund_tx_id| (refund_tx_id.clone(), pending_chain_swap.clone()))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update_chain_swap_accept_zero_conf(
|
||||||
|
&self,
|
||||||
|
swap_id: &str,
|
||||||
|
accept_zero_conf: bool,
|
||||||
|
) -> Result<(), PaymentError> {
|
||||||
|
let con: Connection = self.get_connection()?;
|
||||||
|
con.execute(
|
||||||
|
"UPDATE chain_swaps
|
||||||
|
SET
|
||||||
|
accept_zero_conf = :accept_zero_conf
|
||||||
|
WHERE
|
||||||
|
id = :id",
|
||||||
|
named_params! {
|
||||||
|
":id": swap_id,
|
||||||
|
":accept_zero_conf": accept_zero_conf,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(|_| PaymentError::PersistError)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn try_handle_chain_swap_update(
|
||||||
|
&self,
|
||||||
|
swap_id: &str,
|
||||||
|
to_state: PaymentState,
|
||||||
|
server_lockup_tx_id: Option<&str>,
|
||||||
|
user_lockup_tx_id: Option<&str>,
|
||||||
|
claim_tx_id: Option<&str>,
|
||||||
|
refund_tx_id: Option<&str>,
|
||||||
|
) -> Result<(), PaymentError> {
|
||||||
|
// Do not overwrite server_lockup_tx_id, user_lockup_tx_id, claim_tx_id, refund_tx_id
|
||||||
|
let con: Connection = self.get_connection()?;
|
||||||
|
con.execute(
|
||||||
|
"UPDATE chain_swaps
|
||||||
|
SET
|
||||||
|
server_lockup_tx_id =
|
||||||
|
CASE
|
||||||
|
WHEN server_lockup_tx_id IS NULL THEN :server_lockup_tx_id
|
||||||
|
ELSE server_lockup_tx_id
|
||||||
|
END,
|
||||||
|
|
||||||
|
user_lockup_tx_id =
|
||||||
|
CASE
|
||||||
|
WHEN user_lockup_tx_id IS NULL THEN :user_lockup_tx_id
|
||||||
|
ELSE user_lockup_tx_id
|
||||||
|
END,
|
||||||
|
|
||||||
|
claim_tx_id =
|
||||||
|
CASE
|
||||||
|
WHEN claim_tx_id IS NULL THEN :claim_tx_id
|
||||||
|
ELSE claim_tx_id
|
||||||
|
END,
|
||||||
|
|
||||||
|
refund_tx_id =
|
||||||
|
CASE
|
||||||
|
WHEN refund_tx_id IS NULL THEN :refund_tx_id
|
||||||
|
ELSE refund_tx_id
|
||||||
|
END,
|
||||||
|
|
||||||
|
state = :state
|
||||||
|
WHERE
|
||||||
|
id = :id",
|
||||||
|
named_params! {
|
||||||
|
":id": swap_id,
|
||||||
|
":server_lockup_tx_id": server_lockup_tx_id,
|
||||||
|
":user_lockup_tx_id": user_lockup_tx_id,
|
||||||
|
":claim_tx_id": claim_tx_id,
|
||||||
|
":refund_tx_id": refund_tx_id,
|
||||||
|
":state": to_state,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(|_| PaymentError::PersistError)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub(crate) struct InternalCreateChainResponse {
|
||||||
|
pub(crate) claim_details: ChainSwapDetails,
|
||||||
|
pub(crate) lockup_details: ChainSwapDetails,
|
||||||
|
}
|
||||||
|
impl InternalCreateChainResponse {
|
||||||
|
pub(crate) fn try_convert_from_boltz(
|
||||||
|
boltz_create_response: &CreateChainResponse,
|
||||||
|
expected_swap_id: &str,
|
||||||
|
) -> Result<InternalCreateChainResponse, PaymentError> {
|
||||||
|
// Do not store the CreateResponse fields that are already stored separately
|
||||||
|
// Before skipping them, ensure they match the separately stored ones
|
||||||
|
ensure_sdk!(
|
||||||
|
boltz_create_response.id == expected_swap_id,
|
||||||
|
PaymentError::PersistError
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = InternalCreateChainResponse {
|
||||||
|
claim_details: boltz_create_response.claim_details.clone(),
|
||||||
|
lockup_details: boltz_create_response.lockup_details.clone(),
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,5 +35,24 @@ pub(crate) fn current_migrations() -> Vec<&'static str> {
|
|||||||
amount_sat INTEGER NOT NULL,
|
amount_sat INTEGER NOT NULL,
|
||||||
fees_sat INTEGER NOT NULL
|
fees_sat INTEGER NOT NULL
|
||||||
) STRICT;",
|
) STRICT;",
|
||||||
|
"CREATE TABLE IF NOT EXISTS chain_swaps (
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
direction INTEGER NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
preimage TEXT NOT NULL,
|
||||||
|
payer_amount_sat INTEGER NOT NULL,
|
||||||
|
receiver_amount_sat INTEGER NOT NULL,
|
||||||
|
accept_zero_conf INTEGER NOT NULL,
|
||||||
|
create_response_json TEXT NOT NULL,
|
||||||
|
claim_private_key TEXT NOT NULL,
|
||||||
|
refund_private_key TEXT NOT NULL,
|
||||||
|
server_lockup_tx_id TEXT,
|
||||||
|
user_lockup_tx_id TEXT,
|
||||||
|
claim_fees_sat INTEGER NOT NULL,
|
||||||
|
claim_tx_id TEXT,
|
||||||
|
refund_tx_id TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
state INTEGER NOT NULL
|
||||||
|
) STRICT;",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
mod backup;
|
mod backup;
|
||||||
|
pub(crate) mod chain;
|
||||||
mod migrations;
|
mod migrations;
|
||||||
pub(crate) mod receive;
|
pub(crate) mod receive;
|
||||||
pub(crate) mod send;
|
pub(crate) mod send;
|
||||||
|
|
||||||
use std::{fs::create_dir_all, path::PathBuf, str::FromStr};
|
use std::{fs::create_dir_all, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use migrations::current_migrations;
|
use migrations::current_migrations;
|
||||||
use rusqlite::{params, Connection, OptionalExtension, Row};
|
use rusqlite::{params, Connection, OptionalExtension, Row};
|
||||||
use rusqlite_migration::{Migrations, M};
|
use rusqlite_migration::{Migrations, M};
|
||||||
@@ -50,6 +51,19 @@ impl Persister {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fetch_swap_by_id(&self, id: &str) -> Result<Swap> {
|
||||||
|
match self.fetch_send_swap_by_id(id) {
|
||||||
|
Ok(Some(send_swap)) => Ok(Swap::Send(send_swap)),
|
||||||
|
_ => match self.fetch_receive_swap(id) {
|
||||||
|
Ok(Some(receive_swap)) => Ok(Swap::Receive(receive_swap)),
|
||||||
|
_ => match self.fetch_chain_swap_by_id(id) {
|
||||||
|
Ok(Some(chain_swap)) => Ok(Swap::Chain(chain_swap)),
|
||||||
|
_ => Err(anyhow!("Could not find Swap {id}")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn insert_or_update_payment(&self, ptx: PaymentTxData) -> Result<()> {
|
pub(crate) fn insert_or_update_payment(&self, ptx: PaymentTxData) -> Result<()> {
|
||||||
let mut con = self.get_connection()?;
|
let mut con = self.get_connection()?;
|
||||||
|
|
||||||
@@ -91,7 +105,17 @@ impl Persister {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Swap::Receive)
|
.map(Swap::Receive)
|
||||||
.collect();
|
.collect();
|
||||||
Ok([ongoing_send_swaps, ongoing_receive_swaps].concat())
|
let ongoing_chain_swaps: Vec<Swap> = self
|
||||||
|
.list_ongoing_chain_swaps(&con)?
|
||||||
|
.into_iter()
|
||||||
|
.map(Swap::Chain)
|
||||||
|
.collect();
|
||||||
|
Ok([
|
||||||
|
ongoing_send_swaps,
|
||||||
|
ongoing_receive_swaps,
|
||||||
|
ongoing_chain_swaps,
|
||||||
|
]
|
||||||
|
.concat())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_payment_query(&self, where_clause: Option<&str>) -> String {
|
fn select_payment_query(&self, where_clause: Option<&str>) -> String {
|
||||||
@@ -118,6 +142,14 @@ impl Persister {
|
|||||||
ss.payer_amount_sat,
|
ss.payer_amount_sat,
|
||||||
ss.receiver_amount_sat,
|
ss.receiver_amount_sat,
|
||||||
ss.state,
|
ss.state,
|
||||||
|
cs.id,
|
||||||
|
cs.created_at,
|
||||||
|
cs.direction,
|
||||||
|
cs.preimage,
|
||||||
|
cs.refund_tx_id,
|
||||||
|
cs.payer_amount_sat,
|
||||||
|
cs.receiver_amount_sat,
|
||||||
|
cs.state,
|
||||||
rtx.amount_sat
|
rtx.amount_sat
|
||||||
FROM payment_tx_data AS ptx -- Payment tx (each tx results in a Payment)
|
FROM payment_tx_data AS ptx -- Payment tx (each tx results in a Payment)
|
||||||
FULL JOIN (
|
FULL JOIN (
|
||||||
@@ -127,8 +159,10 @@ impl Persister {
|
|||||||
ON ptx.tx_id = rs.claim_tx_id
|
ON ptx.tx_id = rs.claim_tx_id
|
||||||
LEFT JOIN send_swaps AS ss -- Send Swap data
|
LEFT JOIN send_swaps AS ss -- Send Swap data
|
||||||
ON ptx.tx_id = ss.lockup_tx_id
|
ON ptx.tx_id = ss.lockup_tx_id
|
||||||
|
LEFT JOIN chain_swaps AS cs -- Chain Swap data
|
||||||
|
ON ptx.tx_id in (cs.user_lockup_tx_id, cs.claim_tx_id)
|
||||||
LEFT JOIN payment_tx_data AS rtx -- Refund tx data
|
LEFT JOIN payment_tx_data AS rtx -- Refund tx data
|
||||||
ON rtx.tx_id = ss.refund_tx_id
|
ON rtx.tx_id in (ss.refund_tx_id, cs.refund_tx_id)
|
||||||
WHERE -- Filter out refund txs from Payment tx list
|
WHERE -- Filter out refund txs from Payment tx list
|
||||||
ptx.tx_id NOT IN (SELECT refund_tx_id FROM send_swaps WHERE refund_tx_id NOT NULL)
|
ptx.tx_id NOT IN (SELECT refund_tx_id FROM send_swaps WHERE refund_tx_id NOT NULL)
|
||||||
AND {}
|
AND {}
|
||||||
@@ -166,7 +200,17 @@ impl Persister {
|
|||||||
let maybe_send_swap_payer_amount_sat: Option<u64> = row.get(17)?;
|
let maybe_send_swap_payer_amount_sat: Option<u64> = row.get(17)?;
|
||||||
let maybe_send_swap_receiver_amount_sat: Option<u64> = row.get(18)?;
|
let maybe_send_swap_receiver_amount_sat: Option<u64> = row.get(18)?;
|
||||||
let maybe_send_swap_state: Option<PaymentState> = row.get(19)?;
|
let maybe_send_swap_state: Option<PaymentState> = row.get(19)?;
|
||||||
let maybe_send_swap_refund_tx_amount_sat: Option<u64> = row.get(20)?;
|
|
||||||
|
let maybe_chain_swap_id: Option<String> = row.get(20)?;
|
||||||
|
let maybe_chain_swap_created_at: Option<u32> = row.get(21)?;
|
||||||
|
let maybe_chain_swap_direction: Option<Direction> = row.get(22)?;
|
||||||
|
let maybe_chain_swap_preimage: Option<String> = row.get(23)?;
|
||||||
|
let maybe_chain_swap_refund_tx_id: Option<String> = row.get(24)?;
|
||||||
|
let maybe_chain_swap_payer_amount_sat: Option<u64> = row.get(25)?;
|
||||||
|
let maybe_chain_swap_receiver_amount_sat: Option<u64> = row.get(26)?;
|
||||||
|
let maybe_chain_swap_state: Option<PaymentState> = row.get(27)?;
|
||||||
|
|
||||||
|
let maybe_swap_refund_tx_amount_sat: Option<u64> = row.get(28)?;
|
||||||
|
|
||||||
let (swap, payment_type) = match maybe_receive_swap_id {
|
let (swap, payment_type) = match maybe_receive_swap_id {
|
||||||
Some(receive_swap_id) => (
|
Some(receive_swap_id) => (
|
||||||
@@ -174,7 +218,7 @@ impl Persister {
|
|||||||
swap_id: receive_swap_id,
|
swap_id: receive_swap_id,
|
||||||
created_at: maybe_receive_swap_created_at.unwrap_or(utils::now()),
|
created_at: maybe_receive_swap_created_at.unwrap_or(utils::now()),
|
||||||
preimage: None,
|
preimage: None,
|
||||||
bolt11: maybe_receive_swap_invoice.unwrap_or("".to_string()),
|
bolt11: maybe_receive_swap_invoice,
|
||||||
payer_amount_sat: maybe_receive_swap_payer_amount_sat.unwrap_or(0),
|
payer_amount_sat: maybe_receive_swap_payer_amount_sat.unwrap_or(0),
|
||||||
receiver_amount_sat: maybe_receive_swap_receiver_amount_sat.unwrap_or(0),
|
receiver_amount_sat: maybe_receive_swap_receiver_amount_sat.unwrap_or(0),
|
||||||
refund_tx_id: None,
|
refund_tx_id: None,
|
||||||
@@ -183,20 +227,41 @@ impl Persister {
|
|||||||
}),
|
}),
|
||||||
PaymentType::Receive,
|
PaymentType::Receive,
|
||||||
),
|
),
|
||||||
None => (
|
None => match maybe_send_swap_id {
|
||||||
maybe_send_swap_id.map(|send_swap_id| PaymentSwapData {
|
Some(send_swap_id) => (
|
||||||
swap_id: send_swap_id,
|
Some(PaymentSwapData {
|
||||||
created_at: maybe_send_swap_created_at.unwrap_or(utils::now()),
|
swap_id: send_swap_id,
|
||||||
preimage: maybe_send_swap_preimage,
|
created_at: maybe_send_swap_created_at.unwrap_or(utils::now()),
|
||||||
bolt11: maybe_send_swap_invoice.unwrap_or("".to_string()),
|
preimage: maybe_send_swap_preimage,
|
||||||
payer_amount_sat: maybe_send_swap_payer_amount_sat.unwrap_or(0),
|
bolt11: maybe_send_swap_invoice,
|
||||||
receiver_amount_sat: maybe_send_swap_receiver_amount_sat.unwrap_or(0),
|
payer_amount_sat: maybe_send_swap_payer_amount_sat.unwrap_or(0),
|
||||||
refund_tx_id: maybe_send_swap_refund_tx_id,
|
receiver_amount_sat: maybe_send_swap_receiver_amount_sat.unwrap_or(0),
|
||||||
refund_tx_amount_sat: maybe_send_swap_refund_tx_amount_sat,
|
refund_tx_id: maybe_send_swap_refund_tx_id,
|
||||||
status: maybe_send_swap_state.unwrap_or(PaymentState::Created),
|
refund_tx_amount_sat: maybe_swap_refund_tx_amount_sat,
|
||||||
}),
|
status: maybe_send_swap_state.unwrap_or(PaymentState::Created),
|
||||||
PaymentType::Send,
|
}),
|
||||||
),
|
PaymentType::Send,
|
||||||
|
),
|
||||||
|
None => match maybe_chain_swap_id {
|
||||||
|
Some(chain_swap_id) => (
|
||||||
|
Some(PaymentSwapData {
|
||||||
|
swap_id: chain_swap_id,
|
||||||
|
created_at: maybe_chain_swap_created_at.unwrap_or(utils::now()),
|
||||||
|
preimage: maybe_chain_swap_preimage,
|
||||||
|
bolt11: None,
|
||||||
|
payer_amount_sat: maybe_chain_swap_payer_amount_sat.unwrap_or(0),
|
||||||
|
receiver_amount_sat: maybe_chain_swap_receiver_amount_sat.unwrap_or(0),
|
||||||
|
refund_tx_id: maybe_chain_swap_refund_tx_id,
|
||||||
|
refund_tx_amount_sat: maybe_swap_refund_tx_amount_sat,
|
||||||
|
status: maybe_chain_swap_state.unwrap_or(PaymentState::Created),
|
||||||
|
}),
|
||||||
|
maybe_chain_swap_direction
|
||||||
|
.unwrap_or(Direction::Outgoing)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
None => (None, PaymentType::Send),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match (tx, swap.clone()) {
|
match (tx, swap.clone()) {
|
||||||
|
|||||||
@@ -51,9 +51,8 @@ impl ReceiveSwapStateHandler {
|
|||||||
|
|
||||||
/// Handles status updates from Boltz for Receive swaps
|
/// Handles status updates from Boltz for Receive swaps
|
||||||
pub(crate) async fn on_new_status(&self, update: &boltzv2::Update) -> Result<()> {
|
pub(crate) async fn on_new_status(&self, update: &boltzv2::Update) -> Result<()> {
|
||||||
let id = update.id();
|
let id = &update.id;
|
||||||
let swap_state = update.status();
|
let swap_state = &update.status;
|
||||||
|
|
||||||
let receive_swap = self
|
let receive_swap = self
|
||||||
.persister
|
.persister
|
||||||
.fetch_receive_swap(id)?
|
.fetch_receive_swap(id)?
|
||||||
@@ -75,7 +74,7 @@ impl ReceiveSwapStateHandler {
|
|||||||
// The lockup tx is in the mempool and we accept 0-conf => try to claim
|
// The lockup tx is in the mempool and we accept 0-conf => try to claim
|
||||||
// Execute 0-conf preconditions check
|
// Execute 0-conf preconditions check
|
||||||
Ok(RevSwapStates::TransactionMempool) => {
|
Ok(RevSwapStates::TransactionMempool) => {
|
||||||
let boltzv2::Update::TransactionMempool { transaction, .. } = update else {
|
let Some(transaction) = update.transaction.clone() else {
|
||||||
return Err(anyhow!("Unexpected payload from Boltz status stream"));
|
return Err(anyhow!("Unexpected payload from Boltz status stream"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,18 +12,20 @@ use anyhow::Result;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use boltz_client::lightning_invoice::Bolt11InvoiceDescription;
|
use boltz_client::lightning_invoice::Bolt11InvoiceDescription;
|
||||||
use boltz_client::ToHex;
|
use boltz_client::ToHex;
|
||||||
use boltz_client::{swaps::boltzv2::*, util::secrets::Preimage, Amount, Bolt11Invoice};
|
use boltz_client::{swaps::boltzv2::*, util::secrets::Preimage, Bolt11Invoice};
|
||||||
use futures_util::stream::select_all;
|
use futures_util::stream::select_all;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use lwk_wollet::bitcoin::hex::DisplayHex;
|
use lwk_wollet::bitcoin::hex::DisplayHex;
|
||||||
use lwk_wollet::hashes::{sha256, Hash};
|
use lwk_wollet::hashes::{sha256, Hash};
|
||||||
use lwk_wollet::{elements::LockTime, ElementsNetwork};
|
use lwk_wollet::{elements::LockTime, ElementsNetwork};
|
||||||
use lwk_wollet::{BlockchainBackend, ElectrumClient, ElectrumUrl};
|
use lwk_wollet::{ElectrumClient, ElectrumUrl};
|
||||||
use tokio::sync::{watch, RwLock};
|
use tokio::sync::{watch, Mutex, RwLock};
|
||||||
use tokio::time::MissedTickBehavior;
|
use tokio::time::MissedTickBehavior;
|
||||||
use tokio_stream::wrappers::BroadcastStream;
|
use tokio_stream::wrappers::BroadcastStream;
|
||||||
|
|
||||||
|
use crate::chain::ChainService;
|
||||||
|
use crate::chain_swap::ChainSwapStateHandler;
|
||||||
use crate::error::LiquidSdkError;
|
use crate::error::LiquidSdkError;
|
||||||
use crate::model::PaymentState::*;
|
use crate::model::PaymentState::*;
|
||||||
use crate::receive_swap::ReceiveSwapStateHandler;
|
use crate::receive_swap::ReceiveSwapStateHandler;
|
||||||
@@ -42,9 +44,6 @@ use crate::{
|
|||||||
|
|
||||||
pub const DEFAULT_DATA_DIR: &str = ".data";
|
pub const DEFAULT_DATA_DIR: &str = ".data";
|
||||||
|
|
||||||
pub(crate) trait ChainService: Send + Sync + BlockchainBackend {}
|
|
||||||
impl ChainService for ElectrumClient {}
|
|
||||||
|
|
||||||
pub struct LiquidSdk {
|
pub struct LiquidSdk {
|
||||||
config: Config,
|
config: Config,
|
||||||
onchain_wallet: Arc<dyn OnchainWallet>,
|
onchain_wallet: Arc<dyn OnchainWallet>,
|
||||||
@@ -52,11 +51,13 @@ pub struct LiquidSdk {
|
|||||||
event_manager: Arc<EventManager>,
|
event_manager: Arc<EventManager>,
|
||||||
status_stream: Arc<dyn SwapperStatusStream>,
|
status_stream: Arc<dyn SwapperStatusStream>,
|
||||||
swapper: Arc<dyn Swapper>,
|
swapper: Arc<dyn Swapper>,
|
||||||
|
chain_service: Arc<Mutex<dyn ChainService>>,
|
||||||
is_started: RwLock<bool>,
|
is_started: RwLock<bool>,
|
||||||
shutdown_sender: watch::Sender<()>,
|
shutdown_sender: watch::Sender<()>,
|
||||||
shutdown_receiver: watch::Receiver<()>,
|
shutdown_receiver: watch::Receiver<()>,
|
||||||
send_swap_state_handler: SendSwapStateHandler,
|
send_swap_state_handler: SendSwapStateHandler,
|
||||||
receive_swap_state_handler: ReceiveSwapStateHandler,
|
receive_swap_state_handler: ReceiveSwapStateHandler,
|
||||||
|
chain_swap_state_handler: ChainSwapStateHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiquidSdk {
|
impl LiquidSdk {
|
||||||
@@ -80,11 +81,11 @@ impl LiquidSdk {
|
|||||||
let swapper = Arc::new(BoltzSwapper::new(config.clone()));
|
let swapper = Arc::new(BoltzSwapper::new(config.clone()));
|
||||||
let status_stream = Arc::<dyn SwapperStatusStream>::from(swapper.create_status_stream());
|
let status_stream = Arc::<dyn SwapperStatusStream>::from(swapper.create_status_stream());
|
||||||
|
|
||||||
let chain_service = Arc::new(ElectrumClient::new(&ElectrumUrl::new(
|
let chain_service = Arc::new(Mutex::new(ElectrumClient::new(&ElectrumUrl::new(
|
||||||
&config.electrum_url,
|
&config.liquid_electrum_url,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
))?);
|
))?));
|
||||||
|
|
||||||
let onchain_wallet = Arc::new(LiquidOnchainWallet::new(mnemonic, config.clone())?);
|
let onchain_wallet = Arc::new(LiquidOnchainWallet::new(mnemonic, config.clone())?);
|
||||||
|
|
||||||
@@ -103,6 +104,14 @@ impl LiquidSdk {
|
|||||||
swapper.clone(),
|
swapper.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let chain_swap_state_handler = ChainSwapStateHandler::new(
|
||||||
|
config.clone(),
|
||||||
|
onchain_wallet.clone(),
|
||||||
|
persister.clone(),
|
||||||
|
swapper.clone(),
|
||||||
|
chain_service.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let sdk = Arc::new(LiquidSdk {
|
let sdk = Arc::new(LiquidSdk {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
onchain_wallet,
|
onchain_wallet,
|
||||||
@@ -110,11 +119,13 @@ impl LiquidSdk {
|
|||||||
event_manager,
|
event_manager,
|
||||||
status_stream: status_stream.clone(),
|
status_stream: status_stream.clone(),
|
||||||
swapper,
|
swapper,
|
||||||
|
chain_service,
|
||||||
is_started: RwLock::new(false),
|
is_started: RwLock::new(false),
|
||||||
shutdown_sender,
|
shutdown_sender,
|
||||||
shutdown_receiver,
|
shutdown_receiver,
|
||||||
send_swap_state_handler,
|
send_swap_state_handler,
|
||||||
receive_swap_state_handler,
|
receive_swap_state_handler,
|
||||||
|
chain_swap_state_handler,
|
||||||
});
|
});
|
||||||
Ok(sdk)
|
Ok(sdk)
|
||||||
}
|
}
|
||||||
@@ -202,6 +213,7 @@ impl LiquidSdk {
|
|||||||
cloned
|
cloned
|
||||||
.receive_swap_state_handler
|
.receive_swap_state_handler
|
||||||
.subscribe_payment_updates(),
|
.subscribe_payment_updates(),
|
||||||
|
cloned.chain_swap_state_handler.subscribe_payment_updates(),
|
||||||
];
|
];
|
||||||
let mut combined_swap_streams =
|
let mut combined_swap_streams =
|
||||||
select_all(swaps_streams.into_iter().map(BroadcastStream::new));
|
select_all(swaps_streams.into_iter().map(BroadcastStream::new));
|
||||||
@@ -222,26 +234,22 @@ impl LiquidSdk {
|
|||||||
update = updates_stream.recv() => match update {
|
update = updates_stream.recv() => match update {
|
||||||
Ok(update) => {
|
Ok(update) => {
|
||||||
let _ = cloned.sync().await;
|
let _ = cloned.sync().await;
|
||||||
let id = update.id();
|
let id = &update.id;
|
||||||
match cloned.persister.fetch_send_swap_by_id(id) {
|
match cloned.persister.fetch_swap_by_id(id) {
|
||||||
Ok(Some(_)) => {
|
Ok(Swap::Send(_)) => match cloned.send_swap_state_handler.on_new_status(&update).await {
|
||||||
match cloned.send_swap_state_handler.on_new_status(&update).await {
|
Ok(_) => info!("Successfully handled Send Swap {id} update"),
|
||||||
Ok(_) => info!("Successfully handled Send Swap {id} update"),
|
Err(e) => error!("Failed to handle Send Swap {id} update: {e}")
|
||||||
Err(e) => error!("Failed to handle Send Swap {id} update: {e}")
|
},
|
||||||
}
|
Ok(Swap::Receive(_)) => match cloned.receive_swap_state_handler.on_new_status(&update).await {
|
||||||
}
|
Ok(_) => info!("Successfully handled Receive Swap {id} update"),
|
||||||
|
Err(e) => error!("Failed to handle Receive Swap {id} update: {e}")
|
||||||
|
},
|
||||||
|
Ok(Swap::Chain(_)) => match cloned.chain_swap_state_handler.on_new_status(&update).await {
|
||||||
|
Ok(_) => info!("Successfully handled Chain Swap {id} update"),
|
||||||
|
Err(e) => error!("Failed to handle Chain Swap {id} update: {e}")
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
match cloned.persister.fetch_receive_swap(id) {
|
error!("Could not find Swap {id}");
|
||||||
Ok(Some(_)) => {
|
|
||||||
match cloned.receive_swap_state_handler.on_new_status(&update).await {
|
|
||||||
Ok(_) => info!("Successfully handled Receive Swap {id} update"),
|
|
||||||
Err(e) => error!("Failed to handle Receive Swap {id} update: {e}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
error!("Could not find Swap {id}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,6 +283,16 @@ impl LiquidSdk {
|
|||||||
}
|
}
|
||||||
Err(e) => error!("Error listing pending send swaps: {e:?}"),
|
Err(e) => error!("Error listing pending send swaps: {e:?}"),
|
||||||
}
|
}
|
||||||
|
match cloned.persister.list_pending_chain_swaps() {
|
||||||
|
Ok(pending_chain_swaps) => {
|
||||||
|
for swap in pending_chain_swaps {
|
||||||
|
if let Err(e) = cloned.check_chain_swap_expiration(&swap).await {
|
||||||
|
error!("Error checking expiration for Send Swap {}: {e:?}", swap.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => error!("Error listing pending send swaps: {e:?}"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ = shutdown_receiver.changed() => {
|
_ = shutdown_receiver.changed() => {
|
||||||
info!("Received shutdown signal, exiting refundable swaps loop");
|
info!("Received shutdown signal, exiting refundable swaps loop");
|
||||||
@@ -285,16 +303,46 @@ impl LiquidSdk {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_chain_swap_expiration(&self, chain_swap: &ChainSwap) -> Result<()> {
|
||||||
|
if chain_swap.user_lockup_tx_id.is_some() && chain_swap.refund_tx_id.is_none() {
|
||||||
|
match chain_swap.direction {
|
||||||
|
Direction::Outgoing => {
|
||||||
|
let swap_script = chain_swap.get_lockup_swap_script()?.as_liquid_script()?;
|
||||||
|
let current_height = self.chain_service.lock().await.tip()?.height;
|
||||||
|
let locktime_from_height = LockTime::from_height(current_height)?;
|
||||||
|
|
||||||
|
info!("Checking Chain Swap {} expiration: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", chain_swap.id, swap_script.locktime);
|
||||||
|
if utils::is_locktime_expired(locktime_from_height, swap_script.locktime) {
|
||||||
|
let id = &chain_swap.id;
|
||||||
|
let refund_tx_id = self.refund_chain(chain_swap).await?;
|
||||||
|
info!("Broadcast refund tx for Chain Swap {id}. Tx id: {refund_tx_id}");
|
||||||
|
self.chain_swap_state_handler
|
||||||
|
.update_swap_info(id, Pending, None, None, None, Some(&refund_tx_id))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// TODO: Set the chain swap to refundable when it expires
|
||||||
|
info!(
|
||||||
|
"Not checking receive Chain Swap {} expiration",
|
||||||
|
chain_swap.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn check_send_swap_expiration(&self, send_swap: &SendSwap) -> Result<()> {
|
async fn check_send_swap_expiration(&self, send_swap: &SendSwap) -> Result<()> {
|
||||||
if send_swap.lockup_tx_id.is_some() && send_swap.refund_tx_id.is_none() {
|
if send_swap.lockup_tx_id.is_some() && send_swap.refund_tx_id.is_none() {
|
||||||
let swap_script = send_swap.get_swap_script()?;
|
let swap_script = send_swap.get_swap_script()?;
|
||||||
let current_height = self.onchain_wallet.tip().await.height();
|
let current_height = self.chain_service.lock().await.tip()?.height;
|
||||||
let locktime_from_height = LockTime::from_height(current_height)?;
|
let locktime_from_height = LockTime::from_height(current_height)?;
|
||||||
|
|
||||||
info!("Checking Send Swap {} expiration: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", send_swap.id, swap_script.locktime);
|
info!("Checking Send Swap {} expiration: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", send_swap.id, swap_script.locktime);
|
||||||
if utils::is_locktime_expired(locktime_from_height, swap_script.locktime) {
|
if utils::is_locktime_expired(locktime_from_height, swap_script.locktime) {
|
||||||
let id = &send_swap.id;
|
let id = &send_swap.id;
|
||||||
let refund_tx_id = self.try_refund(send_swap).await?;
|
let refund_tx_id = self.refund_send(send_swap).await?;
|
||||||
info!("Broadcast refund tx for Send Swap {id}. Tx id: {refund_tx_id}");
|
info!("Broadcast refund tx for Send Swap {id}. Tx id: {refund_tx_id}");
|
||||||
self.send_swap_state_handler
|
self.send_swap_state_handler
|
||||||
.update_swap_info(id, Pending, None, None, Some(&refund_tx_id))
|
.update_swap_info(id, Pending, None, None, Some(&refund_tx_id))
|
||||||
@@ -335,55 +383,50 @@ impl LiquidSdk {
|
|||||||
Pending => {
|
Pending => {
|
||||||
// The swap state has changed to Pending
|
// The swap state has changed to Pending
|
||||||
match payment.swap_id.clone() {
|
match payment.swap_id.clone() {
|
||||||
Some(swap_id) => match payment.payment_type {
|
Some(swap_id) => match self.persister.fetch_swap_by_id(&swap_id)? {
|
||||||
PaymentType::Receive => {
|
Swap::Chain(ChainSwap { claim_tx_id, .. })
|
||||||
match self.persister.fetch_receive_swap(&swap_id)? {
|
| Swap::Receive(ReceiveSwap { claim_tx_id, .. }) => {
|
||||||
Some(swap) => match swap.claim_tx_id {
|
match claim_tx_id {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// The claim tx has now been broadcast
|
// The claim tx has now been broadcast
|
||||||
self.notify_event_listeners(
|
self.notify_event_listeners(
|
||||||
LiquidSdkEvent::PaymentWaitingConfirmation {
|
LiquidSdkEvent::PaymentWaitingConfirmation {
|
||||||
details: payment,
|
details: payment,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// The lockup tx is in the mempool/confirmed
|
// The lockup tx is in the mempool/confirmed
|
||||||
self.notify_event_listeners(
|
self.notify_event_listeners(
|
||||||
LiquidSdkEvent::PaymentPending {
|
LiquidSdkEvent::PaymentPending {
|
||||||
details: payment,
|
details: payment,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
},
|
|
||||||
None => debug!("Swap not found: {swap_id}"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PaymentType::Send => {
|
Swap::Send(SendSwap { refund_tx_id, .. }) => {
|
||||||
match self.persister.fetch_send_swap_by_id(&swap_id)? {
|
match refund_tx_id {
|
||||||
Some(swap) => match swap.refund_tx_id {
|
Some(_) => {
|
||||||
Some(_) => {
|
// The refund tx has now been broadcast
|
||||||
// The refund tx has now been broadcast
|
self.notify_event_listeners(
|
||||||
self.notify_event_listeners(
|
LiquidSdkEvent::PaymentRefundPending {
|
||||||
LiquidSdkEvent::PaymentRefundPending {
|
details: payment,
|
||||||
details: payment,
|
},
|
||||||
},
|
)
|
||||||
)
|
.await?
|
||||||
.await?
|
}
|
||||||
}
|
None => {
|
||||||
None => {
|
// The lockup tx is in the mempool/confirmed
|
||||||
// The lockup tx is in the mempool/confirmed
|
self.notify_event_listeners(
|
||||||
self.notify_event_listeners(
|
LiquidSdkEvent::PaymentPending {
|
||||||
LiquidSdkEvent::PaymentPending {
|
details: payment,
|
||||||
details: payment,
|
},
|
||||||
},
|
)
|
||||||
)
|
.await?
|
||||||
.await?
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
None => debug!("Swap not found: {swap_id}"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -508,6 +551,25 @@ impl LiquidSdk {
|
|||||||
Ok(lbtc_pair)
|
Ok(lbtc_pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_chain_pairs(
|
||||||
|
&self,
|
||||||
|
direction: Direction,
|
||||||
|
amount_sat: u64,
|
||||||
|
) -> Result<ChainPair, PaymentError> {
|
||||||
|
let pair = self
|
||||||
|
.swapper
|
||||||
|
.get_chain_pairs(direction)?
|
||||||
|
.ok_or(PaymentError::PairsNotFound)?;
|
||||||
|
|
||||||
|
pair.limits.within(amount_sat)?;
|
||||||
|
|
||||||
|
let fees_sat = pair.fees.total(amount_sat);
|
||||||
|
|
||||||
|
ensure_sdk!(amount_sat > fees_sat, PaymentError::AmountOutOfRange);
|
||||||
|
|
||||||
|
Ok(pair)
|
||||||
|
}
|
||||||
|
|
||||||
/// Estimate the onchain fee for sending the given amount to the given destination address
|
/// Estimate the onchain fee for sending the given amount to the given destination address
|
||||||
async fn estimate_onchain_tx_fee(&self, amount_sat: u64, address: &str) -> Result<u64> {
|
async fn estimate_onchain_tx_fee(&self, amount_sat: u64, address: &str) -> Result<u64> {
|
||||||
Ok(self
|
Ok(self
|
||||||
@@ -563,10 +625,10 @@ impl LiquidSdk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_refund_non_cooperative(
|
async fn refund_send_non_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
) -> Result<String, PaymentError> {
|
) -> Result<String, PaymentError> {
|
||||||
info!(
|
info!(
|
||||||
"Initiating non-cooperative refund for Send Swap {}",
|
"Initiating non-cooperative refund for Send Swap {}",
|
||||||
@@ -589,13 +651,56 @@ impl LiquidSdk {
|
|||||||
Ok(refund_tx_id)
|
Ok(refund_tx_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_refund(&self, swap: &SendSwap) -> Result<String, PaymentError> {
|
async fn refund_chain_non_cooperative(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
info!(
|
||||||
|
"Initiating non-cooperative refund for Chain Swap {}",
|
||||||
|
&swap.id
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_height = self.onchain_wallet.tip().await.height();
|
||||||
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
let refund_tx_id = self.swapper.refund_chain_swap_non_cooperative(
|
||||||
|
swap,
|
||||||
|
broadcast_fees_sat,
|
||||||
|
&output_address,
|
||||||
|
current_height,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Successfully broadcast non-cooperative refund for Chain Swap {}, tx: {}",
|
||||||
|
swap.id, refund_tx_id
|
||||||
|
);
|
||||||
|
Ok(refund_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refund_chain(&self, swap: &ChainSwap) -> Result<String, PaymentError> {
|
||||||
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
let refund_tx_fees_sat = self
|
||||||
|
.estimate_onchain_tx_fee(swap.receiver_amount_sat, &output_address)
|
||||||
|
.await?;
|
||||||
|
let refund_res =
|
||||||
|
self.swapper
|
||||||
|
.refund_chain_swap_cooperative(swap, &output_address, refund_tx_fees_sat);
|
||||||
|
match refund_res {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Cooperative refund failed: {:?}", e);
|
||||||
|
self.refund_chain_non_cooperative(swap, refund_tx_fees_sat)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refund_send(&self, swap: &SendSwap) -> Result<String, PaymentError> {
|
||||||
let amount_sat = get_invoice_amount!(swap.invoice);
|
let amount_sat = get_invoice_amount!(swap.invoice);
|
||||||
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
let refund_tx_fees_sat = Amount::from_sat(
|
let refund_tx_fees_sat = self
|
||||||
self.estimate_onchain_tx_fee(amount_sat, &output_address)
|
.estimate_onchain_tx_fee(amount_sat, &output_address)
|
||||||
.await?,
|
.await?;
|
||||||
);
|
|
||||||
let refund_res =
|
let refund_res =
|
||||||
self.swapper
|
self.swapper
|
||||||
.refund_send_swap_cooperative(swap, &output_address, refund_tx_fees_sat);
|
.refund_send_swap_cooperative(swap, &output_address, refund_tx_fees_sat);
|
||||||
@@ -603,7 +708,7 @@ impl LiquidSdk {
|
|||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Cooperative refund failed: {:?}", e);
|
warn!("Cooperative refund failed: {:?}", e);
|
||||||
self.try_refund_non_cooperative(swap, refund_tx_fees_sat)
|
self.refund_send_non_cooperative(swap, refund_tx_fees_sat)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -751,22 +856,120 @@ impl LiquidSdk {
|
|||||||
self.status_stream.track_swap_id(&swap.id)?;
|
self.status_stream.track_swap_id(&swap.id)?;
|
||||||
|
|
||||||
let accept_zero_conf = swap.get_boltz_create_response()?.accept_zero_conf;
|
let accept_zero_conf = swap.get_boltz_create_response()?.accept_zero_conf;
|
||||||
self.wait_for_payment(swap.id, accept_zero_conf)
|
self.wait_for_payment(Swap::Send(swap), accept_zero_conf)
|
||||||
|
.await
|
||||||
|
.map(|payment| SendPaymentResponse { payment })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn prepare_pay_onchain(
|
||||||
|
&self,
|
||||||
|
req: &PreparePayOnchainRequest,
|
||||||
|
) -> Result<PreparePayOnchainResponse, PaymentError> {
|
||||||
|
self.ensure_is_started().await?;
|
||||||
|
|
||||||
|
let amount_sat = req.amount_sat;
|
||||||
|
let pair = self.validate_chain_pairs(Direction::Outgoing, amount_sat)?;
|
||||||
|
let claim_fees_sat = pair.fees.claim_estimate();
|
||||||
|
let server_lockup_amount_sat = amount_sat + claim_fees_sat;
|
||||||
|
let lockup_fees_sat = self
|
||||||
|
.estimate_lockup_tx_fee(server_lockup_amount_sat)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(PreparePayOnchainResponse {
|
||||||
|
amount_sat,
|
||||||
|
fees_sat: pair.fees.boltz(amount_sat) + lockup_fees_sat + claim_fees_sat,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pay_onchain(
|
||||||
|
&self,
|
||||||
|
req: &PayOnchainRequest,
|
||||||
|
) -> Result<SendPaymentResponse, PaymentError> {
|
||||||
|
self.ensure_is_started().await?;
|
||||||
|
|
||||||
|
let receiver_amount_sat = req.prepare_res.amount_sat;
|
||||||
|
let pair = self.validate_chain_pairs(Direction::Outgoing, receiver_amount_sat)?;
|
||||||
|
let claim_fees_sat = pair.fees.claim_estimate();
|
||||||
|
let server_lockup_amount_sat = receiver_amount_sat + claim_fees_sat;
|
||||||
|
let lockup_fees_sat = self
|
||||||
|
.estimate_lockup_tx_fee(server_lockup_amount_sat)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
ensure_sdk!(
|
||||||
|
req.prepare_res.fees_sat
|
||||||
|
== pair.fees.boltz(receiver_amount_sat) + lockup_fees_sat + claim_fees_sat,
|
||||||
|
PaymentError::InvalidOrExpiredFees
|
||||||
|
);
|
||||||
|
|
||||||
|
let preimage = Preimage::new();
|
||||||
|
let preimage_str = preimage.to_string().ok_or(PaymentError::InvalidPreimage)?;
|
||||||
|
|
||||||
|
let claim_keypair = utils::generate_keypair();
|
||||||
|
let claim_public_key = boltz_client::PublicKey {
|
||||||
|
compressed: true,
|
||||||
|
inner: claim_keypair.public_key(),
|
||||||
|
};
|
||||||
|
let refund_keypair = utils::generate_keypair();
|
||||||
|
let refund_public_key = boltz_client::PublicKey {
|
||||||
|
compressed: true,
|
||||||
|
inner: refund_keypair.public_key(),
|
||||||
|
};
|
||||||
|
let create_response = self.swapper.create_chain_swap(CreateChainRequest {
|
||||||
|
from: "L-BTC".to_string(),
|
||||||
|
to: "BTC".to_string(),
|
||||||
|
preimage_hash: preimage.sha256,
|
||||||
|
claim_public_key: Some(claim_public_key),
|
||||||
|
refund_public_key: Some(refund_public_key),
|
||||||
|
user_lock_amount: None,
|
||||||
|
server_lock_amount: Some(server_lockup_amount_sat as u32), // TODO update our model
|
||||||
|
pair_hash: Some(pair.hash),
|
||||||
|
referral_id: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let swap_id = &create_response.id;
|
||||||
|
let create_response_json = ChainSwap::from_boltz_struct_to_json(&create_response, swap_id)?;
|
||||||
|
|
||||||
|
let accept_zero_conf = server_lockup_amount_sat <= pair.limits.maximal_zero_conf;
|
||||||
|
let payer_amount_sat = req.prepare_res.fees_sat + receiver_amount_sat;
|
||||||
|
|
||||||
|
let swap = ChainSwap {
|
||||||
|
id: swap_id.clone(),
|
||||||
|
direction: Direction::Outgoing,
|
||||||
|
address: req.address.clone(),
|
||||||
|
preimage: preimage_str,
|
||||||
|
payer_amount_sat,
|
||||||
|
receiver_amount_sat,
|
||||||
|
claim_fees_sat,
|
||||||
|
accept_zero_conf,
|
||||||
|
create_response_json,
|
||||||
|
claim_private_key: claim_keypair.display_secret().to_string(),
|
||||||
|
refund_private_key: refund_keypair.display_secret().to_string(),
|
||||||
|
server_lockup_tx_id: None,
|
||||||
|
user_lockup_tx_id: None,
|
||||||
|
claim_tx_id: None,
|
||||||
|
refund_tx_id: None,
|
||||||
|
created_at: utils::now(),
|
||||||
|
state: PaymentState::Created,
|
||||||
|
};
|
||||||
|
self.persister.insert_chain_swap(&swap)?;
|
||||||
|
self.status_stream.track_swap_id(&swap.id)?;
|
||||||
|
|
||||||
|
self.wait_for_payment(Swap::Chain(swap), accept_zero_conf)
|
||||||
.await
|
.await
|
||||||
.map(|payment| SendPaymentResponse { payment })
|
.map(|payment| SendPaymentResponse { payment })
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_payment(
|
async fn wait_for_payment(
|
||||||
&self,
|
&self,
|
||||||
swap_id: String,
|
swap: Swap,
|
||||||
accept_zero_conf: bool,
|
accept_zero_conf: bool,
|
||||||
) -> Result<Payment, PaymentError> {
|
) -> Result<Payment, PaymentError> {
|
||||||
let timeout_fut = tokio::time::sleep(Duration::from_secs(self.config.payment_timeout_sec));
|
let timeout_fut = tokio::time::sleep(Duration::from_secs(self.config.payment_timeout_sec));
|
||||||
tokio::pin!(timeout_fut);
|
tokio::pin!(timeout_fut);
|
||||||
|
|
||||||
|
let swap_id = swap.id();
|
||||||
let mut events_stream = self.event_manager.subscribe();
|
let mut events_stream = self.event_manager.subscribe();
|
||||||
let mut maybe_payment: Option<Payment> = None;
|
let mut maybe_payment: Option<Payment> = None;
|
||||||
let send_swap_state_handler = self.send_swap_state_handler.clone();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@@ -774,7 +977,11 @@ impl LiquidSdk {
|
|||||||
Some(payment) => return Ok(payment),
|
Some(payment) => return Ok(payment),
|
||||||
None => {
|
None => {
|
||||||
debug!("Timeout occured without payment, set swap to timed out");
|
debug!("Timeout occured without payment, set swap to timed out");
|
||||||
send_swap_state_handler.update_swap_info(&swap_id, TimedOut, None, None, None).await?;
|
match swap {
|
||||||
|
Swap::Send(_) => self.send_swap_state_handler.update_swap_info(&swap_id, TimedOut, None, None, None).await?,
|
||||||
|
Swap::Chain(_) => self.chain_swap_state_handler.update_swap_info(&swap_id, TimedOut, None, None, None, None).await?,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
return Err(PaymentError::PaymentTimeout)
|
return Err(PaymentError::PaymentTimeout)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -968,6 +1175,8 @@ impl LiquidSdk {
|
|||||||
self.persister.list_pending_receive_swaps_by_claim_tx_id()?;
|
self.persister.list_pending_receive_swaps_by_claim_tx_id()?;
|
||||||
let pending_send_swaps_by_refund_tx_id =
|
let pending_send_swaps_by_refund_tx_id =
|
||||||
self.persister.list_pending_send_swaps_by_refund_tx_id()?;
|
self.persister.list_pending_send_swaps_by_refund_tx_id()?;
|
||||||
|
let pending_chain_swaps_by_refund_tx_id =
|
||||||
|
self.persister.list_pending_chain_swaps_by_refund_tx_id()?;
|
||||||
|
|
||||||
for tx in self.onchain_wallet.transactions().await? {
|
for tx in self.onchain_wallet.transactions().await? {
|
||||||
let tx_id = tx.txid.to_string();
|
let tx_id = tx.txid.to_string();
|
||||||
@@ -998,6 +1207,12 @@ impl LiquidSdk {
|
|||||||
.update_swap_info(&swap.id, Failed, None, None, None)
|
.update_swap_info(&swap.id, Failed, None, None, None)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
} else if let Some(swap) = pending_chain_swaps_by_refund_tx_id.get(&tx_id) {
|
||||||
|
if is_tx_confirmed {
|
||||||
|
self.chain_swap_state_handler
|
||||||
|
.update_swap_info(&swap.id, Failed, None, None, None, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Payments that are not directly associated with a swap (e.g. direct onchain payments using MRH)
|
// Payments that are not directly associated with a swap (e.g. direct onchain payments using MRH)
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ use anyhow::{anyhow, Result};
|
|||||||
use boltz_client::swaps::boltzv2;
|
use boltz_client::swaps::boltzv2;
|
||||||
use boltz_client::swaps::{boltz::SubSwapStates, boltzv2::CreateSubmarineResponse};
|
use boltz_client::swaps::{boltz::SubSwapStates, boltzv2::CreateSubmarineResponse};
|
||||||
use boltz_client::util::secrets::Preimage;
|
use boltz_client::util::secrets::Preimage;
|
||||||
use boltz_client::{Amount, Bolt11Invoice, ToHex};
|
use boltz_client::{Bolt11Invoice, ToHex};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use lwk_wollet::bitcoin::Witness;
|
use lwk_wollet::bitcoin::Witness;
|
||||||
use lwk_wollet::elements::Transaction;
|
use lwk_wollet::elements::Transaction;
|
||||||
use lwk_wollet::hashes::{sha256, Hash};
|
use lwk_wollet::hashes::{sha256, Hash};
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::{broadcast, Mutex};
|
||||||
|
|
||||||
|
use crate::chain::ChainService;
|
||||||
use crate::model::PaymentState::{Complete, Created, Failed, Pending, TimedOut};
|
use crate::model::PaymentState::{Complete, Created, Failed, Pending, TimedOut};
|
||||||
use crate::model::{Config, SendSwap};
|
use crate::model::{Config, SendSwap};
|
||||||
use crate::sdk::ChainService;
|
|
||||||
use crate::swapper::Swapper;
|
use crate::swapper::Swapper;
|
||||||
use crate::wallet::OnchainWallet;
|
use crate::wallet::OnchainWallet;
|
||||||
use crate::{ensure_sdk, get_invoice_amount};
|
use crate::{ensure_sdk, get_invoice_amount};
|
||||||
@@ -28,7 +28,7 @@ pub(crate) struct SendSwapStateHandler {
|
|||||||
onchain_wallet: Arc<dyn OnchainWallet>,
|
onchain_wallet: Arc<dyn OnchainWallet>,
|
||||||
persister: Arc<Persister>,
|
persister: Arc<Persister>,
|
||||||
swapper: Arc<dyn Swapper>,
|
swapper: Arc<dyn Swapper>,
|
||||||
chain_service: Arc<dyn ChainService>,
|
chain_service: Arc<Mutex<dyn ChainService>>,
|
||||||
subscription_notifier: broadcast::Sender<String>,
|
subscription_notifier: broadcast::Sender<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ impl SendSwapStateHandler {
|
|||||||
onchain_wallet: Arc<dyn OnchainWallet>,
|
onchain_wallet: Arc<dyn OnchainWallet>,
|
||||||
persister: Arc<Persister>,
|
persister: Arc<Persister>,
|
||||||
swapper: Arc<dyn Swapper>,
|
swapper: Arc<dyn Swapper>,
|
||||||
chain_service: Arc<dyn ChainService>,
|
chain_service: Arc<Mutex<dyn ChainService>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (subscription_notifier, _) = broadcast::channel::<String>(30);
|
let (subscription_notifier, _) = broadcast::channel::<String>(30);
|
||||||
Self {
|
Self {
|
||||||
@@ -57,8 +57,8 @@ impl SendSwapStateHandler {
|
|||||||
|
|
||||||
/// Handles status updates from Boltz for Send swaps
|
/// Handles status updates from Boltz for Send swaps
|
||||||
pub(crate) async fn on_new_status(&self, update: &boltzv2::Update) -> Result<()> {
|
pub(crate) async fn on_new_status(&self, update: &boltzv2::Update) -> Result<()> {
|
||||||
let id = update.id();
|
let id = &update.id;
|
||||||
let swap_state = update.status();
|
let swap_state = &update.status;
|
||||||
let swap = self
|
let swap = self
|
||||||
.persister
|
.persister
|
||||||
.fetch_send_swap_by_id(id)?
|
.fetch_send_swap_by_id(id)?
|
||||||
@@ -124,7 +124,9 @@ impl SendSwapStateHandler {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("The claim tx was a script path spend (non-cooperative claim)");
|
debug!("The claim tx was a script path spend (non-cooperative claim)");
|
||||||
let preimage = self.get_preimage_from_script_path_claim_spend(&swap)?;
|
let preimage = self
|
||||||
|
.get_preimage_from_script_path_claim_spend(&swap)
|
||||||
|
.await?;
|
||||||
self.validate_send_swap_preimage(id, &swap.invoice, &preimage)
|
self.validate_send_swap_preimage(id, &swap.invoice, &preimage)
|
||||||
.await?;
|
.await?;
|
||||||
self.update_swap_info(id, Complete, Some(&preimage), None, None)
|
self.update_swap_info(id, Complete, Some(&preimage), None, None)
|
||||||
@@ -200,7 +202,12 @@ impl SendSwapStateHandler {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let lockup_tx_id = self.chain_service.broadcast(&lockup_tx)?.to_string();
|
let lockup_tx_id = self
|
||||||
|
.chain_service
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.broadcast(&lockup_tx)?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
debug!("Successfully broadcast lockup tx for Send Swap {swap_id}. Lockup tx id: {lockup_tx_id}");
|
debug!("Successfully broadcast lockup tx for Send Swap {swap_id}. Lockup tx id: {lockup_tx_id}");
|
||||||
Ok(lockup_tx)
|
Ok(lockup_tx)
|
||||||
@@ -246,7 +253,7 @@ impl SendSwapStateHandler {
|
|||||||
&send_swap.id
|
&send_swap.id
|
||||||
);
|
);
|
||||||
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
let output_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
let claim_tx_details = self.swapper.get_claim_tx_details(send_swap)?;
|
let claim_tx_details = self.swapper.get_send_claim_tx_details(send_swap)?;
|
||||||
self.update_swap_info(
|
self.update_swap_info(
|
||||||
&send_swap.id,
|
&send_swap.id,
|
||||||
Complete,
|
Complete,
|
||||||
@@ -260,7 +267,7 @@ impl SendSwapStateHandler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_preimage_from_script_path_claim_spend(
|
async fn get_preimage_from_script_path_claim_spend(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
) -> Result<String, PaymentError> {
|
) -> Result<String, PaymentError> {
|
||||||
@@ -276,6 +283,8 @@ impl SendSwapStateHandler {
|
|||||||
// Get tx history of the swap script (lockup address)
|
// Get tx history of the swap script (lockup address)
|
||||||
let history: Vec<_> = self
|
let history: Vec<_> = self
|
||||||
.chain_service
|
.chain_service
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
.get_scripts_history(&[&swap_script_pk])?
|
.get_scripts_history(&[&swap_script_pk])?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -299,6 +308,8 @@ impl SendSwapStateHandler {
|
|||||||
|
|
||||||
let claim_tx = self
|
let claim_tx = self
|
||||||
.chain_service
|
.chain_service
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
.get_transactions(&[claim_tx_id])
|
.get_transactions(&[claim_tx_id])
|
||||||
.map_err(|e| anyhow!("Failed to fetch claim tx {claim_tx_id}: {e}"))?
|
.map_err(|e| anyhow!("Failed to fetch claim tx {claim_tx_id}: {e}"))?
|
||||||
.first()
|
.first()
|
||||||
@@ -349,16 +360,15 @@ impl SendSwapStateHandler {
|
|||||||
.all_fees()
|
.all_fees()
|
||||||
.values()
|
.values()
|
||||||
.sum();
|
.sum();
|
||||||
let broadcast_fees_sat = Amount::from_sat(fee);
|
|
||||||
|
|
||||||
let refund_res =
|
let refund_res = self
|
||||||
self.swapper
|
.swapper
|
||||||
.refund_send_swap_cooperative(swap, &output_address, broadcast_fees_sat);
|
.refund_send_swap_cooperative(swap, &output_address, fee);
|
||||||
match refund_res {
|
match refund_res {
|
||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Cooperative refund failed: {:?}", e);
|
warn!("Cooperative refund failed: {:?}", e);
|
||||||
self.refund_non_cooperative(swap, broadcast_fees_sat).await
|
self.refund_non_cooperative(swap, fee).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,7 +376,7 @@ impl SendSwapStateHandler {
|
|||||||
async fn refund_non_cooperative(
|
async fn refund_non_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
) -> Result<String, PaymentError> {
|
) -> Result<String, PaymentError> {
|
||||||
info!(
|
info!(
|
||||||
"Initiating non-cooperative refund for Send Swap {}",
|
"Initiating non-cooperative refund for Send Swap {}",
|
||||||
|
|||||||
@@ -9,19 +9,22 @@ use boltz_client::error::Error;
|
|||||||
use boltz_client::network::electrum::ElectrumConfig;
|
use boltz_client::network::electrum::ElectrumConfig;
|
||||||
use boltz_client::network::Chain;
|
use boltz_client::network::Chain;
|
||||||
use boltz_client::swaps::boltzv2::{
|
use boltz_client::swaps::boltzv2::{
|
||||||
self, BoltzApiClientV2, ClaimTxResponse, CreateReverseRequest, CreateReverseResponse,
|
self, BoltzApiClientV2, ChainPair, Cooperative, CreateChainRequest, CreateChainResponse,
|
||||||
CreateSubmarineRequest, CreateSubmarineResponse, ReversePair, SubmarinePair,
|
CreateReverseRequest, CreateReverseResponse, CreateSubmarineRequest, CreateSubmarineResponse,
|
||||||
|
ReversePair, SubmarineClaimTxResponse, SubmarinePair,
|
||||||
};
|
};
|
||||||
use boltz_client::util::secrets::Preimage;
|
use boltz_client::util::secrets::Preimage;
|
||||||
use boltz_client::{Amount, Bolt11Invoice, LBtcSwapTxV2};
|
use boltz_client::{Amount, Bolt11Invoice, BtcSwapTxV2, Keypair, LBtcSwapTxV2, LockTime};
|
||||||
use boltz_status_stream::BoltzStatusStream;
|
use boltz_status_stream::BoltzStatusStream;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use lwk_wollet::elements::LockTime;
|
use lwk_wollet::elements;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use tokio::sync::{broadcast, watch};
|
use tokio::sync::{broadcast, watch};
|
||||||
|
|
||||||
use crate::error::PaymentError;
|
use crate::error::PaymentError;
|
||||||
use crate::model::{Config, Network, ReceiveSwap, SendSwap};
|
use crate::model::{
|
||||||
|
ChainSwap, Config, Direction, Network, ReceiveSwap, SendSwap, SwapScriptV2, SwapTxV2,
|
||||||
|
};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -41,44 +44,80 @@ pub trait SwapperStatusStream: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Swapper: Send + Sync {
|
pub trait Swapper: Send + Sync {
|
||||||
|
/// Create a new chain swap
|
||||||
|
fn create_chain_swap(
|
||||||
|
&self,
|
||||||
|
req: CreateChainRequest,
|
||||||
|
) -> Result<CreateChainResponse, PaymentError>;
|
||||||
|
|
||||||
/// Create a new send swap
|
/// Create a new send swap
|
||||||
fn create_send_swap(
|
fn create_send_swap(
|
||||||
&self,
|
&self,
|
||||||
req: CreateSubmarineRequest,
|
req: CreateSubmarineRequest,
|
||||||
) -> Result<CreateSubmarineResponse, PaymentError>;
|
) -> Result<CreateSubmarineResponse, PaymentError>;
|
||||||
|
|
||||||
|
/// Get a chain pair information
|
||||||
|
fn get_chain_pairs(&self, direction: Direction) -> Result<Option<ChainPair>, PaymentError>;
|
||||||
|
|
||||||
/// Get a submarine pair information
|
/// Get a submarine pair information
|
||||||
fn get_submarine_pairs(&self) -> Result<Option<SubmarinePair>, PaymentError>;
|
fn get_submarine_pairs(&self) -> Result<Option<SubmarinePair>, PaymentError>;
|
||||||
|
|
||||||
|
/// Refund a cooperatively chain swap
|
||||||
|
fn refund_chain_swap_cooperative(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
output_address: &str,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError>;
|
||||||
|
|
||||||
/// Refund a cooperatively send swap
|
/// Refund a cooperatively send swap
|
||||||
fn refund_send_swap_cooperative(
|
fn refund_send_swap_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
output_address: &str,
|
output_address: &str,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError>;
|
||||||
|
|
||||||
|
/// Refund non-cooperatively chain swap
|
||||||
|
fn refund_chain_swap_non_cooperative(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
output_address: &str,
|
||||||
|
current_height: u32,
|
||||||
) -> Result<String, PaymentError>;
|
) -> Result<String, PaymentError>;
|
||||||
|
|
||||||
/// Refund non-cooperatively send swap
|
/// Refund non-cooperatively send swap
|
||||||
fn refund_send_swap_non_cooperative(
|
fn refund_send_swap_non_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
output_address: &str,
|
output_address: &str,
|
||||||
current_height: u32,
|
current_height: u32,
|
||||||
) -> Result<String, PaymentError>;
|
) -> Result<String, PaymentError>;
|
||||||
|
|
||||||
/// Get claim tx details which includes the preimage as a proof of payment.
|
/// Get send swap claim tx details which includes the preimage as a proof of payment.
|
||||||
/// It is used to validate the preimage before claiming which is the reason why we need to separate
|
/// It is used to validate the preimage before claiming which is the reason why we need to separate
|
||||||
/// the claim into two steps.
|
/// the claim into two steps.
|
||||||
fn get_claim_tx_details(&self, swap: &SendSwap) -> Result<ClaimTxResponse, PaymentError>;
|
fn get_send_claim_tx_details(
|
||||||
|
&self,
|
||||||
|
swap: &SendSwap,
|
||||||
|
) -> Result<SubmarineClaimTxResponse, PaymentError>;
|
||||||
|
|
||||||
|
/// Claim chain swap.
|
||||||
|
fn claim_chain_swap(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
refund_address: String,
|
||||||
|
) -> Result<String, PaymentError>;
|
||||||
|
|
||||||
/// Claim send swap cooperatively. Here the remote swapper is the one that claims.
|
/// Claim send swap cooperatively. Here the remote swapper is the one that claims.
|
||||||
/// We are helping to use key spend path for cheaper fees.
|
/// We are helping to use key spend path for cheaper fees.
|
||||||
fn claim_send_swap_cooperative(
|
fn claim_send_swap_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
claim_tx_response: ClaimTxResponse,
|
claim_tx_response: SubmarineClaimTxResponse,
|
||||||
output_address: &str,
|
refund_address: &str,
|
||||||
) -> Result<(), PaymentError>;
|
) -> Result<(), PaymentError>;
|
||||||
|
|
||||||
/// Create a new receive swap
|
/// Create a new receive swap
|
||||||
@@ -109,7 +148,8 @@ pub trait Swapper: Send + Sync {
|
|||||||
pub struct BoltzSwapper {
|
pub struct BoltzSwapper {
|
||||||
client: BoltzApiClientV2,
|
client: BoltzApiClientV2,
|
||||||
config: Config,
|
config: Config,
|
||||||
electrum_config: ElectrumConfig,
|
liquid_electrum_config: ElectrumConfig,
|
||||||
|
bitcoin_electrum_config: ElectrumConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoltzSwapper {
|
impl BoltzSwapper {
|
||||||
@@ -117,9 +157,16 @@ impl BoltzSwapper {
|
|||||||
BoltzSwapper {
|
BoltzSwapper {
|
||||||
client: BoltzApiClientV2::new(&config.boltz_url),
|
client: BoltzApiClientV2::new(&config.boltz_url),
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
electrum_config: ElectrumConfig::new(
|
liquid_electrum_config: ElectrumConfig::new(
|
||||||
config.network.into(),
|
config.network.into(),
|
||||||
&config.electrum_url,
|
&config.liquid_electrum_url,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
100,
|
||||||
|
),
|
||||||
|
bitcoin_electrum_config: ElectrumConfig::new(
|
||||||
|
config.network.as_bitcoin_chain(),
|
||||||
|
&config.bitcoin_electrum_url,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
100,
|
100,
|
||||||
@@ -129,18 +176,25 @@ impl BoltzSwapper {
|
|||||||
|
|
||||||
fn new_refund_tx(
|
fn new_refund_tx(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap_id: String,
|
||||||
output_address: &String,
|
swap_script: SwapScriptV2,
|
||||||
) -> Result<LBtcSwapTxV2, PaymentError> {
|
refund_address: &String,
|
||||||
let swap_script = swap.get_swap_script()?;
|
) -> Result<SwapTxV2, PaymentError> {
|
||||||
|
let swap_tx = match swap_script {
|
||||||
Ok(LBtcSwapTxV2::new_refund(
|
SwapScriptV2::Bitcoin(swap_script) => SwapTxV2::Bitcoin(BtcSwapTxV2::new_refund(
|
||||||
swap_script.clone(),
|
swap_script.clone(),
|
||||||
output_address,
|
refund_address,
|
||||||
&self.electrum_config,
|
&self.bitcoin_electrum_config,
|
||||||
self.config.boltz_url.clone(),
|
)?),
|
||||||
swap.id.to_string(),
|
SwapScriptV2::Liquid(swap_script) => SwapTxV2::Liquid(LBtcSwapTxV2::new_refund(
|
||||||
)?)
|
swap_script.clone(),
|
||||||
|
refund_address,
|
||||||
|
&self.liquid_electrum_config,
|
||||||
|
self.config.boltz_url.clone(),
|
||||||
|
swap_id,
|
||||||
|
)?),
|
||||||
|
};
|
||||||
|
Ok(swap_tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_send_swap_preimage(
|
fn validate_send_swap_preimage(
|
||||||
@@ -165,9 +219,235 @@ impl BoltzSwapper {
|
|||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or(PaymentError::InvalidPreimage)
|
.ok_or(PaymentError::InvalidPreimage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn claim_outgoing_chain_swap(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
refund_address: String,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let claim_keypair = swap.get_claim_keypair()?;
|
||||||
|
let claim_swap_script = swap.get_claim_swap_script()?.as_bitcoin_script()?;
|
||||||
|
let claim_tx_wrapper = BtcSwapTxV2::new_claim(
|
||||||
|
claim_swap_script,
|
||||||
|
swap.address.clone(),
|
||||||
|
&self.bitcoin_electrum_config,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
|
let lockup_swap_script = swap.get_lockup_swap_script()?;
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap.id.clone(), lockup_swap_script, &refund_address)?
|
||||||
|
.as_liquid_tx()?;
|
||||||
|
|
||||||
|
let claim_tx_response = self.client.get_chain_claim_tx_details(&swap.id)?;
|
||||||
|
let (partial_sig, pub_nonce) = refund_tx.partial_sig(
|
||||||
|
&refund_keypair,
|
||||||
|
&claim_tx_response.pub_nonce,
|
||||||
|
&claim_tx_response.transaction_hash,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let claim_tx = claim_tx_wrapper.sign_claim(
|
||||||
|
&claim_keypair,
|
||||||
|
&Preimage::from_str(&swap.preimage)?,
|
||||||
|
swap.claim_fees_sat,
|
||||||
|
Some(Cooperative {
|
||||||
|
boltz_api: &self.client,
|
||||||
|
swap_id: swap.id.clone(),
|
||||||
|
pub_nonce: Some(pub_nonce),
|
||||||
|
partial_sig: Some(partial_sig),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
debug!("Claim Tx {:?}", claim_tx);
|
||||||
|
|
||||||
|
let claim_tx_id = claim_tx_wrapper
|
||||||
|
.broadcast(&claim_tx, &self.bitcoin_electrum_config)?
|
||||||
|
.to_string();
|
||||||
|
Ok(claim_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn claim_incoming_chain_swap(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
refund_address: String,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let claim_keypair = swap.get_claim_keypair()?;
|
||||||
|
let swap_script = swap.get_claim_swap_script()?.as_liquid_script()?;
|
||||||
|
let claim_tx_wrapper = LBtcSwapTxV2::new_claim(
|
||||||
|
swap_script,
|
||||||
|
swap.address.clone(),
|
||||||
|
&self.liquid_electrum_config,
|
||||||
|
self.config.boltz_url.clone(),
|
||||||
|
swap.id.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
|
let lockup_swap_script = swap.get_lockup_swap_script()?;
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap.id.clone(), lockup_swap_script, &refund_address)?
|
||||||
|
.as_bitcoin_tx()?;
|
||||||
|
|
||||||
|
let claim_tx_response = self.client.get_chain_claim_tx_details(&swap.id)?;
|
||||||
|
let (partial_sig, pub_nonce) = refund_tx.partial_sig(
|
||||||
|
&refund_keypair,
|
||||||
|
&claim_tx_response.pub_nonce,
|
||||||
|
&claim_tx_response.transaction_hash,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let claim_tx = claim_tx_wrapper.sign_claim(
|
||||||
|
&claim_keypair,
|
||||||
|
&Preimage::from_str(&swap.preimage)?,
|
||||||
|
Amount::from_sat(swap.claim_fees_sat),
|
||||||
|
Some(Cooperative {
|
||||||
|
boltz_api: &self.client,
|
||||||
|
swap_id: swap.id.clone(),
|
||||||
|
pub_nonce: Some(pub_nonce),
|
||||||
|
partial_sig: Some(partial_sig),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
debug!("Claim Tx {:?}", claim_tx);
|
||||||
|
let claim_tx_id = claim_tx_wrapper.broadcast(
|
||||||
|
&claim_tx,
|
||||||
|
&self.liquid_electrum_config,
|
||||||
|
Some((&self.client, self.config.network.into())),
|
||||||
|
)?;
|
||||||
|
Ok(claim_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refund_swap_cooperative(
|
||||||
|
&self,
|
||||||
|
swap_id: String,
|
||||||
|
swap_script: SwapScriptV2,
|
||||||
|
refund_keypair: &Keypair,
|
||||||
|
refund_address: &str,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
info!("Initiating cooperative refund for Swap {}", &swap_id);
|
||||||
|
let is_cooperative = Some(Cooperative {
|
||||||
|
boltz_api: &self.client,
|
||||||
|
swap_id: swap_id.clone(),
|
||||||
|
pub_nonce: None,
|
||||||
|
partial_sig: None,
|
||||||
|
});
|
||||||
|
let refund_tx_id = match swap_script.clone() {
|
||||||
|
SwapScriptV2::Bitcoin(_) => {
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap_id.clone(), swap_script, &refund_address.into())?
|
||||||
|
.as_bitcoin_tx()?;
|
||||||
|
let signed_tx =
|
||||||
|
refund_tx.sign_refund(refund_keypair, broadcast_fees_sat, is_cooperative)?;
|
||||||
|
refund_tx
|
||||||
|
.broadcast(&signed_tx, &self.bitcoin_electrum_config)?
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
SwapScriptV2::Liquid(_) => {
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap_id.clone(), swap_script, &refund_address.into())?
|
||||||
|
.as_liquid_tx()?;
|
||||||
|
let signed_tx = refund_tx.sign_refund(
|
||||||
|
refund_keypair,
|
||||||
|
Amount::from_sat(broadcast_fees_sat),
|
||||||
|
is_cooperative,
|
||||||
|
)?;
|
||||||
|
let is_lowball = match self.config.network {
|
||||||
|
Network::Mainnet => None,
|
||||||
|
Network::Testnet => {
|
||||||
|
Some((&self.client, boltz_client::network::Chain::LiquidTestnet))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
refund_tx.broadcast(&signed_tx, &self.liquid_electrum_config, is_lowball)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Successfully broadcast cooperative refund for Swap {}",
|
||||||
|
&swap_id
|
||||||
|
);
|
||||||
|
Ok(refund_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refund_swap_non_cooperative(
|
||||||
|
&self,
|
||||||
|
swap_id: String,
|
||||||
|
swap_script: SwapScriptV2,
|
||||||
|
refund_keypair: &Keypair,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
refund_address: &str,
|
||||||
|
current_height: u32,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let refund_tx_id = match swap_script.clone() {
|
||||||
|
SwapScriptV2::Bitcoin(script) => {
|
||||||
|
let locktime_from_height =
|
||||||
|
LockTime::from_height(current_height).map_err(|e| PaymentError::Generic {
|
||||||
|
err: format!("Error getting locktime from height {current_height:?}: {e}",),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
info!("locktime info: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", script.locktime);
|
||||||
|
if !script.locktime.is_implied_by(locktime_from_height) {
|
||||||
|
return Err(PaymentError::Generic {
|
||||||
|
err: format!(
|
||||||
|
"Cannot refund non-cooperatively. Lock time not elapsed yet. Current tip: {:?}. Script lock time: {:?}",
|
||||||
|
locktime_from_height, script.locktime
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap_id.clone(), swap_script, &refund_address.into())?
|
||||||
|
.as_bitcoin_tx()?;
|
||||||
|
let signed_tx = refund_tx.sign_refund(refund_keypair, broadcast_fees_sat, None)?;
|
||||||
|
refund_tx
|
||||||
|
.broadcast(&signed_tx, &self.bitcoin_electrum_config)?
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
SwapScriptV2::Liquid(script) => {
|
||||||
|
let locktime_from_height = elements::LockTime::from_height(current_height)
|
||||||
|
.map_err(|e| PaymentError::Generic {
|
||||||
|
err: format!("Cannot convert current block height to lock time: {e:?}"),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
info!("locktime info: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", script.locktime);
|
||||||
|
if !utils::is_locktime_expired(locktime_from_height, script.locktime) {
|
||||||
|
return Err(PaymentError::Generic {
|
||||||
|
err: format!(
|
||||||
|
"Cannot refund non-cooperatively. Lock time not elapsed yet. Current tip: {:?}. Script lock time: {:?}",
|
||||||
|
locktime_from_height, script.locktime
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap_id.clone(), swap_script, &refund_address.into())?
|
||||||
|
.as_liquid_tx()?;
|
||||||
|
let signed_tx = refund_tx.sign_refund(
|
||||||
|
refund_keypair,
|
||||||
|
Amount::from_sat(broadcast_fees_sat),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
let is_lowball = match self.config.network {
|
||||||
|
Network::Mainnet => None,
|
||||||
|
Network::Testnet => {
|
||||||
|
Some((&self.client, boltz_client::network::Chain::LiquidTestnet))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
refund_tx.broadcast(&signed_tx, &self.liquid_electrum_config, is_lowball)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Successfully broadcast non-cooperative refund for Swap {}",
|
||||||
|
swap_id
|
||||||
|
);
|
||||||
|
Ok(refund_tx_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Swapper for BoltzSwapper {
|
impl Swapper for BoltzSwapper {
|
||||||
|
/// Create a new chain swap
|
||||||
|
fn create_chain_swap(
|
||||||
|
&self,
|
||||||
|
req: CreateChainRequest,
|
||||||
|
) -> Result<CreateChainResponse, PaymentError> {
|
||||||
|
Ok(self.client.post_chain_req(req)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new send swap
|
/// Create a new send swap
|
||||||
fn create_send_swap(
|
fn create_send_swap(
|
||||||
&self,
|
&self,
|
||||||
@@ -176,114 +456,162 @@ impl Swapper for BoltzSwapper {
|
|||||||
Ok(self.client.post_swap_req(&req)?)
|
Ok(self.client.post_swap_req(&req)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a chain pair information
|
||||||
|
fn get_chain_pairs(&self, direction: Direction) -> Result<Option<ChainPair>, PaymentError> {
|
||||||
|
let pairs = self.client.get_chain_pairs()?;
|
||||||
|
let pair = match direction {
|
||||||
|
Direction::Incoming => pairs.get_btc_to_lbtc_pair(),
|
||||||
|
Direction::Outgoing => pairs.get_lbtc_to_btc_pair(),
|
||||||
|
};
|
||||||
|
Ok(pair)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a submarine pair information
|
/// Get a submarine pair information
|
||||||
fn get_submarine_pairs(&self) -> Result<Option<SubmarinePair>, PaymentError> {
|
fn get_submarine_pairs(&self) -> Result<Option<SubmarinePair>, PaymentError> {
|
||||||
Ok(self.client.get_submarine_pairs()?.get_lbtc_to_btc_pair())
|
Ok(self.client.get_submarine_pairs()?.get_lbtc_to_btc_pair())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refund a cooperatively chain swap
|
||||||
|
fn refund_chain_swap_cooperative(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
output_address: &str,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
|
let swap_script = swap.get_lockup_swap_script()?;
|
||||||
|
info!("Initiating cooperative refund for Chain Swap {}", &swap.id);
|
||||||
|
self.refund_swap_cooperative(
|
||||||
|
swap.id.clone(),
|
||||||
|
swap_script,
|
||||||
|
&refund_keypair,
|
||||||
|
output_address,
|
||||||
|
broadcast_fees_sat,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Refund a cooperatively send swap
|
/// Refund a cooperatively send swap
|
||||||
fn refund_send_swap_cooperative(
|
fn refund_send_swap_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
output_address: &str,
|
output_address: &str,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
) -> Result<String, PaymentError> {
|
) -> Result<String, PaymentError> {
|
||||||
info!("Initiating cooperative refund for Send Swap {}", &swap.id);
|
info!("Initiating cooperative refund for Send Swap {}", &swap.id);
|
||||||
let refund_tx = self.new_refund_tx(swap, &output_address.into())?;
|
let swap_script = SwapScriptV2::Liquid(swap.get_swap_script()?);
|
||||||
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
let cooperative = Some((&self.client, &swap.id));
|
self.refund_swap_cooperative(
|
||||||
let tx = refund_tx.sign_refund(
|
swap.id.clone(),
|
||||||
&swap
|
swap_script,
|
||||||
.get_refund_keypair()
|
&refund_keypair,
|
||||||
.map_err(|e| Error::Generic(e.to_string()))?,
|
output_address,
|
||||||
broadcast_fees_sat,
|
broadcast_fees_sat,
|
||||||
cooperative,
|
)
|
||||||
)?;
|
}
|
||||||
let is_lowball = match self.config.network {
|
|
||||||
Network::Mainnet => None,
|
/// Refund non-cooperatively chain swap
|
||||||
Network::Testnet => Some((&self.client, boltz_client::network::Chain::LiquidTestnet)),
|
fn refund_chain_swap_non_cooperative(
|
||||||
};
|
&self,
|
||||||
let refund_tx_id = refund_tx.broadcast(&tx, &self.electrum_config, is_lowball)?;
|
swap: &ChainSwap,
|
||||||
|
broadcast_fees_sat: u64,
|
||||||
|
output_address: &str,
|
||||||
|
current_height: u32,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
info!(
|
info!(
|
||||||
"Successfully broadcast cooperative refund for Send Swap {}",
|
"Initiating non cooperative refund for Chain Swap {}",
|
||||||
&swap.id
|
&swap.id
|
||||||
);
|
);
|
||||||
Ok(refund_tx_id.clone())
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
|
let swap_script = swap.get_lockup_swap_script()?;
|
||||||
|
self.refund_swap_non_cooperative(
|
||||||
|
swap.id.clone(),
|
||||||
|
swap_script,
|
||||||
|
&refund_keypair,
|
||||||
|
broadcast_fees_sat,
|
||||||
|
output_address,
|
||||||
|
current_height,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refund non-cooperatively send swap
|
/// Refund non-cooperatively send swap
|
||||||
fn refund_send_swap_non_cooperative(
|
fn refund_send_swap_non_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
broadcast_fees_sat: Amount,
|
broadcast_fees_sat: u64,
|
||||||
output_address: &str,
|
output_address: &str,
|
||||||
current_height: u32,
|
current_height: u32,
|
||||||
) -> Result<String, PaymentError> {
|
) -> Result<String, PaymentError> {
|
||||||
let swap_script = swap.get_swap_script()?;
|
let swap_script = SwapScriptV2::Liquid(swap.get_swap_script()?);
|
||||||
let locktime_from_height =
|
let refund_keypair = swap.get_refund_keypair()?;
|
||||||
LockTime::from_height(current_height).map_err(|e| PaymentError::Generic {
|
self.refund_swap_non_cooperative(
|
||||||
err: format!("Cannot convert current block height to lock time: {e:?}"),
|
swap.id.clone(),
|
||||||
})?;
|
swap_script,
|
||||||
|
&refund_keypair,
|
||||||
info!("locktime info: locktime_from_height = {locktime_from_height:?}, swap_script.locktime = {:?}", swap_script.locktime);
|
|
||||||
if !utils::is_locktime_expired(locktime_from_height, swap_script.locktime) {
|
|
||||||
return Err(PaymentError::Generic {
|
|
||||||
err: format!(
|
|
||||||
"Cannot refund non-cooperatively. Lock time not elapsed yet. Current tip: {:?}. Script lock time: {:?}",
|
|
||||||
locktime_from_height, swap_script.locktime
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let refund_tx = self.new_refund_tx(swap, &output_address.into())?;
|
|
||||||
let tx = refund_tx.sign_refund(
|
|
||||||
&swap
|
|
||||||
.get_refund_keypair()
|
|
||||||
.map_err(|e| Error::Generic(e.to_string()))?,
|
|
||||||
broadcast_fees_sat,
|
broadcast_fees_sat,
|
||||||
None,
|
output_address,
|
||||||
)?;
|
current_height,
|
||||||
let is_lowball = match self.config.network {
|
)
|
||||||
Network::Mainnet => None,
|
|
||||||
Network::Testnet => Some((&self.client, boltz_client::network::Chain::LiquidTestnet)),
|
|
||||||
};
|
|
||||||
let refund_tx_id = refund_tx.broadcast(&tx, &self.electrum_config, is_lowball)?;
|
|
||||||
info!(
|
|
||||||
"Successfully broadcast non-cooperative refund for swap-in {}",
|
|
||||||
swap.id
|
|
||||||
);
|
|
||||||
Ok(refund_tx_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get claim tx details which includes the preimage as a proof of payment.
|
/// Get claim tx details which includes the preimage as a proof of payment.
|
||||||
/// It is used to validate the preimage before claiming which is the reason why we need to separate
|
/// It is used to validate the preimage before claiming which is the reason why we need to separate
|
||||||
/// the claim into two steps.
|
/// the claim into two steps.
|
||||||
fn get_claim_tx_details(&self, swap: &SendSwap) -> Result<ClaimTxResponse, PaymentError> {
|
fn get_send_claim_tx_details(
|
||||||
let claim_tx_response = self.client.get_claim_tx_details(&swap.id)?;
|
&self,
|
||||||
|
swap: &SendSwap,
|
||||||
|
) -> Result<SubmarineClaimTxResponse, PaymentError> {
|
||||||
|
let claim_tx_response = self.client.get_submarine_claim_tx_details(&swap.id)?;
|
||||||
info!("Received claim tx details: {:?}", &claim_tx_response);
|
info!("Received claim tx details: {:?}", &claim_tx_response);
|
||||||
|
|
||||||
self.validate_send_swap_preimage(&swap.id, &swap.invoice, &claim_tx_response.preimage)?;
|
self.validate_send_swap_preimage(&swap.id, &swap.invoice, &claim_tx_response.preimage)?;
|
||||||
Ok(claim_tx_response)
|
Ok(claim_tx_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Claim chain swap.
|
||||||
|
fn claim_chain_swap(
|
||||||
|
&self,
|
||||||
|
swap: &ChainSwap,
|
||||||
|
refund_address: String,
|
||||||
|
) -> Result<String, PaymentError> {
|
||||||
|
let claim_tx_id = match swap.direction {
|
||||||
|
Direction::Incoming => self.claim_incoming_chain_swap(swap, refund_address),
|
||||||
|
Direction::Outgoing => self.claim_outgoing_chain_swap(swap, refund_address),
|
||||||
|
}?;
|
||||||
|
info!(
|
||||||
|
"Successfully broadcast claim tx {claim_tx_id} for Chain Swap {}",
|
||||||
|
swap.id
|
||||||
|
);
|
||||||
|
Ok(claim_tx_id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Claim send swap cooperatively. Here the remote swapper is the one that claims.
|
/// Claim send swap cooperatively. Here the remote swapper is the one that claims.
|
||||||
/// We are helping to use key spend path for cheaper fees.
|
/// We are helping to use key spend path for cheaper fees.
|
||||||
fn claim_send_swap_cooperative(
|
fn claim_send_swap_cooperative(
|
||||||
&self,
|
&self,
|
||||||
swap: &SendSwap,
|
swap: &SendSwap,
|
||||||
claim_tx_response: ClaimTxResponse,
|
claim_tx_response: SubmarineClaimTxResponse,
|
||||||
output_address: &str,
|
refund_address: &str,
|
||||||
) -> Result<(), PaymentError> {
|
) -> Result<(), PaymentError> {
|
||||||
let swap_id = &swap.id;
|
let swap_id = &swap.id;
|
||||||
let keypair = swap.get_refund_keypair()?;
|
let keypair = swap.get_refund_keypair()?;
|
||||||
let refund_tx = self.new_refund_tx(swap, &output_address.into())?;
|
let swap_script = SwapScriptV2::Liquid(swap.get_swap_script()?);
|
||||||
|
let refund_tx = self
|
||||||
|
.new_refund_tx(swap.id.clone(), swap_script, &refund_address.into())?
|
||||||
|
.as_liquid_tx()?;
|
||||||
|
|
||||||
self.validate_send_swap_preimage(swap_id, &swap.invoice, &claim_tx_response.preimage)?;
|
self.validate_send_swap_preimage(swap_id, &swap.invoice, &claim_tx_response.preimage)?;
|
||||||
|
|
||||||
let (partial_sig, pub_nonce) =
|
let (partial_sig, pub_nonce) = refund_tx.partial_sig(
|
||||||
refund_tx.submarine_partial_sig(&keypair, &claim_tx_response)?;
|
&keypair,
|
||||||
|
&claim_tx_response.pub_nonce,
|
||||||
|
&claim_tx_response.transaction_hash,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.client
|
self.client.post_submarine_claim_tx_details(
|
||||||
.post_claim_tx_details(&swap_id.to_string(), pub_nonce, partial_sig)?;
|
&swap_id.to_string(),
|
||||||
|
pub_nonce,
|
||||||
|
partial_sig,
|
||||||
|
)?;
|
||||||
info!("Successfully sent claim details for swap-in {swap_id}");
|
info!("Successfully sent claim details for swap-in {swap_id}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -312,24 +640,27 @@ impl Swapper for BoltzSwapper {
|
|||||||
let claim_tx_wrapper = LBtcSwapTxV2::new_claim(
|
let claim_tx_wrapper = LBtcSwapTxV2::new_claim(
|
||||||
swap_script,
|
swap_script,
|
||||||
claim_address,
|
claim_address,
|
||||||
&self.electrum_config,
|
&self.liquid_electrum_config,
|
||||||
self.config.boltz_url.clone(),
|
self.config.boltz_url.clone(),
|
||||||
swap.id.clone(),
|
swap.id.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let cooperative = Some((&self.client, swap.id.clone()));
|
let is_cooperative = Some(Cooperative {
|
||||||
|
boltz_api: &self.client,
|
||||||
|
swap_id: swap.id.clone(),
|
||||||
|
pub_nonce: None,
|
||||||
|
partial_sig: None,
|
||||||
|
});
|
||||||
let claim_tx = claim_tx_wrapper.sign_claim(
|
let claim_tx = claim_tx_wrapper.sign_claim(
|
||||||
&swap.get_claim_keypair()?,
|
&swap.get_claim_keypair()?,
|
||||||
&Preimage::from_str(&swap.preimage)?,
|
&Preimage::from_str(&swap.preimage)?,
|
||||||
Amount::from_sat(swap.claim_fees_sat),
|
Amount::from_sat(swap.claim_fees_sat),
|
||||||
// Enable cooperative claim (Some) or not (None)
|
is_cooperative,
|
||||||
cooperative,
|
|
||||||
// None
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let claim_tx_id = claim_tx_wrapper.broadcast(
|
let claim_tx_id = claim_tx_wrapper.broadcast(
|
||||||
&claim_tx,
|
&claim_tx,
|
||||||
&self.electrum_config,
|
&self.liquid_electrum_config,
|
||||||
Some((&self.client, self.config.network.into())),
|
Some((&self.client, self.config.network.into())),
|
||||||
)?;
|
)?;
|
||||||
info!("Successfully broadcast claim tx {claim_tx_id} for Receive Swap {swap_id}");
|
info!("Successfully broadcast claim tx {claim_tx_id} for Receive Swap {swap_id}");
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
model::{Config, Network, PaymentState, PaymentTxData, PaymentType, ReceiveSwap, SendSwap},
|
chain_swap::ChainSwapStateHandler,
|
||||||
|
model::{
|
||||||
|
ChainSwap, Config, Direction, Network, PaymentState, PaymentTxData, PaymentType,
|
||||||
|
ReceiveSwap, SendSwap,
|
||||||
|
},
|
||||||
persist::Persister,
|
persist::Persister,
|
||||||
receive_swap::ReceiveSwapStateHandler,
|
receive_swap::ReceiveSwapStateHandler,
|
||||||
send_swap::SendSwapStateHandler,
|
send_swap::SendSwapStateHandler,
|
||||||
@@ -15,6 +19,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use bip39::rand::{self, distributions::Alphanumeric, Rng};
|
use bip39::rand::{self, distributions::Alphanumeric, Rng};
|
||||||
use lwk_wollet::{ElectrumClient, ElectrumUrl};
|
use lwk_wollet::{ElectrumClient, ElectrumUrl};
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
pub(crate) const TEST_MNEMONIC: &str =
|
pub(crate) const TEST_MNEMONIC: &str =
|
||||||
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
||||||
@@ -25,11 +30,11 @@ pub(crate) fn new_send_swap_state_handler(
|
|||||||
let config = Config::testnet();
|
let config = Config::testnet();
|
||||||
let onchain_wallet = Arc::new(new_onchain_wallet(&config)?);
|
let onchain_wallet = Arc::new(new_onchain_wallet(&config)?);
|
||||||
let swapper = Arc::new(BoltzSwapper::new(config.clone()));
|
let swapper = Arc::new(BoltzSwapper::new(config.clone()));
|
||||||
let chain_service = Arc::new(ElectrumClient::new(&ElectrumUrl::new(
|
let chain_service = Arc::new(Mutex::new(ElectrumClient::new(&ElectrumUrl::new(
|
||||||
&config.electrum_url,
|
&config.liquid_electrum_url,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
))?);
|
))?));
|
||||||
|
|
||||||
Ok(SendSwapStateHandler::new(
|
Ok(SendSwapStateHandler::new(
|
||||||
config,
|
config,
|
||||||
@@ -55,6 +60,27 @@ pub(crate) fn new_receive_swap_state_handler(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_chain_swap_state_handler(
|
||||||
|
persister: Arc<Persister>,
|
||||||
|
) -> Result<ChainSwapStateHandler> {
|
||||||
|
let config = Config::testnet();
|
||||||
|
let onchain_wallet = Arc::new(new_onchain_wallet(&config)?);
|
||||||
|
let swapper = Arc::new(BoltzSwapper::new(config.clone()));
|
||||||
|
let liquid_chain_service = Arc::new(Mutex::new(ElectrumClient::new(&ElectrumUrl::new(
|
||||||
|
&config.liquid_electrum_url,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
))?));
|
||||||
|
|
||||||
|
ChainSwapStateHandler::new(
|
||||||
|
config,
|
||||||
|
onchain_wallet,
|
||||||
|
persister,
|
||||||
|
swapper,
|
||||||
|
liquid_chain_service,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_send_swap(payment_state: Option<PaymentState>) -> SendSwap {
|
pub(crate) fn new_send_swap(payment_state: Option<PaymentState>) -> SendSwap {
|
||||||
let id = rand::thread_rng()
|
let id = rand::thread_rng()
|
||||||
.sample_iter(&Alphanumeric)
|
.sample_iter(&Alphanumeric)
|
||||||
@@ -102,6 +128,33 @@ pub(crate) fn new_receive_swap(payment_state: Option<PaymentState>) -> ReceiveSw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_chain_swap(payment_state: Option<PaymentState>) -> ChainSwap {
|
||||||
|
let id = rand::thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.take(4)
|
||||||
|
.map(char::from)
|
||||||
|
.collect();
|
||||||
|
ChainSwap {
|
||||||
|
id,
|
||||||
|
direction: Direction::Incoming,
|
||||||
|
address: "".to_string(),
|
||||||
|
preimage: "".to_string(),
|
||||||
|
create_response_json: "{}".to_string(),
|
||||||
|
claim_private_key: "".to_string(),
|
||||||
|
refund_private_key: "".to_string(),
|
||||||
|
payer_amount_sat: 0,
|
||||||
|
receiver_amount_sat: 0,
|
||||||
|
claim_fees_sat: 0,
|
||||||
|
server_lockup_tx_id: None,
|
||||||
|
user_lockup_tx_id: None,
|
||||||
|
claim_tx_id: None,
|
||||||
|
refund_tx_id: None,
|
||||||
|
created_at: utils::now(),
|
||||||
|
state: payment_state.unwrap_or(PaymentState::Created),
|
||||||
|
accept_zero_conf: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_persister() -> Result<(TempDir, Persister)> {
|
pub(crate) fn new_persister() -> Result<(TempDir, Persister)> {
|
||||||
let temp_dir = TempDir::new("liquid-sdk")?;
|
let temp_dir = TempDir::new("liquid-sdk")?;
|
||||||
let persister = Persister::new(
|
let persister = Persister::new(
|
||||||
|
|||||||
@@ -137,8 +137,11 @@ impl OnchainWallet for LiquidOnchainWallet {
|
|||||||
/// Perform a full scan of the wallet
|
/// Perform a full scan of the wallet
|
||||||
async fn full_scan(&self) -> Result<(), PaymentError> {
|
async fn full_scan(&self) -> Result<(), PaymentError> {
|
||||||
let mut wallet = self.wallet.lock().await;
|
let mut wallet = self.wallet.lock().await;
|
||||||
let mut electrum_client =
|
let mut electrum_client = ElectrumClient::new(&ElectrumUrl::new(
|
||||||
ElectrumClient::new(&ElectrumUrl::new(&self.config.electrum_url, true, true))?;
|
&self.config.liquid_electrum_url,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
))?;
|
||||||
lwk_wollet::full_scan_with_electrum_client(&mut wallet, &mut electrum_client)?;
|
lwk_wollet::full_scan_with_electrum_client(&mut wallet, &mut electrum_client)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ abstract class BindingLiquidSdk implements RustOpaqueInterface {
|
|||||||
|
|
||||||
Future<List<Payment>> listPayments();
|
Future<List<Payment>> listPayments();
|
||||||
|
|
||||||
|
Future<SendPaymentResponse> payOnchain({required PayOnchainRequest req});
|
||||||
|
|
||||||
|
Future<PreparePayOnchainResponse> preparePayOnchain({required PreparePayOnchainRequest req});
|
||||||
|
|
||||||
Future<PrepareReceiveResponse> prepareReceivePayment({required PrepareReceiveRequest req});
|
Future<PrepareReceiveResponse> prepareReceivePayment({required PrepareReceiveRequest req});
|
||||||
|
|
||||||
Future<PrepareSendResponse> prepareSendPayment({required PrepareSendRequest req});
|
Future<PrepareSendResponse> prepareSendPayment({required PrepareSendRequest req});
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ sealed class LiquidSdkError with _$LiquidSdkError implements FrbException {
|
|||||||
required String err,
|
required String err,
|
||||||
}) = LiquidSdkError_Generic;
|
}) = LiquidSdkError_Generic;
|
||||||
const factory LiquidSdkError.notStarted() = LiquidSdkError_NotStarted;
|
const factory LiquidSdkError.notStarted() = LiquidSdkError_NotStarted;
|
||||||
|
const factory LiquidSdkError.serviceConnectivity({
|
||||||
|
required String err,
|
||||||
|
}) = LiquidSdkError_ServiceConnectivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
|||||||
@@ -188,6 +188,80 @@ abstract class LiquidSdkError_NotStarted extends LiquidSdkError {
|
|||||||
const LiquidSdkError_NotStarted._() : super._();
|
const LiquidSdkError_NotStarted._() : super._();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$LiquidSdkError_ServiceConnectivityImplCopyWith<$Res> {
|
||||||
|
factory _$$LiquidSdkError_ServiceConnectivityImplCopyWith(_$LiquidSdkError_ServiceConnectivityImpl value,
|
||||||
|
$Res Function(_$LiquidSdkError_ServiceConnectivityImpl) then) =
|
||||||
|
__$$LiquidSdkError_ServiceConnectivityImplCopyWithImpl<$Res>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String err});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$LiquidSdkError_ServiceConnectivityImplCopyWithImpl<$Res>
|
||||||
|
extends _$LiquidSdkErrorCopyWithImpl<$Res, _$LiquidSdkError_ServiceConnectivityImpl>
|
||||||
|
implements _$$LiquidSdkError_ServiceConnectivityImplCopyWith<$Res> {
|
||||||
|
__$$LiquidSdkError_ServiceConnectivityImplCopyWithImpl(_$LiquidSdkError_ServiceConnectivityImpl _value,
|
||||||
|
$Res Function(_$LiquidSdkError_ServiceConnectivityImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? err = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$LiquidSdkError_ServiceConnectivityImpl(
|
||||||
|
err: null == err
|
||||||
|
? _value.err
|
||||||
|
: err // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$LiquidSdkError_ServiceConnectivityImpl extends LiquidSdkError_ServiceConnectivity {
|
||||||
|
const _$LiquidSdkError_ServiceConnectivityImpl({required this.err}) : super._();
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String err;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LiquidSdkError.serviceConnectivity(err: $err)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$LiquidSdkError_ServiceConnectivityImpl &&
|
||||||
|
(identical(other.err, err) || other.err == err));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, err);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$LiquidSdkError_ServiceConnectivityImplCopyWith<_$LiquidSdkError_ServiceConnectivityImpl> get copyWith =>
|
||||||
|
__$$LiquidSdkError_ServiceConnectivityImplCopyWithImpl<_$LiquidSdkError_ServiceConnectivityImpl>(
|
||||||
|
this, _$identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class LiquidSdkError_ServiceConnectivity extends LiquidSdkError {
|
||||||
|
const factory LiquidSdkError_ServiceConnectivity({required final String err}) =
|
||||||
|
_$LiquidSdkError_ServiceConnectivityImpl;
|
||||||
|
const LiquidSdkError_ServiceConnectivity._() : super._();
|
||||||
|
|
||||||
|
String get err;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$LiquidSdkError_ServiceConnectivityImplCopyWith<_$LiquidSdkError_ServiceConnectivityImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$PaymentError {}
|
mixin _$PaymentError {}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
|||||||
String get codegenVersion => '2.0.0-dev.38';
|
String get codegenVersion => '2.0.0-dev.38';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get rustContentHash => 308302012;
|
int get rustContentHash => -107248138;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig(
|
static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig(
|
||||||
stem: 'breez_liquid_sdk',
|
stem: 'breez_liquid_sdk',
|
||||||
@@ -76,6 +76,12 @@ abstract class RustLibApi extends BaseApi {
|
|||||||
|
|
||||||
Future<List<Payment>> crateBindingsBindingLiquidSdkListPayments({required BindingLiquidSdk that});
|
Future<List<Payment>> crateBindingsBindingLiquidSdkListPayments({required BindingLiquidSdk that});
|
||||||
|
|
||||||
|
Future<SendPaymentResponse> crateBindingsBindingLiquidSdkPayOnchain(
|
||||||
|
{required BindingLiquidSdk that, required PayOnchainRequest req});
|
||||||
|
|
||||||
|
Future<PreparePayOnchainResponse> crateBindingsBindingLiquidSdkPreparePayOnchain(
|
||||||
|
{required BindingLiquidSdk that, required PreparePayOnchainRequest req});
|
||||||
|
|
||||||
Future<PrepareReceiveResponse> crateBindingsBindingLiquidSdkPrepareReceivePayment(
|
Future<PrepareReceiveResponse> crateBindingsBindingLiquidSdkPrepareReceivePayment(
|
||||||
{required BindingLiquidSdk that, required PrepareReceiveRequest req});
|
{required BindingLiquidSdk that, required PrepareReceiveRequest req});
|
||||||
|
|
||||||
@@ -266,6 +272,58 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
argNames: ["that"],
|
argNames: ["that"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<SendPaymentResponse> crateBindingsBindingLiquidSdkPayOnchain(
|
||||||
|
{required BindingLiquidSdk that, required PayOnchainRequest req}) {
|
||||||
|
return handler.executeNormal(NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 =
|
||||||
|
cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
|
||||||
|
that);
|
||||||
|
var arg1 = cst_encode_box_autoadd_pay_onchain_request(req);
|
||||||
|
return wire.wire__crate__bindings__BindingLiquidSdk_pay_onchain(port_, arg0, arg1);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_send_payment_response,
|
||||||
|
decodeErrorData: dco_decode_payment_error,
|
||||||
|
),
|
||||||
|
constMeta: kCrateBindingsBindingLiquidSdkPayOnchainConstMeta,
|
||||||
|
argValues: [that, req],
|
||||||
|
apiImpl: this,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateBindingsBindingLiquidSdkPayOnchainConstMeta => const TaskConstMeta(
|
||||||
|
debugName: "BindingLiquidSdk_pay_onchain",
|
||||||
|
argNames: ["that", "req"],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PreparePayOnchainResponse> crateBindingsBindingLiquidSdkPreparePayOnchain(
|
||||||
|
{required BindingLiquidSdk that, required PreparePayOnchainRequest req}) {
|
||||||
|
return handler.executeNormal(NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
var arg0 =
|
||||||
|
cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
|
||||||
|
that);
|
||||||
|
var arg1 = cst_encode_box_autoadd_prepare_pay_onchain_request(req);
|
||||||
|
return wire.wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(port_, arg0, arg1);
|
||||||
|
},
|
||||||
|
codec: DcoCodec(
|
||||||
|
decodeSuccessData: dco_decode_prepare_pay_onchain_response,
|
||||||
|
decodeErrorData: dco_decode_payment_error,
|
||||||
|
),
|
||||||
|
constMeta: kCrateBindingsBindingLiquidSdkPreparePayOnchainConstMeta,
|
||||||
|
argValues: [that, req],
|
||||||
|
apiImpl: this,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateBindingsBindingLiquidSdkPreparePayOnchainConstMeta => const TaskConstMeta(
|
||||||
|
debugName: "BindingLiquidSdk_prepare_pay_onchain",
|
||||||
|
argNames: ["that", "req"],
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PrepareReceiveResponse> crateBindingsBindingLiquidSdkPrepareReceivePayment(
|
Future<PrepareReceiveResponse> crateBindingsBindingLiquidSdkPrepareReceivePayment(
|
||||||
{required BindingLiquidSdk that, required PrepareReceiveRequest req}) {
|
{required BindingLiquidSdk that, required PrepareReceiveRequest req}) {
|
||||||
@@ -631,12 +689,24 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return dco_decode_liquid_sdk_event(raw);
|
return dco_decode_liquid_sdk_event(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest dco_decode_box_autoadd_pay_onchain_request(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return dco_decode_pay_onchain_request(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment dco_decode_box_autoadd_payment(dynamic raw) {
|
Payment dco_decode_box_autoadd_payment(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
return dco_decode_payment(raw);
|
return dco_decode_payment(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest dco_decode_box_autoadd_prepare_pay_onchain_request(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
return dco_decode_prepare_pay_onchain_request(raw);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest dco_decode_box_autoadd_prepare_receive_request(dynamic raw) {
|
PrepareReceiveRequest dco_decode_box_autoadd_prepare_receive_request(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@@ -677,15 +747,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
Config dco_decode_config(dynamic raw) {
|
Config dco_decode_config(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
final arr = raw as List<dynamic>;
|
final arr = raw as List<dynamic>;
|
||||||
if (arr.length != 7) throw Exception('unexpected arr length: expect 7 but see ${arr.length}');
|
if (arr.length != 8) throw Exception('unexpected arr length: expect 8 but see ${arr.length}');
|
||||||
return Config(
|
return Config(
|
||||||
boltzUrl: dco_decode_String(arr[0]),
|
boltzUrl: dco_decode_String(arr[0]),
|
||||||
electrumUrl: dco_decode_String(arr[1]),
|
liquidElectrumUrl: dco_decode_String(arr[1]),
|
||||||
workingDir: dco_decode_String(arr[2]),
|
bitcoinElectrumUrl: dco_decode_String(arr[2]),
|
||||||
network: dco_decode_network(arr[3]),
|
workingDir: dco_decode_String(arr[3]),
|
||||||
paymentTimeoutSec: dco_decode_u_64(arr[4]),
|
network: dco_decode_network(arr[4]),
|
||||||
zeroConfMinFeeRate: dco_decode_f_32(arr[5]),
|
paymentTimeoutSec: dco_decode_u_64(arr[5]),
|
||||||
zeroConfMaxAmountSat: dco_decode_opt_box_autoadd_u_64(arr[6]),
|
zeroConfMinFeeRate: dco_decode_f_32(arr[6]),
|
||||||
|
zeroConfMaxAmountSat: dco_decode_opt_box_autoadd_u_64(arr[7]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,6 +808,10 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
return LiquidSdkError_NotStarted();
|
return LiquidSdkError_NotStarted();
|
||||||
|
case 3:
|
||||||
|
return LiquidSdkError_ServiceConnectivity(
|
||||||
|
err: dco_decode_String(raw[1]),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw Exception("unreachable");
|
throw Exception("unreachable");
|
||||||
}
|
}
|
||||||
@@ -851,6 +926,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return raw == null ? null : dco_decode_box_autoadd_u_64(raw);
|
return raw == null ? null : dco_decode_box_autoadd_u_64(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
|
||||||
|
return PayOnchainRequest(
|
||||||
|
address: dco_decode_String(arr[0]),
|
||||||
|
prepareRes: dco_decode_prepare_pay_onchain_response(arr[1]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment dco_decode_payment(dynamic raw) {
|
Payment dco_decode_payment(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@@ -943,6 +1029,27 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return PaymentType.values[raw as int];
|
return PaymentType.values[raw as int];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest dco_decode_prepare_pay_onchain_request(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 1) throw Exception('unexpected arr length: expect 1 but see ${arr.length}');
|
||||||
|
return PreparePayOnchainRequest(
|
||||||
|
amountSat: dco_decode_u_64(arr[0]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainResponse dco_decode_prepare_pay_onchain_response(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
final arr = raw as List<dynamic>;
|
||||||
|
if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
|
||||||
|
return PreparePayOnchainResponse(
|
||||||
|
amountSat: dco_decode_u_64(arr[0]),
|
||||||
|
feesSat: dco_decode_u_64(arr[1]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest dco_decode_prepare_receive_request(dynamic raw) {
|
PrepareReceiveRequest dco_decode_prepare_receive_request(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@@ -1162,12 +1269,24 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return (sse_decode_liquid_sdk_event(deserializer));
|
return (sse_decode_liquid_sdk_event(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest sse_decode_box_autoadd_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return (sse_decode_pay_onchain_request(deserializer));
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment sse_decode_box_autoadd_payment(SseDeserializer deserializer) {
|
Payment sse_decode_box_autoadd_payment(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
return (sse_decode_payment(deserializer));
|
return (sse_decode_payment(deserializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest sse_decode_box_autoadd_prepare_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
return (sse_decode_prepare_pay_onchain_request(deserializer));
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest sse_decode_box_autoadd_prepare_receive_request(SseDeserializer deserializer) {
|
PrepareReceiveRequest sse_decode_box_autoadd_prepare_receive_request(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -1208,7 +1327,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
Config sse_decode_config(SseDeserializer deserializer) {
|
Config sse_decode_config(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
var var_boltzUrl = sse_decode_String(deserializer);
|
var var_boltzUrl = sse_decode_String(deserializer);
|
||||||
var var_electrumUrl = sse_decode_String(deserializer);
|
var var_liquidElectrumUrl = sse_decode_String(deserializer);
|
||||||
|
var var_bitcoinElectrumUrl = sse_decode_String(deserializer);
|
||||||
var var_workingDir = sse_decode_String(deserializer);
|
var var_workingDir = sse_decode_String(deserializer);
|
||||||
var var_network = sse_decode_network(deserializer);
|
var var_network = sse_decode_network(deserializer);
|
||||||
var var_paymentTimeoutSec = sse_decode_u_64(deserializer);
|
var var_paymentTimeoutSec = sse_decode_u_64(deserializer);
|
||||||
@@ -1216,7 +1336,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
var var_zeroConfMaxAmountSat = sse_decode_opt_box_autoadd_u_64(deserializer);
|
var var_zeroConfMaxAmountSat = sse_decode_opt_box_autoadd_u_64(deserializer);
|
||||||
return Config(
|
return Config(
|
||||||
boltzUrl: var_boltzUrl,
|
boltzUrl: var_boltzUrl,
|
||||||
electrumUrl: var_electrumUrl,
|
liquidElectrumUrl: var_liquidElectrumUrl,
|
||||||
|
bitcoinElectrumUrl: var_bitcoinElectrumUrl,
|
||||||
workingDir: var_workingDir,
|
workingDir: var_workingDir,
|
||||||
network: var_network,
|
network: var_network,
|
||||||
paymentTimeoutSec: var_paymentTimeoutSec,
|
paymentTimeoutSec: var_paymentTimeoutSec,
|
||||||
@@ -1271,6 +1392,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return LiquidSdkError_Generic(err: var_err);
|
return LiquidSdkError_Generic(err: var_err);
|
||||||
case 2:
|
case 2:
|
||||||
return LiquidSdkError_NotStarted();
|
return LiquidSdkError_NotStarted();
|
||||||
|
case 3:
|
||||||
|
var var_err = sse_decode_String(deserializer);
|
||||||
|
return LiquidSdkError_ServiceConnectivity(err: var_err);
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError('');
|
throw UnimplementedError('');
|
||||||
}
|
}
|
||||||
@@ -1417,6 +1541,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_address = sse_decode_String(deserializer);
|
||||||
|
var var_prepareRes = sse_decode_prepare_pay_onchain_response(deserializer);
|
||||||
|
return PayOnchainRequest(address: var_address, prepareRes: var_prepareRes);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment sse_decode_payment(SseDeserializer deserializer) {
|
Payment sse_decode_payment(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -1514,6 +1646,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return PaymentType.values[inner];
|
return PaymentType.values[inner];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest sse_decode_prepare_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_amountSat = sse_decode_u_64(deserializer);
|
||||||
|
return PreparePayOnchainRequest(amountSat: var_amountSat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainResponse sse_decode_prepare_pay_onchain_response(SseDeserializer deserializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
var var_amountSat = sse_decode_u_64(deserializer);
|
||||||
|
var var_feesSat = sse_decode_u_64(deserializer);
|
||||||
|
return PreparePayOnchainResponse(amountSat: var_amountSat, feesSat: var_feesSat);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest sse_decode_prepare_receive_request(SseDeserializer deserializer) {
|
PrepareReceiveRequest sse_decode_prepare_receive_request(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -1788,12 +1935,25 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
sse_encode_liquid_sdk_event(self, serializer);
|
sse_encode_liquid_sdk_event(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_pay_onchain_request(self, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_payment(Payment self, SseSerializer serializer) {
|
void sse_encode_box_autoadd_payment(Payment self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
sse_encode_payment(self, serializer);
|
sse_encode_payment(self, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_prepare_pay_onchain_request(
|
||||||
|
PreparePayOnchainRequest self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_prepare_pay_onchain_request(self, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer) {
|
void sse_encode_box_autoadd_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -1835,7 +1995,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
void sse_encode_config(Config self, SseSerializer serializer) {
|
void sse_encode_config(Config self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
sse_encode_String(self.boltzUrl, serializer);
|
sse_encode_String(self.boltzUrl, serializer);
|
||||||
sse_encode_String(self.electrumUrl, serializer);
|
sse_encode_String(self.liquidElectrumUrl, serializer);
|
||||||
|
sse_encode_String(self.bitcoinElectrumUrl, serializer);
|
||||||
sse_encode_String(self.workingDir, serializer);
|
sse_encode_String(self.workingDir, serializer);
|
||||||
sse_encode_network(self.network, serializer);
|
sse_encode_network(self.network, serializer);
|
||||||
sse_encode_u_64(self.paymentTimeoutSec, serializer);
|
sse_encode_u_64(self.paymentTimeoutSec, serializer);
|
||||||
@@ -1882,6 +2043,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
sse_encode_String(err, serializer);
|
sse_encode_String(err, serializer);
|
||||||
case LiquidSdkError_NotStarted():
|
case LiquidSdkError_NotStarted():
|
||||||
sse_encode_i_32(2, serializer);
|
sse_encode_i_32(2, serializer);
|
||||||
|
case LiquidSdkError_ServiceConnectivity(err: final err):
|
||||||
|
sse_encode_i_32(3, serializer);
|
||||||
|
sse_encode_String(err, serializer);
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError('');
|
throw UnimplementedError('');
|
||||||
}
|
}
|
||||||
@@ -2000,6 +2164,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_String(self.address, serializer);
|
||||||
|
sse_encode_prepare_pay_onchain_response(self.prepareRes, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_payment(Payment self, SseSerializer serializer) {
|
void sse_encode_payment(Payment self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -2081,6 +2252,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
sse_encode_i_32(self.index, serializer);
|
sse_encode_i_32(self.index, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_prepare_pay_onchain_request(PreparePayOnchainRequest self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_64(self.amountSat, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_prepare_pay_onchain_response(PreparePayOnchainResponse self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
sse_encode_u_64(self.amountSat, serializer);
|
||||||
|
sse_encode_u_64(self.feesSat, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer) {
|
void sse_encode_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -2220,6 +2404,12 @@ class BindingLiquidSdkImpl extends RustOpaque implements BindingLiquidSdk {
|
|||||||
that: this,
|
that: this,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<SendPaymentResponse> payOnchain({required PayOnchainRequest req}) =>
|
||||||
|
RustLib.instance.api.crateBindingsBindingLiquidSdkPayOnchain(that: this, req: req);
|
||||||
|
|
||||||
|
Future<PreparePayOnchainResponse> preparePayOnchain({required PreparePayOnchainRequest req}) =>
|
||||||
|
RustLib.instance.api.crateBindingsBindingLiquidSdkPreparePayOnchain(that: this, req: req);
|
||||||
|
|
||||||
Future<PrepareReceiveResponse> prepareReceivePayment({required PrepareReceiveRequest req}) =>
|
Future<PrepareReceiveResponse> prepareReceivePayment({required PrepareReceiveRequest req}) =>
|
||||||
RustLib.instance.api.crateBindingsBindingLiquidSdkPrepareReceivePayment(that: this, req: req);
|
RustLib.instance.api.crateBindingsBindingLiquidSdkPrepareReceivePayment(that: this, req: req);
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
LiquidSdkEvent dco_decode_box_autoadd_liquid_sdk_event(dynamic raw);
|
LiquidSdkEvent dco_decode_box_autoadd_liquid_sdk_event(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest dco_decode_box_autoadd_pay_onchain_request(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment dco_decode_box_autoadd_payment(dynamic raw);
|
Payment dco_decode_box_autoadd_payment(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest dco_decode_box_autoadd_prepare_pay_onchain_request(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest dco_decode_box_autoadd_prepare_receive_request(dynamic raw);
|
PrepareReceiveRequest dco_decode_box_autoadd_prepare_receive_request(dynamic raw);
|
||||||
|
|
||||||
@@ -136,6 +142,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt? dco_decode_opt_box_autoadd_u_64(dynamic raw);
|
BigInt? dco_decode_opt_box_autoadd_u_64(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment dco_decode_payment(dynamic raw);
|
Payment dco_decode_payment(dynamic raw);
|
||||||
|
|
||||||
@@ -148,6 +157,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
PaymentType dco_decode_payment_type(dynamic raw);
|
PaymentType dco_decode_payment_type(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest dco_decode_prepare_pay_onchain_request(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainResponse dco_decode_prepare_pay_onchain_response(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest dco_decode_prepare_receive_request(dynamic raw);
|
PrepareReceiveRequest dco_decode_prepare_receive_request(dynamic raw);
|
||||||
|
|
||||||
@@ -234,9 +249,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
LiquidSdkEvent sse_decode_box_autoadd_liquid_sdk_event(SseDeserializer deserializer);
|
LiquidSdkEvent sse_decode_box_autoadd_liquid_sdk_event(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest sse_decode_box_autoadd_pay_onchain_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment sse_decode_box_autoadd_payment(SseDeserializer deserializer);
|
Payment sse_decode_box_autoadd_payment(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest sse_decode_box_autoadd_prepare_pay_onchain_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest sse_decode_box_autoadd_prepare_receive_request(SseDeserializer deserializer);
|
PrepareReceiveRequest sse_decode_box_autoadd_prepare_receive_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@@ -303,6 +324,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
BigInt? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
|
BigInt? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
Payment sse_decode_payment(SseDeserializer deserializer);
|
Payment sse_decode_payment(SseDeserializer deserializer);
|
||||||
|
|
||||||
@@ -315,6 +339,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
PaymentType sse_decode_payment_type(SseDeserializer deserializer);
|
PaymentType sse_decode_payment_type(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainRequest sse_decode_prepare_pay_onchain_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PreparePayOnchainResponse sse_decode_prepare_pay_onchain_response(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PrepareReceiveRequest sse_decode_prepare_receive_request(SseDeserializer deserializer);
|
PrepareReceiveRequest sse_decode_prepare_receive_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@@ -421,6 +451,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_pay_onchain_request> cst_encode_box_autoadd_pay_onchain_request(
|
||||||
|
PayOnchainRequest raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
final ptr = wire.cst_new_box_autoadd_pay_onchain_request();
|
||||||
|
cst_api_fill_to_wire_pay_onchain_request(raw, ptr.ref);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_payment> cst_encode_box_autoadd_payment(Payment raw) {
|
ffi.Pointer<wire_cst_payment> cst_encode_box_autoadd_payment(Payment raw) {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
@@ -429,6 +468,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
ffi.Pointer<wire_cst_prepare_pay_onchain_request> cst_encode_box_autoadd_prepare_pay_onchain_request(
|
||||||
|
PreparePayOnchainRequest raw) {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
final ptr = wire.cst_new_box_autoadd_prepare_pay_onchain_request();
|
||||||
|
cst_api_fill_to_wire_prepare_pay_onchain_request(raw, ptr.ref);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
ffi.Pointer<wire_cst_prepare_receive_request> cst_encode_box_autoadd_prepare_receive_request(
|
ffi.Pointer<wire_cst_prepare_receive_request> cst_encode_box_autoadd_prepare_receive_request(
|
||||||
PrepareReceiveRequest raw) {
|
PrepareReceiveRequest raw) {
|
||||||
@@ -576,11 +624,23 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
cst_api_fill_to_wire_liquid_sdk_event(apiObj, wireObj.ref);
|
cst_api_fill_to_wire_liquid_sdk_event(apiObj, wireObj.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_box_autoadd_pay_onchain_request(
|
||||||
|
PayOnchainRequest apiObj, ffi.Pointer<wire_cst_pay_onchain_request> wireObj) {
|
||||||
|
cst_api_fill_to_wire_pay_onchain_request(apiObj, wireObj.ref);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_box_autoadd_payment(Payment apiObj, ffi.Pointer<wire_cst_payment> wireObj) {
|
void cst_api_fill_to_wire_box_autoadd_payment(Payment apiObj, ffi.Pointer<wire_cst_payment> wireObj) {
|
||||||
cst_api_fill_to_wire_payment(apiObj, wireObj.ref);
|
cst_api_fill_to_wire_payment(apiObj, wireObj.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_box_autoadd_prepare_pay_onchain_request(
|
||||||
|
PreparePayOnchainRequest apiObj, ffi.Pointer<wire_cst_prepare_pay_onchain_request> wireObj) {
|
||||||
|
cst_api_fill_to_wire_prepare_pay_onchain_request(apiObj, wireObj.ref);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_box_autoadd_prepare_receive_request(
|
void cst_api_fill_to_wire_box_autoadd_prepare_receive_request(
|
||||||
PrepareReceiveRequest apiObj, ffi.Pointer<wire_cst_prepare_receive_request> wireObj) {
|
PrepareReceiveRequest apiObj, ffi.Pointer<wire_cst_prepare_receive_request> wireObj) {
|
||||||
@@ -614,7 +674,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_config(Config apiObj, wire_cst_config wireObj) {
|
void cst_api_fill_to_wire_config(Config apiObj, wire_cst_config wireObj) {
|
||||||
wireObj.boltz_url = cst_encode_String(apiObj.boltzUrl);
|
wireObj.boltz_url = cst_encode_String(apiObj.boltzUrl);
|
||||||
wireObj.electrum_url = cst_encode_String(apiObj.electrumUrl);
|
wireObj.liquid_electrum_url = cst_encode_String(apiObj.liquidElectrumUrl);
|
||||||
|
wireObj.bitcoin_electrum_url = cst_encode_String(apiObj.bitcoinElectrumUrl);
|
||||||
wireObj.working_dir = cst_encode_String(apiObj.workingDir);
|
wireObj.working_dir = cst_encode_String(apiObj.workingDir);
|
||||||
wireObj.network = cst_encode_network(apiObj.network);
|
wireObj.network = cst_encode_network(apiObj.network);
|
||||||
wireObj.payment_timeout_sec = cst_encode_u_64(apiObj.paymentTimeoutSec);
|
wireObj.payment_timeout_sec = cst_encode_u_64(apiObj.paymentTimeoutSec);
|
||||||
@@ -652,6 +713,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
wireObj.tag = 2;
|
wireObj.tag = 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (apiObj is LiquidSdkError_ServiceConnectivity) {
|
||||||
|
var pre_err = cst_encode_String(apiObj.err);
|
||||||
|
wireObj.tag = 3;
|
||||||
|
wireObj.kind.ServiceConnectivity.err = pre_err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
@@ -720,6 +787,13 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
wireObj.level = cst_encode_String(apiObj.level);
|
wireObj.level = cst_encode_String(apiObj.level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_pay_onchain_request(
|
||||||
|
PayOnchainRequest apiObj, wire_cst_pay_onchain_request wireObj) {
|
||||||
|
wireObj.address = cst_encode_String(apiObj.address);
|
||||||
|
cst_api_fill_to_wire_prepare_pay_onchain_response(apiObj.prepareRes, wireObj.prepare_res);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_payment(Payment apiObj, wire_cst_payment wireObj) {
|
void cst_api_fill_to_wire_payment(Payment apiObj, wire_cst_payment wireObj) {
|
||||||
wireObj.tx_id = cst_encode_opt_String(apiObj.txId);
|
wireObj.tx_id = cst_encode_opt_String(apiObj.txId);
|
||||||
@@ -827,6 +901,19 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_prepare_pay_onchain_request(
|
||||||
|
PreparePayOnchainRequest apiObj, wire_cst_prepare_pay_onchain_request wireObj) {
|
||||||
|
wireObj.amount_sat = cst_encode_u_64(apiObj.amountSat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_prepare_pay_onchain_response(
|
||||||
|
PreparePayOnchainResponse apiObj, wire_cst_prepare_pay_onchain_response wireObj) {
|
||||||
|
wireObj.amount_sat = cst_encode_u_64(apiObj.amountSat);
|
||||||
|
wireObj.fees_sat = cst_encode_u_64(apiObj.feesSat);
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_prepare_receive_request(
|
void cst_api_fill_to_wire_prepare_receive_request(
|
||||||
PrepareReceiveRequest apiObj, wire_cst_prepare_receive_request wireObj) {
|
PrepareReceiveRequest apiObj, wire_cst_prepare_receive_request wireObj) {
|
||||||
@@ -966,9 +1053,16 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_liquid_sdk_event(LiquidSdkEvent self, SseSerializer serializer);
|
void sse_encode_box_autoadd_liquid_sdk_event(LiquidSdkEvent self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_payment(Payment self, SseSerializer serializer);
|
void sse_encode_box_autoadd_payment(Payment self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_box_autoadd_prepare_pay_onchain_request(
|
||||||
|
PreparePayOnchainRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_box_autoadd_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer);
|
void sse_encode_box_autoadd_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@@ -1035,6 +1129,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_box_autoadd_u_64(BigInt? self, SseSerializer serializer);
|
void sse_encode_opt_box_autoadd_u_64(BigInt? self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_payment(Payment self, SseSerializer serializer);
|
void sse_encode_payment(Payment self, SseSerializer serializer);
|
||||||
|
|
||||||
@@ -1047,6 +1144,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_payment_type(PaymentType self, SseSerializer serializer);
|
void sse_encode_payment_type(PaymentType self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_prepare_pay_onchain_request(PreparePayOnchainRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_prepare_pay_onchain_response(PreparePayOnchainResponse self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer);
|
void sse_encode_prepare_receive_request(PrepareReceiveRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@@ -1229,6 +1332,46 @@ class RustLibWire implements BaseWire {
|
|||||||
late final _wire__crate__bindings__BindingLiquidSdk_list_payments =
|
late final _wire__crate__bindings__BindingLiquidSdk_list_payments =
|
||||||
_wire__crate__bindings__BindingLiquidSdk_list_paymentsPtr.asFunction<void Function(int, int)>();
|
_wire__crate__bindings__BindingLiquidSdk_list_paymentsPtr.asFunction<void Function(int, int)>();
|
||||||
|
|
||||||
|
void wire__crate__bindings__BindingLiquidSdk_pay_onchain(
|
||||||
|
int port_,
|
||||||
|
int that,
|
||||||
|
ffi.Pointer<wire_cst_pay_onchain_request> req,
|
||||||
|
) {
|
||||||
|
return _wire__crate__bindings__BindingLiquidSdk_pay_onchain(
|
||||||
|
port_,
|
||||||
|
that,
|
||||||
|
req,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__bindings__BindingLiquidSdk_pay_onchainPtr = _lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_pay_onchain_request>)>>(
|
||||||
|
'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain');
|
||||||
|
late final _wire__crate__bindings__BindingLiquidSdk_pay_onchain =
|
||||||
|
_wire__crate__bindings__BindingLiquidSdk_pay_onchainPtr
|
||||||
|
.asFunction<void Function(int, int, ffi.Pointer<wire_cst_pay_onchain_request>)>();
|
||||||
|
|
||||||
|
void wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(
|
||||||
|
int port_,
|
||||||
|
int that,
|
||||||
|
ffi.Pointer<wire_cst_prepare_pay_onchain_request> req,
|
||||||
|
) {
|
||||||
|
return _wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(
|
||||||
|
port_,
|
||||||
|
that,
|
||||||
|
req,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchainPtr = _lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_prepare_pay_onchain_request>)>>(
|
||||||
|
'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain');
|
||||||
|
late final _wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain =
|
||||||
|
_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchainPtr
|
||||||
|
.asFunction<void Function(int, int, ffi.Pointer<wire_cst_prepare_pay_onchain_request>)>();
|
||||||
|
|
||||||
void wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
void wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
||||||
int port_,
|
int port_,
|
||||||
int that,
|
int that,
|
||||||
@@ -1497,6 +1640,16 @@ class RustLibWire implements BaseWire {
|
|||||||
late final _cst_new_box_autoadd_liquid_sdk_event = _cst_new_box_autoadd_liquid_sdk_eventPtr
|
late final _cst_new_box_autoadd_liquid_sdk_event = _cst_new_box_autoadd_liquid_sdk_eventPtr
|
||||||
.asFunction<ffi.Pointer<wire_cst_liquid_sdk_event> Function()>();
|
.asFunction<ffi.Pointer<wire_cst_liquid_sdk_event> Function()>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_pay_onchain_request> cst_new_box_autoadd_pay_onchain_request() {
|
||||||
|
return _cst_new_box_autoadd_pay_onchain_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _cst_new_box_autoadd_pay_onchain_requestPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Pointer<wire_cst_pay_onchain_request> Function()>>(
|
||||||
|
'frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request');
|
||||||
|
late final _cst_new_box_autoadd_pay_onchain_request = _cst_new_box_autoadd_pay_onchain_requestPtr
|
||||||
|
.asFunction<ffi.Pointer<wire_cst_pay_onchain_request> Function()>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_payment> cst_new_box_autoadd_payment() {
|
ffi.Pointer<wire_cst_payment> cst_new_box_autoadd_payment() {
|
||||||
return _cst_new_box_autoadd_payment();
|
return _cst_new_box_autoadd_payment();
|
||||||
}
|
}
|
||||||
@@ -1507,6 +1660,17 @@ class RustLibWire implements BaseWire {
|
|||||||
late final _cst_new_box_autoadd_payment =
|
late final _cst_new_box_autoadd_payment =
|
||||||
_cst_new_box_autoadd_paymentPtr.asFunction<ffi.Pointer<wire_cst_payment> Function()>();
|
_cst_new_box_autoadd_paymentPtr.asFunction<ffi.Pointer<wire_cst_payment> Function()>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_prepare_pay_onchain_request> cst_new_box_autoadd_prepare_pay_onchain_request() {
|
||||||
|
return _cst_new_box_autoadd_prepare_pay_onchain_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _cst_new_box_autoadd_prepare_pay_onchain_requestPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Pointer<wire_cst_prepare_pay_onchain_request> Function()>>(
|
||||||
|
'frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request');
|
||||||
|
late final _cst_new_box_autoadd_prepare_pay_onchain_request =
|
||||||
|
_cst_new_box_autoadd_prepare_pay_onchain_requestPtr
|
||||||
|
.asFunction<ffi.Pointer<wire_cst_prepare_pay_onchain_request> Function()>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_prepare_receive_request> cst_new_box_autoadd_prepare_receive_request() {
|
ffi.Pointer<wire_cst_prepare_receive_request> cst_new_box_autoadd_prepare_receive_request() {
|
||||||
return _cst_new_box_autoadd_prepare_receive_request();
|
return _cst_new_box_autoadd_prepare_receive_request();
|
||||||
}
|
}
|
||||||
@@ -1652,6 +1816,25 @@ final class wire_cst_backup_request extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> backup_path;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> backup_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_response extends ffi.Struct {
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int amount_sat;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int fees_sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_pay_onchain_request extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> address;
|
||||||
|
|
||||||
|
external wire_cst_prepare_pay_onchain_response prepare_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int amount_sat;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_prepare_receive_request extends ffi.Struct {
|
final class wire_cst_prepare_receive_request extends ffi.Struct {
|
||||||
@ffi.Uint64()
|
@ffi.Uint64()
|
||||||
external int payer_amount_sat;
|
external int payer_amount_sat;
|
||||||
@@ -1761,7 +1944,9 @@ final class wire_cst_liquid_sdk_event extends ffi.Struct {
|
|||||||
final class wire_cst_config extends ffi.Struct {
|
final class wire_cst_config extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> boltz_url;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> boltz_url;
|
||||||
|
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> electrum_url;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> liquid_electrum_url;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> bitcoin_electrum_url;
|
||||||
|
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir;
|
||||||
|
|
||||||
@@ -1845,8 +2030,14 @@ final class wire_cst_LiquidSdkError_Generic extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_LiquidSdkError_ServiceConnectivity extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
||||||
|
}
|
||||||
|
|
||||||
final class LiquidSdkErrorKind extends ffi.Union {
|
final class LiquidSdkErrorKind extends ffi.Union {
|
||||||
external wire_cst_LiquidSdkError_Generic Generic;
|
external wire_cst_LiquidSdkError_Generic Generic;
|
||||||
|
|
||||||
|
external wire_cst_LiquidSdkError_ServiceConnectivity ServiceConnectivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_liquid_sdk_error extends ffi.Struct {
|
final class wire_cst_liquid_sdk_error extends ffi.Struct {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ class BackupRequest {
|
|||||||
/// Configuration for the Liquid SDK
|
/// Configuration for the Liquid SDK
|
||||||
class Config {
|
class Config {
|
||||||
final String boltzUrl;
|
final String boltzUrl;
|
||||||
final String electrumUrl;
|
final String liquidElectrumUrl;
|
||||||
|
final String bitcoinElectrumUrl;
|
||||||
|
|
||||||
/// Directory in which all SDK files (DB, log, cache) are stored.
|
/// Directory in which all SDK files (DB, log, cache) are stored.
|
||||||
///
|
///
|
||||||
@@ -51,7 +52,8 @@ class Config {
|
|||||||
|
|
||||||
const Config({
|
const Config({
|
||||||
required this.boltzUrl,
|
required this.boltzUrl,
|
||||||
required this.electrumUrl,
|
required this.liquidElectrumUrl,
|
||||||
|
required this.bitcoinElectrumUrl,
|
||||||
required this.workingDir,
|
required this.workingDir,
|
||||||
required this.network,
|
required this.network,
|
||||||
required this.paymentTimeoutSec,
|
required this.paymentTimeoutSec,
|
||||||
@@ -62,7 +64,8 @@ class Config {
|
|||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
boltzUrl.hashCode ^
|
boltzUrl.hashCode ^
|
||||||
electrumUrl.hashCode ^
|
liquidElectrumUrl.hashCode ^
|
||||||
|
bitcoinElectrumUrl.hashCode ^
|
||||||
workingDir.hashCode ^
|
workingDir.hashCode ^
|
||||||
network.hashCode ^
|
network.hashCode ^
|
||||||
paymentTimeoutSec.hashCode ^
|
paymentTimeoutSec.hashCode ^
|
||||||
@@ -75,7 +78,8 @@ class Config {
|
|||||||
other is Config &&
|
other is Config &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
boltzUrl == other.boltzUrl &&
|
boltzUrl == other.boltzUrl &&
|
||||||
electrumUrl == other.electrumUrl &&
|
liquidElectrumUrl == other.liquidElectrumUrl &&
|
||||||
|
bitcoinElectrumUrl == other.bitcoinElectrumUrl &&
|
||||||
workingDir == other.workingDir &&
|
workingDir == other.workingDir &&
|
||||||
network == other.network &&
|
network == other.network &&
|
||||||
paymentTimeoutSec == other.paymentTimeoutSec &&
|
paymentTimeoutSec == other.paymentTimeoutSec &&
|
||||||
@@ -254,6 +258,27 @@ enum Network {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PayOnchainRequest {
|
||||||
|
final String address;
|
||||||
|
final PreparePayOnchainResponse prepareRes;
|
||||||
|
|
||||||
|
const PayOnchainRequest({
|
||||||
|
required this.address,
|
||||||
|
required this.prepareRes,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => address.hashCode ^ prepareRes.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is PayOnchainRequest &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
address == other.address &&
|
||||||
|
prepareRes == other.prepareRes;
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents an SDK payment.
|
/// Represents an SDK payment.
|
||||||
///
|
///
|
||||||
/// By default, this is an onchain tx. It may represent a swap, if swap metadata is available.
|
/// By default, this is an onchain tx. It may represent a swap, if swap metadata is available.
|
||||||
@@ -418,6 +443,43 @@ enum PaymentType {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PreparePayOnchainRequest {
|
||||||
|
final BigInt amountSat;
|
||||||
|
|
||||||
|
const PreparePayOnchainRequest({
|
||||||
|
required this.amountSat,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => amountSat.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is PreparePayOnchainRequest && runtimeType == other.runtimeType && amountSat == other.amountSat;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PreparePayOnchainResponse {
|
||||||
|
final BigInt amountSat;
|
||||||
|
final BigInt feesSat;
|
||||||
|
|
||||||
|
const PreparePayOnchainResponse({
|
||||||
|
required this.amountSat,
|
||||||
|
required this.feesSat,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => amountSat.hashCode ^ feesSat.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is PreparePayOnchainResponse &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
amountSat == other.amountSat &&
|
||||||
|
feesSat == other.feesSat;
|
||||||
|
}
|
||||||
|
|
||||||
class PrepareReceiveRequest {
|
class PrepareReceiveRequest {
|
||||||
final BigInt payerAmountSat;
|
final BigInt payerAmountSat;
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,46 @@ class FlutterBreezLiquidBindings {
|
|||||||
_frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_paymentsPtr
|
_frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_list_paymentsPtr
|
||||||
.asFunction<void Function(int, int)>();
|
.asFunction<void Function(int, int)>();
|
||||||
|
|
||||||
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(
|
||||||
|
int port_,
|
||||||
|
int that,
|
||||||
|
ffi.Pointer<wire_cst_pay_onchain_request> req,
|
||||||
|
) {
|
||||||
|
return _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(
|
||||||
|
port_,
|
||||||
|
that,
|
||||||
|
req,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchainPtr = _lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_pay_onchain_request>)>>(
|
||||||
|
'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain');
|
||||||
|
late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain =
|
||||||
|
_frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchainPtr
|
||||||
|
.asFunction<void Function(int, int, ffi.Pointer<wire_cst_pay_onchain_request>)>();
|
||||||
|
|
||||||
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(
|
||||||
|
int port_,
|
||||||
|
int that,
|
||||||
|
ffi.Pointer<wire_cst_prepare_pay_onchain_request> req,
|
||||||
|
) {
|
||||||
|
return _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain(
|
||||||
|
port_,
|
||||||
|
that,
|
||||||
|
req,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchainPtr = _lookup<
|
||||||
|
ffi.NativeFunction<
|
||||||
|
ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_prepare_pay_onchain_request>)>>(
|
||||||
|
'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain');
|
||||||
|
late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchain =
|
||||||
|
_frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_pay_onchainPtr
|
||||||
|
.asFunction<void Function(int, int, ffi.Pointer<wire_cst_prepare_pay_onchain_request>)>();
|
||||||
|
|
||||||
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_receive_payment(
|
||||||
int port_,
|
int port_,
|
||||||
int that,
|
int that,
|
||||||
@@ -420,6 +460,17 @@ class FlutterBreezLiquidBindings {
|
|||||||
_frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_eventPtr
|
_frbgen_breez_liquid_cst_new_box_autoadd_liquid_sdk_eventPtr
|
||||||
.asFunction<ffi.Pointer<wire_cst_liquid_sdk_event> Function()>();
|
.asFunction<ffi.Pointer<wire_cst_liquid_sdk_event> Function()>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_pay_onchain_request> frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request() {
|
||||||
|
return _frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_requestPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Pointer<wire_cst_pay_onchain_request> Function()>>(
|
||||||
|
'frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request');
|
||||||
|
late final _frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request =
|
||||||
|
_frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_requestPtr
|
||||||
|
.asFunction<ffi.Pointer<wire_cst_pay_onchain_request> Function()>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_payment> frbgen_breez_liquid_cst_new_box_autoadd_payment() {
|
ffi.Pointer<wire_cst_payment> frbgen_breez_liquid_cst_new_box_autoadd_payment() {
|
||||||
return _frbgen_breez_liquid_cst_new_box_autoadd_payment();
|
return _frbgen_breez_liquid_cst_new_box_autoadd_payment();
|
||||||
}
|
}
|
||||||
@@ -431,6 +482,18 @@ class FlutterBreezLiquidBindings {
|
|||||||
_frbgen_breez_liquid_cst_new_box_autoadd_paymentPtr
|
_frbgen_breez_liquid_cst_new_box_autoadd_paymentPtr
|
||||||
.asFunction<ffi.Pointer<wire_cst_payment> Function()>();
|
.asFunction<ffi.Pointer<wire_cst_payment> Function()>();
|
||||||
|
|
||||||
|
ffi.Pointer<wire_cst_prepare_pay_onchain_request>
|
||||||
|
frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request() {
|
||||||
|
return _frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_requestPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Pointer<wire_cst_prepare_pay_onchain_request> Function()>>(
|
||||||
|
'frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request');
|
||||||
|
late final _frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_request =
|
||||||
|
_frbgen_breez_liquid_cst_new_box_autoadd_prepare_pay_onchain_requestPtr
|
||||||
|
.asFunction<ffi.Pointer<wire_cst_prepare_pay_onchain_request> Function()>();
|
||||||
|
|
||||||
ffi.Pointer<wire_cst_prepare_receive_request>
|
ffi.Pointer<wire_cst_prepare_receive_request>
|
||||||
frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request() {
|
frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request() {
|
||||||
return _frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request();
|
return _frbgen_breez_liquid_cst_new_box_autoadd_prepare_receive_request();
|
||||||
@@ -600,6 +663,25 @@ final class wire_cst_backup_request extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> backup_path;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> backup_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_response extends ffi.Struct {
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int amount_sat;
|
||||||
|
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int fees_sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_pay_onchain_request extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> address;
|
||||||
|
|
||||||
|
external wire_cst_prepare_pay_onchain_response prepare_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
||||||
|
@ffi.Uint64()
|
||||||
|
external int amount_sat;
|
||||||
|
}
|
||||||
|
|
||||||
final class wire_cst_prepare_receive_request extends ffi.Struct {
|
final class wire_cst_prepare_receive_request extends ffi.Struct {
|
||||||
@ffi.Uint64()
|
@ffi.Uint64()
|
||||||
external int payer_amount_sat;
|
external int payer_amount_sat;
|
||||||
@@ -709,7 +791,9 @@ final class wire_cst_liquid_sdk_event extends ffi.Struct {
|
|||||||
final class wire_cst_config extends ffi.Struct {
|
final class wire_cst_config extends ffi.Struct {
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> boltz_url;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> boltz_url;
|
||||||
|
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> electrum_url;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> liquid_electrum_url;
|
||||||
|
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> bitcoin_electrum_url;
|
||||||
|
|
||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> working_dir;
|
||||||
|
|
||||||
@@ -793,8 +877,14 @@ final class wire_cst_LiquidSdkError_Generic extends ffi.Struct {
|
|||||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class wire_cst_LiquidSdkError_ServiceConnectivity extends ffi.Struct {
|
||||||
|
external ffi.Pointer<wire_cst_list_prim_u_8_strict> err;
|
||||||
|
}
|
||||||
|
|
||||||
final class LiquidSdkErrorKind extends ffi.Union {
|
final class LiquidSdkErrorKind extends ffi.Union {
|
||||||
external wire_cst_LiquidSdkError_Generic Generic;
|
external wire_cst_LiquidSdkError_Generic Generic;
|
||||||
|
|
||||||
|
external wire_cst_LiquidSdkError_ServiceConnectivity ServiceConnectivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_liquid_sdk_error extends ffi.Struct {
|
final class wire_cst_liquid_sdk_error extends ffi.Struct {
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ fun asConfig(config: ReadableMap): Config? {
|
|||||||
config,
|
config,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
"boltzUrl",
|
"boltzUrl",
|
||||||
"electrumUrl",
|
"liquidElectrumUrl",
|
||||||
|
"bitcoinElectrumUrl",
|
||||||
"workingDir",
|
"workingDir",
|
||||||
"network",
|
"network",
|
||||||
"paymentTimeoutSec",
|
"paymentTimeoutSec",
|
||||||
@@ -49,7 +50,8 @@ fun asConfig(config: ReadableMap): Config? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val boltzUrl = config.getString("boltzUrl")!!
|
val boltzUrl = config.getString("boltzUrl")!!
|
||||||
val electrumUrl = config.getString("electrumUrl")!!
|
val liquidElectrumUrl = config.getString("liquidElectrumUrl")!!
|
||||||
|
val bitcoinElectrumUrl = config.getString("bitcoinElectrumUrl")!!
|
||||||
val workingDir = config.getString("workingDir")!!
|
val workingDir = config.getString("workingDir")!!
|
||||||
val network = config.getString("network")?.let { asNetwork(it) }!!
|
val network = config.getString("network")?.let { asNetwork(it) }!!
|
||||||
val paymentTimeoutSec = config.getDouble("paymentTimeoutSec").toULong()
|
val paymentTimeoutSec = config.getDouble("paymentTimeoutSec").toULong()
|
||||||
@@ -66,7 +68,8 @@ fun asConfig(config: ReadableMap): Config? {
|
|||||||
}
|
}
|
||||||
return Config(
|
return Config(
|
||||||
boltzUrl,
|
boltzUrl,
|
||||||
electrumUrl,
|
liquidElectrumUrl,
|
||||||
|
bitcoinElectrumUrl,
|
||||||
workingDir,
|
workingDir,
|
||||||
network,
|
network,
|
||||||
paymentTimeoutSec,
|
paymentTimeoutSec,
|
||||||
@@ -78,7 +81,8 @@ fun asConfig(config: ReadableMap): Config? {
|
|||||||
fun readableMapOf(config: Config): ReadableMap =
|
fun readableMapOf(config: Config): ReadableMap =
|
||||||
readableMapOf(
|
readableMapOf(
|
||||||
"boltzUrl" to config.boltzUrl,
|
"boltzUrl" to config.boltzUrl,
|
||||||
"electrumUrl" to config.electrumUrl,
|
"liquidElectrumUrl" to config.liquidElectrumUrl,
|
||||||
|
"bitcoinElectrumUrl" to config.bitcoinElectrumUrl,
|
||||||
"workingDir" to config.workingDir,
|
"workingDir" to config.workingDir,
|
||||||
"network" to config.network.name.lowercase(),
|
"network" to config.network.name.lowercase(),
|
||||||
"paymentTimeoutSec" to config.paymentTimeoutSec,
|
"paymentTimeoutSec" to config.paymentTimeoutSec,
|
||||||
@@ -286,6 +290,42 @@ fun asLogEntryList(arr: ReadableArray): List<LogEntry> {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asPayOnchainRequest(payOnchainRequest: ReadableMap): PayOnchainRequest? {
|
||||||
|
if (!validateMandatoryFields(
|
||||||
|
payOnchainRequest,
|
||||||
|
arrayOf(
|
||||||
|
"address",
|
||||||
|
"prepareRes",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val address = payOnchainRequest.getString("address")!!
|
||||||
|
val prepareRes = payOnchainRequest.getMap("prepareRes")?.let { asPreparePayOnchainResponse(it) }!!
|
||||||
|
return PayOnchainRequest(
|
||||||
|
address,
|
||||||
|
prepareRes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readableMapOf(payOnchainRequest: PayOnchainRequest): ReadableMap =
|
||||||
|
readableMapOf(
|
||||||
|
"address" to payOnchainRequest.address,
|
||||||
|
"prepareRes" to readableMapOf(payOnchainRequest.prepareRes),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun asPayOnchainRequestList(arr: ReadableArray): List<PayOnchainRequest> {
|
||||||
|
val list = ArrayList<PayOnchainRequest>()
|
||||||
|
for (value in arr.toArrayList()) {
|
||||||
|
when (value) {
|
||||||
|
is ReadableMap -> list.add(asPayOnchainRequest(value)!!)
|
||||||
|
else -> throw LiquidSdkException.Generic(errUnexpectedType("${value::class.java.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
fun asPayment(payment: ReadableMap): Payment? {
|
fun asPayment(payment: ReadableMap): Payment? {
|
||||||
if (!validateMandatoryFields(
|
if (!validateMandatoryFields(
|
||||||
payment,
|
payment,
|
||||||
@@ -352,6 +392,74 @@ fun asPaymentList(arr: ReadableArray): List<Payment> {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asPreparePayOnchainRequest(preparePayOnchainRequest: ReadableMap): PreparePayOnchainRequest? {
|
||||||
|
if (!validateMandatoryFields(
|
||||||
|
preparePayOnchainRequest,
|
||||||
|
arrayOf(
|
||||||
|
"amountSat",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val amountSat = preparePayOnchainRequest.getDouble("amountSat").toULong()
|
||||||
|
return PreparePayOnchainRequest(
|
||||||
|
amountSat,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readableMapOf(preparePayOnchainRequest: PreparePayOnchainRequest): ReadableMap =
|
||||||
|
readableMapOf(
|
||||||
|
"amountSat" to preparePayOnchainRequest.amountSat,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun asPreparePayOnchainRequestList(arr: ReadableArray): List<PreparePayOnchainRequest> {
|
||||||
|
val list = ArrayList<PreparePayOnchainRequest>()
|
||||||
|
for (value in arr.toArrayList()) {
|
||||||
|
when (value) {
|
||||||
|
is ReadableMap -> list.add(asPreparePayOnchainRequest(value)!!)
|
||||||
|
else -> throw LiquidSdkException.Generic(errUnexpectedType("${value::class.java.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asPreparePayOnchainResponse(preparePayOnchainResponse: ReadableMap): PreparePayOnchainResponse? {
|
||||||
|
if (!validateMandatoryFields(
|
||||||
|
preparePayOnchainResponse,
|
||||||
|
arrayOf(
|
||||||
|
"amountSat",
|
||||||
|
"feesSat",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val amountSat = preparePayOnchainResponse.getDouble("amountSat").toULong()
|
||||||
|
val feesSat = preparePayOnchainResponse.getDouble("feesSat").toULong()
|
||||||
|
return PreparePayOnchainResponse(
|
||||||
|
amountSat,
|
||||||
|
feesSat,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readableMapOf(preparePayOnchainResponse: PreparePayOnchainResponse): ReadableMap =
|
||||||
|
readableMapOf(
|
||||||
|
"amountSat" to preparePayOnchainResponse.amountSat,
|
||||||
|
"feesSat" to preparePayOnchainResponse.feesSat,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun asPreparePayOnchainResponseList(arr: ReadableArray): List<PreparePayOnchainResponse> {
|
||||||
|
val list = ArrayList<PreparePayOnchainResponse>()
|
||||||
|
for (value in arr.toArrayList()) {
|
||||||
|
when (value) {
|
||||||
|
is ReadableMap -> list.add(asPreparePayOnchainResponse(value)!!)
|
||||||
|
else -> throw LiquidSdkException.Generic(errUnexpectedType("${value::class.java.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
fun asPrepareReceiveRequest(prepareReceiveRequest: ReadableMap): PrepareReceiveRequest? {
|
fun asPrepareReceiveRequest(prepareReceiveRequest: ReadableMap): PrepareReceiveRequest? {
|
||||||
if (!validateMandatoryFields(
|
if (!validateMandatoryFields(
|
||||||
prepareReceiveRequest,
|
prepareReceiveRequest,
|
||||||
|
|||||||
@@ -243,6 +243,42 @@ class BreezLiquidSDKModule(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
fun preparePayOnchain(
|
||||||
|
req: ReadableMap,
|
||||||
|
promise: Promise,
|
||||||
|
) {
|
||||||
|
executor.execute {
|
||||||
|
try {
|
||||||
|
val preparePayOnchainRequest =
|
||||||
|
asPreparePayOnchainRequest(req)
|
||||||
|
?: run { throw LiquidSdkException.Generic(errMissingMandatoryField("req", "PreparePayOnchainRequest")) }
|
||||||
|
val res = getBindingLiquidSdk().preparePayOnchain(preparePayOnchainRequest)
|
||||||
|
promise.resolve(readableMapOf(res))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
promise.reject(e.javaClass.simpleName.replace("Exception", "Error"), e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
fun payOnchain(
|
||||||
|
req: ReadableMap,
|
||||||
|
promise: Promise,
|
||||||
|
) {
|
||||||
|
executor.execute {
|
||||||
|
try {
|
||||||
|
val payOnchainRequest =
|
||||||
|
asPayOnchainRequest(req)
|
||||||
|
?: run { throw LiquidSdkException.Generic(errMissingMandatoryField("req", "PayOnchainRequest")) }
|
||||||
|
val res = getBindingLiquidSdk().payOnchain(payOnchainRequest)
|
||||||
|
promise.resolve(readableMapOf(res))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
promise.reject(e.javaClass.simpleName.replace("Exception", "Error"), e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
fun listPayments(promise: Promise) {
|
fun listPayments(promise: Promise) {
|
||||||
executor.execute {
|
executor.execute {
|
||||||
|
|||||||
@@ -42,8 +42,11 @@ enum BreezLiquidSDKMapper {
|
|||||||
guard let boltzUrl = config["boltzUrl"] as? String else {
|
guard let boltzUrl = config["boltzUrl"] as? String else {
|
||||||
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "boltzUrl", typeName: "Config"))
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "boltzUrl", typeName: "Config"))
|
||||||
}
|
}
|
||||||
guard let electrumUrl = config["electrumUrl"] as? String else {
|
guard let liquidElectrumUrl = config["liquidElectrumUrl"] as? String else {
|
||||||
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "electrumUrl", typeName: "Config"))
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "liquidElectrumUrl", typeName: "Config"))
|
||||||
|
}
|
||||||
|
guard let bitcoinElectrumUrl = config["bitcoinElectrumUrl"] as? String else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "bitcoinElectrumUrl", typeName: "Config"))
|
||||||
}
|
}
|
||||||
guard let workingDir = config["workingDir"] as? String else {
|
guard let workingDir = config["workingDir"] as? String else {
|
||||||
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "workingDir", typeName: "Config"))
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "workingDir", typeName: "Config"))
|
||||||
@@ -69,7 +72,8 @@ enum BreezLiquidSDKMapper {
|
|||||||
|
|
||||||
return Config(
|
return Config(
|
||||||
boltzUrl: boltzUrl,
|
boltzUrl: boltzUrl,
|
||||||
electrumUrl: electrumUrl,
|
liquidElectrumUrl: liquidElectrumUrl,
|
||||||
|
bitcoinElectrumUrl: bitcoinElectrumUrl,
|
||||||
workingDir: workingDir,
|
workingDir: workingDir,
|
||||||
network: network,
|
network: network,
|
||||||
paymentTimeoutSec: paymentTimeoutSec,
|
paymentTimeoutSec: paymentTimeoutSec,
|
||||||
@@ -81,7 +85,8 @@ enum BreezLiquidSDKMapper {
|
|||||||
static func dictionaryOf(config: Config) -> [String: Any?] {
|
static func dictionaryOf(config: Config) -> [String: Any?] {
|
||||||
return [
|
return [
|
||||||
"boltzUrl": config.boltzUrl,
|
"boltzUrl": config.boltzUrl,
|
||||||
"electrumUrl": config.electrumUrl,
|
"liquidElectrumUrl": config.liquidElectrumUrl,
|
||||||
|
"bitcoinElectrumUrl": config.bitcoinElectrumUrl,
|
||||||
"workingDir": config.workingDir,
|
"workingDir": config.workingDir,
|
||||||
"network": valueOf(network: config.network),
|
"network": valueOf(network: config.network),
|
||||||
"paymentTimeoutSec": config.paymentTimeoutSec,
|
"paymentTimeoutSec": config.paymentTimeoutSec,
|
||||||
@@ -337,6 +342,45 @@ enum BreezLiquidSDKMapper {
|
|||||||
return logEntryList.map { v -> [String: Any?] in dictionaryOf(logEntry: v) }
|
return logEntryList.map { v -> [String: Any?] in dictionaryOf(logEntry: v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func asPayOnchainRequest(payOnchainRequest: [String: Any?]) throws -> PayOnchainRequest {
|
||||||
|
guard let address = payOnchainRequest["address"] as? String else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "address", typeName: "PayOnchainRequest"))
|
||||||
|
}
|
||||||
|
guard let prepareResTmp = payOnchainRequest["prepareRes"] as? [String: Any?] else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "prepareRes", typeName: "PayOnchainRequest"))
|
||||||
|
}
|
||||||
|
let prepareRes = try asPreparePayOnchainResponse(preparePayOnchainResponse: prepareResTmp)
|
||||||
|
|
||||||
|
return PayOnchainRequest(
|
||||||
|
address: address,
|
||||||
|
prepareRes: prepareRes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func dictionaryOf(payOnchainRequest: PayOnchainRequest) -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"address": payOnchainRequest.address,
|
||||||
|
"prepareRes": dictionaryOf(preparePayOnchainResponse: payOnchainRequest.prepareRes),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func asPayOnchainRequestList(arr: [Any]) throws -> [PayOnchainRequest] {
|
||||||
|
var list = [PayOnchainRequest]()
|
||||||
|
for value in arr {
|
||||||
|
if let val = value as? [String: Any?] {
|
||||||
|
var payOnchainRequest = try asPayOnchainRequest(payOnchainRequest: val)
|
||||||
|
list.append(payOnchainRequest)
|
||||||
|
} else {
|
||||||
|
throw LiquidSdkError.Generic(message: errUnexpectedType(typeName: "PayOnchainRequest"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
static func arrayOf(payOnchainRequestList: [PayOnchainRequest]) -> [Any] {
|
||||||
|
return payOnchainRequestList.map { v -> [String: Any?] in dictionaryOf(payOnchainRequest: v) }
|
||||||
|
}
|
||||||
|
|
||||||
static func asPayment(payment: [String: Any?]) throws -> Payment {
|
static func asPayment(payment: [String: Any?]) throws -> Payment {
|
||||||
var txId: String?
|
var txId: String?
|
||||||
if hasNonNilKey(data: payment, key: "txId") {
|
if hasNonNilKey(data: payment, key: "txId") {
|
||||||
@@ -447,6 +491,76 @@ enum BreezLiquidSDKMapper {
|
|||||||
return paymentList.map { v -> [String: Any?] in dictionaryOf(payment: v) }
|
return paymentList.map { v -> [String: Any?] in dictionaryOf(payment: v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func asPreparePayOnchainRequest(preparePayOnchainRequest: [String: Any?]) throws -> PreparePayOnchainRequest {
|
||||||
|
guard let amountSat = preparePayOnchainRequest["amountSat"] as? UInt64 else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "amountSat", typeName: "PreparePayOnchainRequest"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return PreparePayOnchainRequest(
|
||||||
|
amountSat: amountSat)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func dictionaryOf(preparePayOnchainRequest: PreparePayOnchainRequest) -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"amountSat": preparePayOnchainRequest.amountSat,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func asPreparePayOnchainRequestList(arr: [Any]) throws -> [PreparePayOnchainRequest] {
|
||||||
|
var list = [PreparePayOnchainRequest]()
|
||||||
|
for value in arr {
|
||||||
|
if let val = value as? [String: Any?] {
|
||||||
|
var preparePayOnchainRequest = try asPreparePayOnchainRequest(preparePayOnchainRequest: val)
|
||||||
|
list.append(preparePayOnchainRequest)
|
||||||
|
} else {
|
||||||
|
throw LiquidSdkError.Generic(message: errUnexpectedType(typeName: "PreparePayOnchainRequest"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
static func arrayOf(preparePayOnchainRequestList: [PreparePayOnchainRequest]) -> [Any] {
|
||||||
|
return preparePayOnchainRequestList.map { v -> [String: Any?] in dictionaryOf(preparePayOnchainRequest: v) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static func asPreparePayOnchainResponse(preparePayOnchainResponse: [String: Any?]) throws -> PreparePayOnchainResponse {
|
||||||
|
guard let amountSat = preparePayOnchainResponse["amountSat"] as? UInt64 else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "amountSat", typeName: "PreparePayOnchainResponse"))
|
||||||
|
}
|
||||||
|
guard let feesSat = preparePayOnchainResponse["feesSat"] as? UInt64 else {
|
||||||
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "feesSat", typeName: "PreparePayOnchainResponse"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return PreparePayOnchainResponse(
|
||||||
|
amountSat: amountSat,
|
||||||
|
feesSat: feesSat
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func dictionaryOf(preparePayOnchainResponse: PreparePayOnchainResponse) -> [String: Any?] {
|
||||||
|
return [
|
||||||
|
"amountSat": preparePayOnchainResponse.amountSat,
|
||||||
|
"feesSat": preparePayOnchainResponse.feesSat,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func asPreparePayOnchainResponseList(arr: [Any]) throws -> [PreparePayOnchainResponse] {
|
||||||
|
var list = [PreparePayOnchainResponse]()
|
||||||
|
for value in arr {
|
||||||
|
if let val = value as? [String: Any?] {
|
||||||
|
var preparePayOnchainResponse = try asPreparePayOnchainResponse(preparePayOnchainResponse: val)
|
||||||
|
list.append(preparePayOnchainResponse)
|
||||||
|
} else {
|
||||||
|
throw LiquidSdkError.Generic(message: errUnexpectedType(typeName: "PreparePayOnchainResponse"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
static func arrayOf(preparePayOnchainResponseList: [PreparePayOnchainResponse]) -> [Any] {
|
||||||
|
return preparePayOnchainResponseList.map { v -> [String: Any?] in dictionaryOf(preparePayOnchainResponse: v) }
|
||||||
|
}
|
||||||
|
|
||||||
static func asPrepareReceiveRequest(prepareReceiveRequest: [String: Any?]) throws -> PrepareReceiveRequest {
|
static func asPrepareReceiveRequest(prepareReceiveRequest: [String: Any?]) throws -> PrepareReceiveRequest {
|
||||||
guard let payerAmountSat = prepareReceiveRequest["payerAmountSat"] as? UInt64 else {
|
guard let payerAmountSat = prepareReceiveRequest["payerAmountSat"] as? UInt64 else {
|
||||||
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "payerAmountSat", typeName: "PrepareReceiveRequest"))
|
throw LiquidSdkError.Generic(message: errMissingMandatoryField(fieldName: "payerAmountSat", typeName: "PrepareReceiveRequest"))
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ RCT_EXTERN_METHOD(
|
|||||||
reject: (RCTPromiseRejectBlock)reject
|
reject: (RCTPromiseRejectBlock)reject
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RCT_EXTERN_METHOD(
|
||||||
|
preparePayOnchain: (NSDictionary*)req
|
||||||
|
resolve: (RCTPromiseResolveBlock)resolve
|
||||||
|
reject: (RCTPromiseRejectBlock)reject
|
||||||
|
)
|
||||||
|
|
||||||
|
RCT_EXTERN_METHOD(
|
||||||
|
payOnchain: (NSDictionary*)req
|
||||||
|
resolve: (RCTPromiseResolveBlock)resolve
|
||||||
|
reject: (RCTPromiseRejectBlock)reject
|
||||||
|
)
|
||||||
|
|
||||||
RCT_EXTERN_METHOD(
|
RCT_EXTERN_METHOD(
|
||||||
listPayments: (RCTPromiseResolveBlock)resolve
|
listPayments: (RCTPromiseResolveBlock)resolve
|
||||||
reject: (RCTPromiseRejectBlock)reject
|
reject: (RCTPromiseRejectBlock)reject
|
||||||
|
|||||||
@@ -198,6 +198,28 @@ class RNBreezLiquidSDK: RCTEventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc(preparePayOnchain:resolve:reject:)
|
||||||
|
func preparePayOnchain(_ req: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
|
do {
|
||||||
|
let preparePayOnchainRequest = try BreezLiquidSDKMapper.asPreparePayOnchainRequest(preparePayOnchainRequest: req)
|
||||||
|
var res = try getBindingLiquidSdk().preparePayOnchain(req: preparePayOnchainRequest)
|
||||||
|
resolve(BreezLiquidSDKMapper.dictionaryOf(preparePayOnchainResponse: res))
|
||||||
|
} catch let err {
|
||||||
|
rejectErr(err: err, reject: reject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(payOnchain:resolve:reject:)
|
||||||
|
func payOnchain(_ req: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
|
do {
|
||||||
|
let payOnchainRequest = try BreezLiquidSDKMapper.asPayOnchainRequest(payOnchainRequest: req)
|
||||||
|
var res = try getBindingLiquidSdk().payOnchain(req: payOnchainRequest)
|
||||||
|
resolve(BreezLiquidSDKMapper.dictionaryOf(sendPaymentResponse: res))
|
||||||
|
} catch let err {
|
||||||
|
rejectErr(err: err, reject: reject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc(listPayments:reject:)
|
@objc(listPayments:reject:)
|
||||||
func listPayments(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
func listPayments(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
do {
|
do {
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export interface BackupRequest {
|
|||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
boltzUrl: string
|
boltzUrl: string
|
||||||
electrumUrl: string
|
liquidElectrumUrl: string
|
||||||
|
bitcoinElectrumUrl: string
|
||||||
workingDir: string
|
workingDir: string
|
||||||
network: Network
|
network: Network
|
||||||
paymentTimeoutSec: number
|
paymentTimeoutSec: number
|
||||||
@@ -65,6 +66,11 @@ export interface LogEntry {
|
|||||||
level: string
|
level: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PayOnchainRequest {
|
||||||
|
address: string
|
||||||
|
prepareRes: PreparePayOnchainResponse
|
||||||
|
}
|
||||||
|
|
||||||
export interface Payment {
|
export interface Payment {
|
||||||
txId?: string
|
txId?: string
|
||||||
swapId?: string
|
swapId?: string
|
||||||
@@ -79,6 +85,15 @@ export interface Payment {
|
|||||||
status: PaymentState
|
status: PaymentState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PreparePayOnchainRequest {
|
||||||
|
amountSat: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PreparePayOnchainResponse {
|
||||||
|
amountSat: number
|
||||||
|
feesSat: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface PrepareReceiveRequest {
|
export interface PrepareReceiveRequest {
|
||||||
payerAmountSat: number
|
payerAmountSat: number
|
||||||
}
|
}
|
||||||
@@ -240,6 +255,16 @@ export const receivePayment = async (req: PrepareReceiveResponse): Promise<Recei
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const preparePayOnchain = async (req: PreparePayOnchainRequest): Promise<PreparePayOnchainResponse> => {
|
||||||
|
const response = await BreezLiquidSDK.preparePayOnchain(req)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
export const payOnchain = async (req: PayOnchainRequest): Promise<SendPaymentResponse> => {
|
||||||
|
const response = await BreezLiquidSDK.payOnchain(req)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
export const listPayments = async (): Promise<Payment[]> => {
|
export const listPayments = async (): Promise<Payment[]> => {
|
||||||
const response = await BreezLiquidSDK.listPayments()
|
const response = await BreezLiquidSDK.listPayments()
|
||||||
return response
|
return response
|
||||||
|
|||||||
Reference in New Issue
Block a user