diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2316009..a411256 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,6 +34,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install WASM target + run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 with: workspaces: | @@ -46,12 +49,21 @@ jobs: version: "27.2" repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Check Rust Clippy - run: | - cd lib - cargo clippy -- -D warnings - cd ../cli - cargo clippy -- -D warnings + - name: Clippy bindings + working-directory: lib/bindings + run: cargo clippy -- -D warnings + + - name: Clippy core + working-directory: lib/core + run: cargo clippy -- -D warnings + + - name: Clippy WASM + working-directory: lib/wasm + run: cargo clippy --target=wasm32-unknown-unknown -- -D warnings + + - name: Clippy cli + working-directory: cli + run: cargo clippy -- -D warnings build: name: Cargo Build @@ -59,6 +71,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install WASM target + run: rustup target add wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 with: workspaces: | @@ -71,8 +86,17 @@ jobs: version: "27.2" repo-token: ${{ secrets.GITHUB_TOKEN }} - - run: cargo build - working-directory: lib + - name: Cargo build bindings + working-directory: lib/bindings + run: cargo build + + - name: Cargo build core + working-directory: lib/core + run: cargo build + + - name: Cargo build WASM + working-directory: lib/wasm + run: cargo build --target=wasm32-unknown-unknown - name: Check git status env: @@ -171,6 +195,34 @@ jobs: cd lib/bindings cargo test + build-wasm: + name: Test WASM + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install WASM target + run: rustup target add wasm32-unknown-unknown + + - name: Install wasm-pack + run: cargo install wasm-pack + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: | + lib -> target + cli -> target + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + version: "27.2" + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Test WASM + working-directory: lib/wasm + run: wasm-pack test --headless --firefox + notification-plugin: name: Check notification plugin runs-on: macOS-14 diff --git a/Makefile b/Makefile index 558499c..c66602a 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,26 @@ fmt: cd lib && cargo fmt cd cli && cargo fmt -clippy: - cd lib && cargo clippy -- -D warnings - cd lib && cargo clippy --tests -- -D warnings +clippy: cargo-clippy wasm-clippy + +cargo-clippy: + cd lib/bindings && cargo clippy -- -D warnings + cd lib/bindings && cargo clippy --tests -- -D warnings + cd lib/core && cargo clippy -- -D warnings + cd lib/core && cargo clippy --tests -- -D warnings cd cli && cargo clippy -- -D warnings -test: - cd lib && cargo test +wasm-clippy: + make -C ./lib/wasm clippy + +test: cargo-test wasm-test + +cargo-test: + cd lib/bindings && cargo test + cd lib/core && cargo test + +wasm-test: + make -C ./lib/wasm test codegen: flutter-codegen react-native-codegen diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 991c483..458c5a4 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -33,7 +33,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -441,7 +441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", @@ -721,6 +721,7 @@ dependencies = [ "bip39", "boltz-client", "chrono", + "console_log", "derivative", "ecies", "electrum-client", @@ -734,11 +735,13 @@ dependencies = [ "lwk_common", "lwk_signer", "lwk_wollet", + "maybe-sync", "prost 0.13.5", - "reqwest 0.12.12", + "reqwest 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", "rusqlite", "rusqlite_migration", "sdk-common", + "sdk-macros", "security-framework", "security-framework-sys", "semver", @@ -807,6 +810,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -825,7 +834,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -917,6 +926,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -929,10 +947,20 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "cookie-factory" version = "0.3.3" @@ -973,7 +1001,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1020,7 +1048,7 @@ version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "curve25519-dalek-derive", "fiat-crypto", @@ -1055,7 +1083,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "num_cpus", ] @@ -1065,12 +1093,12 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "hashbrown 0.14.5", - "lock_api", + "lock_api 0.4.12", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -1155,6 +1183,16 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "dns-parser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" +dependencies = [ + "byteorder", + "quick-error", +] + [[package]] name = "ecies" version = "0.2.7" @@ -1166,7 +1204,7 @@ dependencies = [ "hkdf", "libsecp256k1", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "rand_core", "sha2", "typenum", @@ -1227,7 +1265,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1340,7 +1378,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "rustix", "windows-sys 0.52.0", ] @@ -1625,7 +1663,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -1638,7 +1676,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.13.3+wasi-0.2.2", "windows-targets 0.52.6", @@ -1666,19 +1704,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" -[[package]] -name = "gloo-utils" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "h2" version = "0.3.26" @@ -1808,7 +1833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ "async-trait", - "cfg-if", + "cfg-if 1.0.0", "data-encoding", "enum-as-inner", "futures-channel", @@ -1832,13 +1857,13 @@ version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "futures-util", "hickory-proto", "ipconfig", "lru-cache", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "rand", "resolv-conf", "smallvec", @@ -2056,19 +2081,6 @@ dependencies = [ "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.32", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -2131,7 +2143,7 @@ dependencies = [ "i18n-embed-impl", "intl-memoizer", "log", - "parking_lot", + "parking_lot 0.12.3", "rust-embed", "thiserror 1.0.69", "unic-langid", @@ -2600,6 +2612,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -2674,7 +2695,7 @@ dependencies = [ "once_cell", "rand", "regex-lite", - "reqwest 0.12.12", + "reqwest 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "thiserror 1.0.69", @@ -2696,13 +2717,22 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "maybe-sync" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7551d6fcc47ecf769e6c8b2e5dd7f56f90361d3d1360e3a280c8d0d7c8e680b7" +dependencies = [ + "parking_lot 0.10.2", +] + [[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "digest 0.10.7", ] @@ -2810,7 +2840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ "bitflags 2.9.0", - "cfg-if", + "cfg-if 1.0.0", "libc", ] @@ -2909,7 +2939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ "bitflags 2.9.0", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -2967,14 +2997,38 @@ dependencies = [ "log", ] +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.7.3", +] + [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "lock_api", - "parking_lot_core", + "lock_api 0.4.12", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93f386bb233083c799e6e642a9d73db98c24a5deeb95ffc85bf281255dffc98" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", ] [[package]] @@ -2983,9 +3037,9 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.5.10", "smallvec", "windows-targets 0.52.6", ] @@ -3087,7 +3141,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "opaque-debug", "universal-hash", @@ -3399,6 +3453,12 @@ dependencies = [ "getrandom 0.2.14", ] +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + [[package]] name = "redox_syscall" version = "0.5.10" @@ -3443,43 +3503,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[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.32", - "hyper-tls 0.5.0", - "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", -] - [[package]] name = "reqwest" version = "0.12.12" @@ -3498,7 +3521,7 @@ dependencies = [ "http-body-util", "hyper 1.6.0", "hyper-rustls", - "hyper-tls 0.6.0", + "hyper-tls", "hyper-util", "ipnet", "js-sys", @@ -3530,6 +3553,49 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "reqwest" +version = "0.12.12" +source = "git+https://github.com/seanmonstar/reqwest?rev=1e7e9653e5b7ee3175131052c097a8d9a07ecbcd#1e7e9653e5b7ee3175131052c097a8d9a07ecbcd" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.8", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower 0.5.2", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -3562,7 +3628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.0", "getrandom 0.2.14", "libc", "untrusted 0.9.0", @@ -3765,7 +3831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" dependencies = [ "bitflags 2.9.0", - "cfg-if", + "cfg-if 1.0.0", "clipboard-win", "fd-lock", "home", @@ -3855,7 +3921,7 @@ dependencies = [ [[package]] name = "sdk-common" version = "0.6.2" -source = "git+https://github.com/breez/breez-sdk?rev=19ed955c6fa854ad6cd2beb2eca9127d8099c506#19ed955c6fa854ad6cd2beb2eca9127d8099c506" +source = "git+https://github.com/breez/breez-sdk?rev=0017f7d3f76a1f0094ad9ff25422b72c31acc60e#0017f7d3f76a1f0094ad9ff25422b72c31acc60e" dependencies = [ "aes", "anyhow", @@ -3864,6 +3930,7 @@ dependencies = [ "bip21", "bitcoin 0.29.2", "cbc", + "dns-parser", "elements", "getrandom 0.2.14", "hex", @@ -3878,7 +3945,8 @@ dependencies = [ "prost 0.13.5", "querystring", "regex", - "reqwest 0.11.20", + "reqwest 0.12.12 (git+https://github.com/seanmonstar/reqwest?rev=1e7e9653e5b7ee3175131052c097a8d9a07ecbcd)", + "sdk-macros", "serde", "serde_json", "strum_macros", @@ -3889,12 +3957,21 @@ dependencies = [ "tonic-build 0.12.3", "tonic-build 0.8.4", "tonic-web-wasm-client", - "tsify-next", "url", "urlencoding", "wasm-bindgen", ] +[[package]] +name = "sdk-macros" +version = "0.6.2" +source = "git+https://github.com/breez/breez-sdk?rev=0017f7d3f76a1f0094ad9ff25422b72c31acc60e#0017f7d3f76a1f0094ad9ff25422b72c31acc60e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -4029,17 +4106,6 @@ dependencies = [ "syn 2.0.99", ] -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.99", -] - [[package]] name = "serde_json" version = "1.0.140" @@ -4070,7 +4136,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -4081,7 +4147,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -4132,7 +4198,7 @@ dependencies = [ "fragile", "js-sys", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "thiserror 2.0.12", "tokio", "wasm-bindgen", @@ -4253,7 +4319,7 @@ version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "getrandom 0.3.1", "once_cell", @@ -4706,31 +4772,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tsify-next" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8bf7232b89b86f63b5f0ef22c64960f9cf4fb52c6698f1e7f60de93bc3292f" -dependencies = [ - "gloo-utils", - "serde", - "serde_json", - "tsify-next-macros", - "wasm-bindgen", -] - -[[package]] -name = "tsify-next-macros" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2d85ebe93eedca20d3fe6d65814c856467a649674aa7763ebd42e3bb815fec" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.99", -] - [[package]] name = "tungstenite" version = "0.21.0" @@ -4901,6 +4942,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ "getrandom 0.3.1", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -4955,7 +4998,7 @@ version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -4981,7 +5024,7 @@ version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "once_cell", "wasm-bindgen", @@ -5335,7 +5378,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys 0.48.0", ] diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 72a5e59..9342eab 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -33,7 +33,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -285,7 +285,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -344,7 +344,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", "synstructure", ] @@ -356,7 +356,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -378,7 +378,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -389,7 +389,7 @@ checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -520,7 +520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", @@ -799,6 +799,7 @@ dependencies = [ "bip39", "boltz-client", "chrono", + "console_log", "derivative", "ecies", "electrum-client", @@ -812,12 +813,14 @@ dependencies = [ "lwk_common", "lwk_signer", "lwk_wollet", + "maybe-sync", "paste", "prost 0.13.4", "reqwest 0.12.7", "rusqlite", "rusqlite_migration", "sdk-common", + "sdk-macros", "security-framework", "security-framework-sys", "semver", @@ -835,6 +838,7 @@ dependencies = [ "tonic-build 0.12.3", "url", "uuid", + "wasm-bindgen-test", "x509-parser", "zbase32", ] @@ -860,7 +864,14 @@ dependencies = [ name = "breez-sdk-liquid-wasm" version = "0.7.1" dependencies = [ + "anyhow", "breez-sdk-liquid", + "console_log", + "js-sys", + "log", + "sdk-macros", + "serde", + "tsify-next", "wasm-bindgen", "wasm-bindgen-futures", ] @@ -945,6 +956,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -957,7 +974,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", ] @@ -1061,7 +1078,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1079,6 +1096,15 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -1091,10 +1117,20 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "cookie-factory" version = "0.3.3" @@ -1135,7 +1171,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1182,7 +1218,7 @@ version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "curve25519-dalek-derive", "fiat-crypto", @@ -1199,7 +1235,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1217,7 +1253,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "num_cpus", ] @@ -1227,12 +1263,12 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "hashbrown 0.14.5", - "lock_api", + "lock_api 0.4.12", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -1249,7 +1285,7 @@ checksum = "51aac4c99b2e6775164b412ea33ae8441b2fde2dbf05a20bc0052a63d08c475b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1314,7 +1350,17 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", +] + +[[package]] +name = "dns-parser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" +dependencies = [ + "byteorder", + "quick-error", ] [[package]] @@ -1328,7 +1374,7 @@ dependencies = [ "hkdf", "libsecp256k1", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "rand_core 0.6.4", "sha2", "typenum", @@ -1389,7 +1435,7 @@ version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1401,7 +1447,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1599,7 +1645,7 @@ dependencies = [ "md-5", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1715,7 +1761,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -1773,7 +1819,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi", @@ -1949,7 +1995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" dependencies = [ "async-trait", - "cfg-if", + "cfg-if 1.0.0", "data-encoding", "enum-as-inner", "futures-channel", @@ -1973,13 +2019,13 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "futures-util", "hickory-proto", "ipconfig", "lru-cache", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "rand 0.8.5", "resolv-conf", "smallvec", @@ -2197,19 +2243,6 @@ dependencies = [ "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.30", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -2272,7 +2305,7 @@ dependencies = [ "i18n-embed-impl", "intl-memoizer", "log", - "parking_lot", + "parking_lot 0.12.3", "rust-embed", "thiserror 1.0.63", "unic-langid", @@ -2295,7 +2328,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.98", "unic-langid", ] @@ -2309,7 +2342,7 @@ dependencies = [ "i18n-config", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -2450,7 +2483,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -2761,6 +2794,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -2857,13 +2899,22 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "maybe-sync" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7551d6fcc47ecf769e6c8b2e5dd7f56f90361d3d1360e3a280c8d0d7c8e680b7" +dependencies = [ + "parking_lot 0.10.2", +] + [[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "digest 0.10.7", ] @@ -2889,6 +2940,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3061,7 +3122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -3077,7 +3138,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -3125,14 +3186,38 @@ dependencies = [ "log", ] +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.7.3", +] + [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "lock_api", - "parking_lot_core", + "lock_api 0.4.12", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93f386bb233083c799e6e642a9d73db98c24a5deeb95ffc85bf281255dffc98" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", ] [[package]] @@ -3141,9 +3226,9 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.5.10", "smallvec", "windows-targets 0.52.6", ] @@ -3203,7 +3288,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -3247,7 +3332,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "opaque-debug", "universal-hash", @@ -3291,7 +3376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -3337,14 +3422,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -3407,7 +3492,7 @@ dependencies = [ "prost 0.13.4", "prost-types 0.13.4", "regex", - "syn 2.0.87", + "syn 2.0.98", "tempfile", ] @@ -3434,7 +3519,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -3602,9 +3687,15 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags 2.6.0", ] @@ -3653,43 +3744,6 @@ dependencies = [ "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.30", - "hyper-tls 0.5.0", - "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", -] - [[package]] name = "reqwest" version = "0.12.7" @@ -3708,7 +3762,7 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-rustls", - "hyper-tls 0.6.0", + "hyper-tls", "hyper-util", "ipnet", "js-sys", @@ -3739,6 +3793,49 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "reqwest" +version = "0.12.12" +source = "git+https://github.com/seanmonstar/reqwest?rev=1e7e9653e5b7ee3175131052c097a8d9a07ecbcd#1e7e9653e5b7ee3175131052c097a8d9a07ecbcd" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.1.3", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower 0.5.2", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -3771,7 +3868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.0", "getrandom", "libc", "spin 0.9.8", @@ -3822,7 +3919,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.87", + "syn 2.0.98", "walkdir", ] @@ -4044,7 +4141,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4071,7 +4168,7 @@ dependencies = [ [[package]] name = "sdk-common" version = "0.6.2" -source = "git+https://github.com/breez/breez-sdk?rev=19ed955c6fa854ad6cd2beb2eca9127d8099c506#19ed955c6fa854ad6cd2beb2eca9127d8099c506" +source = "git+https://github.com/breez/breez-sdk?rev=0017f7d3f76a1f0094ad9ff25422b72c31acc60e#0017f7d3f76a1f0094ad9ff25422b72c31acc60e" dependencies = [ "aes", "anyhow", @@ -4080,6 +4177,7 @@ dependencies = [ "bip21", "bitcoin 0.29.2", "cbc", + "dns-parser", "elements", "getrandom", "hex", @@ -4094,7 +4192,8 @@ dependencies = [ "prost 0.13.4", "querystring", "regex", - "reqwest 0.11.20", + "reqwest 0.12.12", + "sdk-macros", "serde", "serde_json", "strum_macros", @@ -4105,12 +4204,21 @@ dependencies = [ "tonic-build 0.12.3", "tonic-build 0.8.4", "tonic-web-wasm-client", - "tsify-next", "url", "urlencoding", "wasm-bindgen", ] +[[package]] +name = "sdk-macros" +version = "0.6.2" +source = "git+https://github.com/breez/breez-sdk?rev=0017f7d3f76a1f0094ad9ff25422b72c31acc60e#0017f7d3f76a1f0094ad9ff25422b72c31acc60e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -4245,7 +4353,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4256,7 +4364,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4289,7 +4397,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -4300,7 +4408,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -4372,7 +4480,7 @@ dependencies = [ "fragile", "js-sys", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "thiserror 2.0.11", "tokio", "wasm-bindgen", @@ -4421,7 +4529,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4443,9 +4551,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -4475,7 +4583,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4515,7 +4623,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "once_cell", "rustix", @@ -4563,7 +4671,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4574,7 +4682,7 @@ checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4652,7 +4760,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4678,7 +4786,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4854,7 +4962,7 @@ dependencies = [ "prost-build 0.13.4", "prost-types 0.13.4", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4912,6 +5020,7 @@ dependencies = [ "futures-util", "pin-project-lite", "sync_wrapper 1.0.1", + "tokio", "tower-layer", "tower-service", ] @@ -4947,7 +5056,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -4997,7 +5106,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -5217,7 +5326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -5284,7 +5393,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.98", "toml", "uniffi_build 0.25.3", "uniffi_meta 0.25.3", @@ -5442,6 +5551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", + "wasm-bindgen", ] [[package]] @@ -5487,7 +5597,7 @@ version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -5503,7 +5613,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", "wasm-bindgen-shared", ] @@ -5513,7 +5623,7 @@ version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "once_cell", "wasm-bindgen", @@ -5538,7 +5648,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5552,6 +5662,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-bindgen-test" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +dependencies = [ + "js-sys", + "minicov", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "wasm-streams" version = "0.4.1" @@ -5860,7 +5994,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys 0.48.0", ] @@ -5940,7 +6074,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", "synstructure", ] @@ -5968,7 +6102,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -5988,7 +6122,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", "synstructure", ] @@ -6009,7 +6143,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] [[package]] @@ -6031,5 +6165,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.98", ] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index d1ccb6a..7869cbd 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -36,6 +36,9 @@ unexpected_cfgs = { level = "allow", check-cfg = ['cfg(frb_expand)'] } anyhow = "1.0" log = "0.4.20" once_cell = "1.19" +serde = { version = "1.0", features = ["derive"] } +sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "0017f7d3f76a1f0094ad9ff25422b72c31acc60e", features = ["liquid"] } +sdk-macros = { git = "https://github.com/breez/breez-sdk", rev = "0017f7d3f76a1f0094ad9ff25422b72c31acc60e" } thiserror = "1.0" # Version must match that used by uniffi-bindgen-go uniffi = "0.25.0" diff --git a/lib/core/Cargo.toml b/lib/core/Cargo.toml index 82327c2..b06c6cb 100644 --- a/lib/core/Cargo.toml +++ b/lib/core/Cargo.toml @@ -28,8 +28,8 @@ lwk_common = "0.8.0" lwk_signer = { version = "0.8.0", default-features = false } rusqlite = { git = "https://github.com/Spxg/rusqlite", rev = "e36644127f31fa6e7ea0999b59432deb4a07f220", features = [ "backup", "bundled" ] } tokio = { version = "1", default-features = false, features = ["rt", "macros"] } -# TODO: Change on top of main once PR is merged -sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "19ed955c6fa854ad6cd2beb2eca9127d8099c506", features = ["liquid"] } +sdk-common = { workspace = true } +sdk-macros = { workspace = true } rusqlite_migration = { git = "https://github.com/hydra-yse/rusqlite_migration", branch = "rusqlite-v0.33.0" } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.116" @@ -52,25 +52,36 @@ ecies = { version = "0.2.7", default-features = false, features = ["pure"] } semver = "1.0.23" lazy_static = "1.5.0" +# Non-WASM dependencies [target.'cfg(not(all(target_family = "wasm", target_os = "unknown")))'.dependencies] electrum-client = { version = "0.21.0", default-features = false, features = [ "use-rustls-ring", "proxy", ] } boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", rev = "12c9e546f15706b563ba7e49f2be7e8a5e7ada90" } +lwk_wollet = { git = "https://github.com/breez/lwk", branch = "breez-sdk-liquid-0.6.3" } +maybe-sync = { version = "0.1.1", features = ["sync"] } tokio-stream = { version = "0.1.14", features = ["sync"] } tokio-tungstenite = { version = "0.21.0", features = ["native-tls-vendored"] } tonic = { version = "0.12.3", features = ["tls", "tls-webpki-roots"] } uuid = { version = "1.8.0", features = ["v4"] } -lwk_wollet = { git = "https://github.com/breez/lwk", branch = "breez-sdk-liquid-0.6.3" } +# WASM dependencies [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies] +console_log = "1" lwk_wollet = { git = "https://github.com/breez/lwk", branch = "breez-sdk-liquid-0.6.3", default-features = false, features = [ "esplora" ] } +maybe-sync = "0.1.1" +uuid = { version = "1.8.0", features = ["v4", "js"] } [dev-dependencies] +sdk-common = { workspace = true, features = ["test-utils"] } paste = "1.0.15" tempdir = "0.3.7" +# WASM dev dependencies +[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dev-dependencies] +wasm-bindgen-test = "0.3.33" + [build-dependencies] anyhow = { version = "1.0.79", features = ["backtrace"] } glob = "0.3.1" diff --git a/lib/core/src/buy.rs b/lib/core/src/buy.rs index 90f5da6..817a107 100644 --- a/lib/core/src/buy.rs +++ b/lib/core/src/buy.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; -use async_trait::async_trait; use sdk_common::prelude::{BreezServer, BuyBitcoinProviderApi, MoonpayProvider}; use crate::{ @@ -9,7 +8,7 @@ use crate::{ prelude::LiquidNetwork, }; -#[async_trait] +#[sdk_macros::async_trait] pub(crate) trait BuyBitcoinApi: Send + Sync { /// Initiate buying Bitcoin and return a URL to the selected third party provider async fn buy_bitcoin( @@ -35,7 +34,7 @@ impl BuyBitcoinService { } } -#[async_trait] +#[sdk_macros::async_trait] impl BuyBitcoinApi for BuyBitcoinService { async fn buy_bitcoin( &self, diff --git a/lib/core/src/chain/bitcoin.rs b/lib/core/src/chain/bitcoin.rs index b32f4d6..78dbb07 100644 --- a/lib/core/src/chain/bitcoin.rs +++ b/lib/core/src/chain/bitcoin.rs @@ -1,11 +1,10 @@ use std::{ collections::HashMap, - sync::{Mutex, OnceLock}, + sync::{Arc, Mutex, OnceLock}, time::Duration, }; use anyhow::{anyhow, Result}; -use async_trait::async_trait; use electrum_client::{ bitcoin::{ consensus::{deserialize, serialize}, @@ -16,7 +15,10 @@ use electrum_client::{ }; use log::info; use lwk_wollet::{bitcoin::ScriptBuf, ElectrumOptions, ElectrumUrl, Error, History}; -use sdk_common::{bitcoin::hashes::hex::ToHex, prelude::get_parse_and_log_response}; +use sdk_common::{ + bitcoin::hashes::hex::ToHex, + prelude::{get_and_check_success, parse_json, RestClient}, +}; use crate::{ model::{Config, LiquidNetwork, RecommendedFees}, @@ -25,7 +27,7 @@ use crate::{ /// Trait implemented by types that can fetch data from a blockchain data source. #[allow(dead_code)] -#[async_trait] +#[sdk_macros::async_trait] pub trait BitcoinChainService: Send + Sync { /// Get the blockchain latest block fn tip(&self) -> Result; @@ -82,14 +84,16 @@ pub trait BitcoinChainService: Send + Sync { } pub(crate) struct HybridBitcoinChainService { - client: OnceLock, config: Config, + rest_client: Arc, + client: OnceLock, last_known_tip: Mutex>, } impl HybridBitcoinChainService { - pub fn new(config: Config) -> Result { + pub fn new(config: Config, rest_client: Arc) -> Result { Ok(Self { config, + rest_client, client: OnceLock::new(), last_known_tip: Mutex::new(None), }) @@ -112,7 +116,7 @@ impl HybridBitcoinChainService { } } -#[async_trait] +#[sdk_macros::async_trait] impl BitcoinChainService for HybridBitcoinChainService { fn tip(&self) -> Result { let client = self.get_client()?; @@ -364,11 +368,11 @@ impl BitcoinChainService for HybridBitcoinChainService { } async fn recommended_fees(&self) -> Result { - get_parse_and_log_response( + let (response, _) = get_and_check_success( + self.rest_client.as_ref(), &format!("{}/v1/fees/recommended", self.config.mempoolspace_url), - true, ) - .await - .map_err(Into::into) + .await?; + Ok(parse_json(&response)?) } } diff --git a/lib/core/src/chain/liquid.rs b/lib/core/src/chain/liquid.rs index d60b9b8..7fda3a4 100644 --- a/lib/core/src/chain/liquid.rs +++ b/lib/core/src/chain/liquid.rs @@ -2,7 +2,6 @@ use std::sync::{Mutex, OnceLock}; use std::time::Duration; use anyhow::{anyhow, Result}; -use async_trait::async_trait; use boltz_client::ToHex; use electrum_client::{Client, ElectrumApi}; use elements::encode::serialize as elements_serialize; @@ -19,7 +18,7 @@ use crate::model::LiquidNetwork; use crate::prelude::Utxo; use crate::{model::Config, utils}; -#[async_trait] +#[sdk_macros::async_trait] pub trait LiquidChainService: Send + Sync { /// Get the blockchain latest block async fn tip(&self) -> Result; @@ -93,7 +92,7 @@ impl HybridLiquidChainService { } } -#[async_trait] +#[sdk_macros::async_trait] impl LiquidChainService for HybridLiquidChainService { async fn tip(&self) -> Result { let client = self.get_client()?; diff --git a/lib/core/src/chain_swap.rs b/lib/core/src/chain_swap.rs index 0b35ede..ffbb19b 100644 --- a/lib/core/src/chain_swap.rs +++ b/lib/core/src/chain_swap.rs @@ -1,7 +1,6 @@ use std::{str::FromStr, sync::Arc}; use anyhow::{anyhow, bail, Context, Result}; -use async_trait::async_trait; use boltz_client::{ boltz::{self}, swaps::boltz::{ChainSwapStates, CreateChainResponse, SwapUpdateTxDetails}, @@ -46,7 +45,7 @@ pub(crate) struct ChainSwapHandler { subscription_notifier: broadcast::Sender, } -#[async_trait] +#[sdk_macros::async_trait] impl BlockListener for ChainSwapHandler { async fn on_bitcoin_block(&self, height: u32) { if let Err(e) = self.claim_outgoing(height).await { @@ -1491,7 +1490,10 @@ mod tests { }, }; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_chain_swap_state_transitions() -> Result<()> { create_persister!(persister); diff --git a/lib/core/src/event.rs b/lib/core/src/event.rs index a80eb4f..9c5c5f2 100644 --- a/lib/core/src/event.rs +++ b/lib/core/src/event.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{SystemTime, UNIX_EPOCH}; use anyhow::Result; use log::{debug, info}; use tokio::sync::{broadcast, RwLock}; +use uuid::Uuid; use crate::model::{EventListener, SdkEvent}; @@ -26,10 +26,7 @@ impl EventManager { } pub async fn add(&self, listener: Box) -> Result { - let id = format!( - "{:X}", - SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() - ); + let id = Uuid::new_v4().to_string(); (*self.listeners.write().await).insert(id.clone(), listener); Ok(id) } diff --git a/lib/core/src/lnurl/auth.rs b/lib/core/src/lnurl/auth.rs index 98a1265..20f5340 100644 --- a/lib/core/src/lnurl/auth.rs +++ b/lib/core/src/lnurl/auth.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use async_trait::async_trait; use sdk_common::{ bitcoin::util::bip32::{ChildNumber, DerivationPath}, prelude::{LnUrlResult, LnurlAuthSigner}, @@ -18,7 +17,7 @@ impl SdkLnurlAuthSigner { } } -#[async_trait] +#[sdk_macros::async_trait] impl LnurlAuthSigner for SdkLnurlAuthSigner { async fn derive_bip32_pub_key(&self, derivation_path: &[ChildNumber]) -> LnUrlResult> { let derivation: DerivationPath = derivation_path.to_vec().into(); diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs index a9a13bb..51a2b66 100644 --- a/lib/core/src/model.rs +++ b/lib/core/src/model.rs @@ -1,5 +1,4 @@ use anyhow::{anyhow, Result}; -use async_trait::async_trait; use boltz_client::{ bitcoin::ScriptBuf, boltz::{ChainPair, BOLTZ_MAINNET_URL_V2, BOLTZ_REGTEST, BOLTZ_TESTNET_URL_V2}, @@ -13,6 +12,7 @@ use boltz_client::{BtcSwapScript, Keypair, LBtcSwapScript}; use derivative::Derivative; use lwk_wollet::elements::AssetId; use lwk_wollet::{bitcoin::bip32, ElementsNetwork}; +use maybe_sync::{MaybeSend, MaybeSync}; use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef}; use rusqlite::ToSql; use sdk_common::prelude::*; @@ -281,7 +281,7 @@ impl From for boltz_client::bitcoin::Network { } /// Trait that can be used to react to various [SdkEvent]s emitted by the SDK. -pub trait EventListener: Send + Sync { +pub trait EventListener: MaybeSend + MaybeSync { fn on_event(&self, e: SdkEvent); } @@ -324,7 +324,7 @@ impl From for SignerError { /// A trait that can be used to sign messages and verify signatures. /// The sdk user can implement this trait to use their own signer. -pub trait Signer: Send + Sync { +pub trait Signer: MaybeSend + MaybeSync { /// The master xpub encoded as 78 bytes length as defined in bip32 specification. /// For reference: fn xpub(&self) -> Result, SignerError>; @@ -783,7 +783,7 @@ pub enum GetPaymentRequest { } /// Trait that can be used to react to new blocks from Bitcoin and Liquid chains -#[async_trait] +#[sdk_macros::async_trait] pub(crate) trait BlockListener: Send + Sync { async fn on_bitcoin_block(&self, height: u32); async fn on_liquid_block(&self, height: u32); diff --git a/lib/core/src/persist/address.rs b/lib/core/src/persist/address.rs index ffb73da..942cfbe 100644 --- a/lib/core/src/persist/address.rs +++ b/lib/core/src/persist/address.rs @@ -102,7 +102,10 @@ mod tests { use crate::test_utils::persist::create_persister; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_next_expired_reserved_address() -> Result<()> { create_persister!(storage); let address = "tlq1pq2amlulhea6ltq7x3eu9atsc2nnrer7yt7xve363zxedqwu2mk6ctcyv9awl8xf28cythreqklt5q0qqwsxzlm6wu4z6d574adl9zh2zmr0h85gt534n"; @@ -128,7 +131,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_delete_reserved_address() -> Result<()> { create_persister!(storage); let address = "tlq1pq2amlulhea6ltq7x3eu9atsc2nnrer7yt7xve363zxedqwu2mk6ctcyv9awl8xf28cythreqklt5q0qqwsxzlm6wu4z6d574adl9zh2zmr0h85gt534n"; diff --git a/lib/core/src/persist/backup.rs b/lib/core/src/persist/backup.rs index 5cb227e..019ac57 100644 --- a/lib/core/src/persist/backup.rs +++ b/lib/core/src/persist/backup.rs @@ -44,7 +44,10 @@ mod tests { test_utils::persist::{create_persister, new_receive_swap, new_send_swap}, }; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_backup_and_restore() -> Result<()> { create_persister!(local); diff --git a/lib/core/src/persist/cache.rs b/lib/core/src/persist/cache.rs index f7bd85c..91e4e9b 100644 --- a/lib/core/src/persist/cache.rs +++ b/lib/core/src/persist/cache.rs @@ -194,7 +194,10 @@ mod tests { use crate::test_utils::persist::create_persister; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_cached_items() -> Result<()> { create_persister!(persister); @@ -209,7 +212,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_get_last_derivation_index() -> Result<()> { create_persister!(persister); @@ -231,7 +234,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_next_derivation_index() -> Result<()> { create_persister!(persister); diff --git a/lib/core/src/persist/chain.rs b/lib/core/src/persist/chain.rs index a995787..dbbd021 100644 --- a/lib/core/src/persist/chain.rs +++ b/lib/core/src/persist/chain.rs @@ -512,7 +512,10 @@ mod tests { use crate::test_utils::persist::create_persister; use anyhow::Result; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_writing_stale_swap() -> Result<()> { create_persister!(storage); @@ -538,7 +541,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_list_local_swaps() -> Result<()> { create_persister!(storage); diff --git a/lib/core/src/persist/mod.rs b/lib/core/src/persist/mod.rs index 9b9aa37..8bd33a7 100644 --- a/lib/core/src/persist/mod.rs +++ b/lib/core/src/persist/mod.rs @@ -1032,7 +1032,10 @@ mod tests { use super::{PaymentState, PaymentType}; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_get_payments() -> Result<()> { create_persister!(storage); @@ -1056,7 +1059,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_list_ongoing_swaps() -> Result<()> { create_persister!(storage); diff --git a/lib/core/src/persist/receive.rs b/lib/core/src/persist/receive.rs index 92c9bbc..dc1155f 100644 --- a/lib/core/src/persist/receive.rs +++ b/lib/core/src/persist/receive.rs @@ -396,7 +396,10 @@ mod tests { use super::PaymentState; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_fetch_receive_swap() -> Result<()> { create_persister!(storage); @@ -413,7 +416,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_list_receive_swap() -> Result<()> { create_persister!(storage); @@ -436,7 +439,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_update_receive_swap() -> Result<()> { create_persister!(storage); @@ -466,7 +469,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_writing_stale_swap() -> Result<()> { create_persister!(storage); diff --git a/lib/core/src/persist/send.rs b/lib/core/src/persist/send.rs index 12e6efb..7f84900 100644 --- a/lib/core/src/persist/send.rs +++ b/lib/core/src/persist/send.rs @@ -407,7 +407,10 @@ mod tests { use super::PaymentState; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_fetch_send_swap() -> Result<()> { create_persister!(storage); let send_swap = new_send_swap(None, None); @@ -423,7 +426,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_list_send_swap() -> Result<()> { create_persister!(storage); @@ -449,7 +452,7 @@ mod tests { Ok(()) } - #[test] + #[sdk_macros::test_all] fn test_update_send_swap() -> Result<()> { create_persister!(storage); @@ -492,7 +495,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_writing_stale_swap() -> Result<()> { create_persister!(storage); diff --git a/lib/core/src/receive_swap.rs b/lib/core/src/receive_swap.rs index 07240c4..1389f9e 100644 --- a/lib/core/src/receive_swap.rs +++ b/lib/core/src/receive_swap.rs @@ -1,7 +1,6 @@ use std::{str::FromStr, sync::Arc}; use anyhow::{anyhow, bail, Result}; -use async_trait::async_trait; use boltz_client::swaps::boltz::RevSwapStates; use boltz_client::{boltz, Serialize, ToHex}; use log::{debug, error, info, warn}; @@ -33,7 +32,7 @@ pub(crate) struct ReceiveSwapHandler { liquid_chain_service: Arc, } -#[async_trait] +#[sdk_macros::async_trait] impl BlockListener for ReceiveSwapHandler { async fn on_bitcoin_block(&self, _height: u32) {} @@ -546,7 +545,10 @@ mod tests { }, }; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_receive_swap_state_transitions() -> Result<()> { create_persister!(persister); diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index 14d355b..b4d0167 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -72,11 +72,284 @@ pub const DEFAULT_EXTERNAL_INPUT_PARSERS: &[(&str, &str, &str)] = &[( pub(crate) const NETWORK_PROPAGATION_GRACE_PERIOD: Duration = Duration::from_secs(30); +pub(crate) struct LiquidSdkBuilder { + config: Config, + signer: Arc>, + breez_server: Arc, + bitcoin_chain_service: Option>, + liquid_chain_service: Option>, + onchain_wallet: Option>, + persister: Option>, + recoverer: Option>, + rest_client: Option>, + status_stream: Option>, + swapper: Option>, + sync_service: Option>, +} + +#[allow(dead_code)] +impl LiquidSdkBuilder { + pub fn new( + config: Config, + server_url: String, + signer: Arc>, + ) -> Result { + let breez_server = Arc::new(BreezServer::new(server_url, None)?); + Ok(LiquidSdkBuilder { + config, + signer, + breez_server, + bitcoin_chain_service: None, + liquid_chain_service: None, + onchain_wallet: None, + persister: None, + recoverer: None, + rest_client: None, + status_stream: None, + swapper: None, + sync_service: None, + }) + } + + pub fn bitcoin_chain_service( + &mut self, + bitcoin_chain_service: Arc, + ) -> &mut Self { + self.bitcoin_chain_service = Some(bitcoin_chain_service.clone()); + self + } + + pub fn liquid_chain_service( + &mut self, + liquid_chain_service: Arc, + ) -> &mut Self { + self.liquid_chain_service = Some(liquid_chain_service.clone()); + self + } + + pub fn recoverer(&mut self, recoverer: Arc) -> &mut Self { + self.recoverer = Some(recoverer.clone()); + self + } + + pub fn onchain_wallet(&mut self, onchain_wallet: Arc) -> &mut Self { + self.onchain_wallet = Some(onchain_wallet.clone()); + self + } + + pub fn persister(&mut self, persister: Arc) -> &mut Self { + self.persister = Some(persister.clone()); + self + } + + pub fn rest_client(&mut self, rest_client: Arc) -> &mut Self { + self.rest_client = Some(rest_client.clone()); + self + } + + pub fn status_stream(&mut self, status_stream: Arc) -> &mut Self { + self.status_stream = Some(status_stream.clone()); + self + } + + pub fn swapper(&mut self, swapper: Arc) -> &mut Self { + self.swapper = Some(swapper.clone()); + self + } + + pub fn sync_service(&mut self, sync_service: Arc) -> &mut Self { + self.sync_service = Some(sync_service.clone()); + self + } + + pub fn build(&self) -> Result> { + if let Some(breez_api_key) = &self.config.breez_api_key { + LiquidSdk::validate_breez_api_key(breez_api_key)? + } + + fs::create_dir_all(&self.config.working_dir)?; + let fingerprint_hex: String = + Xpub::decode(self.signer.xpub()?.as_slice())?.identifier()[0..4].to_hex(); + let working_dir = self + .config + .get_wallet_dir(&self.config.working_dir, &fingerprint_hex)?; + let cache_dir = self.config.get_wallet_dir( + self.config + .cache_dir + .as_ref() + .unwrap_or(&self.config.working_dir), + &fingerprint_hex, + )?; + + let sync_enabled = self + .config + .sync_service_url + .clone() + .map(|_| true) + .unwrap_or(false); + + let persister = match self.persister.clone() { + Some(persister) => persister, + None => { + let persister = Arc::new(Persister::new( + &working_dir, + self.config.network, + sync_enabled, + )?); + persister.init()?; + persister.replace_asset_metadata(self.config.asset_metadata.clone())?; + persister + } + }; + + let rest_client: Arc = match self.rest_client.clone() { + Some(rest_client) => rest_client, + None => Arc::new(ReqwestRestClient::new()?), + }; + + let bitcoin_chain_service: Arc = + match self.bitcoin_chain_service.clone() { + Some(bitcoin_chain_service) => bitcoin_chain_service, + None => Arc::new(HybridBitcoinChainService::new( + self.config.clone(), + rest_client.clone(), + )?), + }; + + let liquid_chain_service: Arc = + match self.liquid_chain_service.clone() { + Some(liquid_chain_service) => liquid_chain_service, + None => Arc::new(HybridLiquidChainService::new(self.config.clone())?), + }; + + let onchain_wallet: Arc = match self.onchain_wallet.clone() { + Some(onchain_wallet) => onchain_wallet, + None => Arc::new(LiquidOnchainWallet::new( + self.config.clone(), + &cache_dir, + persister.clone(), + self.signer.clone(), + )?), + }; + + let event_manager = Arc::new(EventManager::new()); + let (shutdown_sender, shutdown_receiver) = watch::channel::<()>(()); + + let swapper: Arc = match self.swapper.clone() { + Some(swapper) => swapper, + None => { + let proxy_url_fetcher = Arc::new(BoltzProxyFetcher::new(persister.clone())); + Arc::new(BoltzSwapper::new(self.config.clone(), proxy_url_fetcher)) + } + }; + + let status_stream: Arc = match self.status_stream.clone() { + Some(status_stream) => status_stream, + None => Arc::from(swapper.create_status_stream()), + }; + + let recoverer = match self.recoverer.clone() { + Some(recoverer) => recoverer, + None => Arc::new(Recoverer::new( + self.signer.slip77_master_blinding_key()?, + swapper.clone(), + onchain_wallet.clone(), + liquid_chain_service.clone(), + bitcoin_chain_service.clone(), + )?), + }; + + let sync_service = match self.sync_service.clone() { + Some(sync_service) => Some(sync_service), + None => match self.config.sync_service_url.clone() { + Some(sync_service_url) => { + if BREEZ_SYNC_SERVICE_URL == sync_service_url + && self.config.breez_api_key.is_none() + { + anyhow::bail!( + "Cannot start the Breez real-time sync service without providing a valid API key. See https://sdk-doc-liquid.breez.technology/guide/getting_started.html#api-key", + ); + } + + let syncer_client = + Box::new(BreezSyncerClient::new(self.config.breez_api_key.clone())); + Some(Arc::new(SyncService::new( + sync_service_url, + persister.clone(), + recoverer.clone(), + self.signer.clone(), + syncer_client, + ))) + } + None => None, + }, + }; + + let send_swap_handler = SendSwapHandler::new( + self.config.clone(), + onchain_wallet.clone(), + persister.clone(), + swapper.clone(), + liquid_chain_service.clone(), + ); + + let receive_swap_handler = ReceiveSwapHandler::new( + self.config.clone(), + onchain_wallet.clone(), + persister.clone(), + swapper.clone(), + liquid_chain_service.clone(), + ); + + let chain_swap_handler = Arc::new(ChainSwapHandler::new( + self.config.clone(), + onchain_wallet.clone(), + persister.clone(), + swapper.clone(), + liquid_chain_service.clone(), + bitcoin_chain_service.clone(), + )?); + + let buy_bitcoin_service = Arc::new(BuyBitcoinService::new( + self.config.clone(), + self.breez_server.clone(), + )); + + let external_input_parsers = self.config.get_all_external_input_parsers(); + + let sdk = Arc::new(LiquidSdk { + config: self.config.clone(), + onchain_wallet, + signer: self.signer.clone(), + persister: persister.clone(), + rest_client, + event_manager, + status_stream: status_stream.clone(), + swapper, + recoverer, + bitcoin_chain_service, + liquid_chain_service, + fiat_api: self.breez_server.clone(), + is_started: RwLock::new(false), + shutdown_sender, + shutdown_receiver, + send_swap_handler, + receive_swap_handler, + sync_service, + chain_swap_handler, + buy_bitcoin_service, + external_input_parsers, + }); + Ok(sdk) + } +} + pub struct LiquidSdk { pub(crate) config: Config, pub(crate) onchain_wallet: Arc, pub(crate) signer: Arc>, pub(crate) persister: Arc, + pub(crate) rest_client: Arc, pub(crate) event_manager: Arc, pub(crate) status_stream: Arc, pub(crate) swapper: Arc, @@ -135,7 +408,12 @@ impl LiquidSdk { req: ConnectWithSignerRequest, signer: Box, ) -> Result> { - let sdk = LiquidSdk::new(req.config, Arc::new(signer))?; + let sdk = LiquidSdkBuilder::new( + req.config, + PRODUCTION_BREEZSERVER_URL.into(), + Arc::new(signer), + )? + .build()?; sdk.start() .inspect_err(|e| error!("Failed to start an SDK instance: {:?}", e)) .await?; @@ -167,129 +445,6 @@ impl LiquidSdk { Ok(()) } - fn new(config: Config, signer: Arc>) -> Result> { - if let Some(breez_api_key) = &config.breez_api_key { - Self::validate_breez_api_key(breez_api_key)? - } - - fs::create_dir_all(&config.working_dir)?; - let fingerprint_hex: String = - Xpub::decode(signer.xpub()?.as_slice())?.identifier()[0..4].to_hex(); - let working_dir = config.get_wallet_dir(&config.working_dir, &fingerprint_hex)?; - let cache_dir = config.get_wallet_dir( - config.cache_dir.as_ref().unwrap_or(&config.working_dir), - &fingerprint_hex, - )?; - - let sync_enabled = config - .sync_service_url - .clone() - .map(|_| true) - .unwrap_or(false); - let persister = Arc::new(Persister::new(&working_dir, config.network, sync_enabled)?); - persister.init()?; - persister.replace_asset_metadata(config.asset_metadata.clone())?; - - let liquid_chain_service = Arc::new(HybridLiquidChainService::new(config.clone())?); - let bitcoin_chain_service = Arc::new(HybridBitcoinChainService::new(config.clone())?); - - let onchain_wallet = Arc::new(LiquidOnchainWallet::new( - config.clone(), - &cache_dir, - persister.clone(), - signer.clone(), - )?); - - let event_manager = Arc::new(EventManager::new()); - let (shutdown_sender, shutdown_receiver) = watch::channel::<()>(()); - - let proxy_url_fetcher = Arc::new(BoltzProxyFetcher::new(persister.clone())); - let swapper = Arc::new(BoltzSwapper::new(config.clone(), proxy_url_fetcher)); - let status_stream = Arc::::from(swapper.create_status_stream()); - - let recoverer = Arc::new(Recoverer::new( - signer.slip77_master_blinding_key()?, - swapper.clone(), - onchain_wallet.clone(), - liquid_chain_service.clone(), - bitcoin_chain_service.clone(), - )?); - - let mut sync_service = None; - if let Some(sync_service_url) = config.sync_service_url.clone() { - if BREEZ_SYNC_SERVICE_URL == sync_service_url && config.breez_api_key.is_none() { - anyhow::bail!( - "Cannot start the Breez real-time sync service without providing a valid API key. See https://sdk-doc-liquid.breez.technology/guide/getting_started.html#api-key", - ); - } - - let syncer_client = Box::new(BreezSyncerClient::new(config.breez_api_key.clone())); - sync_service = Some(Arc::new(SyncService::new( - sync_service_url, - persister.clone(), - recoverer.clone(), - signer.clone(), - syncer_client, - ))); - } - - let send_swap_handler = SendSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - ); - - let receive_swap_handler = ReceiveSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - ); - - let chain_swap_handler = Arc::new(ChainSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - bitcoin_chain_service.clone(), - )?); - - let breez_server = Arc::new(BreezServer::new(PRODUCTION_BREEZSERVER_URL.into(), None)?); - - let buy_bitcoin_service = - Arc::new(BuyBitcoinService::new(config.clone(), breez_server.clone())); - - let external_input_parsers = config.get_all_external_input_parsers(); - - let sdk = Arc::new(LiquidSdk { - config: config.clone(), - onchain_wallet, - signer: signer.clone(), - persister: persister.clone(), - event_manager, - status_stream: status_stream.clone(), - swapper, - recoverer, - bitcoin_chain_service, - liquid_chain_service, - fiat_api: breez_server, - is_started: RwLock::new(false), - shutdown_sender, - shutdown_receiver, - send_swap_handler, - receive_swap_handler, - sync_service, - chain_swap_handler, - buy_bitcoin_service, - external_input_parsers, - }); - Ok(sdk) - } - /// Starts an SDK instance. /// /// Internal method. Should only be called once per instance. @@ -3296,6 +3451,7 @@ impl LiquidSdk { }; match validate_lnurl_pay( + self.rest_client.as_ref(), amount_msat, &req.comment, &req.data, @@ -3492,7 +3648,9 @@ impl LiquidSdk { }); }; - let res = validate_lnurl_withdraw(req.data.clone(), invoice.clone()).await?; + let res = + validate_lnurl_withdraw(self.rest_client.as_ref(), req.data.clone(), invoice.clone()) + .await?; if let LnUrlWithdrawResult::Ok { data: _ } = res { if let Some(ReceiveSwap { claim_tx_id: Some(tx_id), @@ -3526,7 +3684,12 @@ impl LiquidSdk { &self, req_data: LnUrlAuthRequestData, ) -> Result { - Ok(perform_lnurl_auth(&req_data, &SdkLnurlAuthSigner::new(self.signer.clone())).await?) + Ok(perform_lnurl_auth( + self.rest_client.as_ref(), + &req_data, + &SdkLnurlAuthSigner::new(self.signer.clone()), + ) + .await?) } /// Register for webhook callbacks at the given `webhook_url`. Each created swap after registering the @@ -3591,9 +3754,10 @@ impl LiquidSdk { /// Can optionally be configured to use external input parsers by providing `external_input_parsers` in [Config]. pub async fn parse(&self, input: &str) -> Result { let external_parsers = &self.external_input_parsers; - let input_type = parse(input, Some(external_parsers)) - .await - .map_err(|e| PaymentError::generic(&e.to_string()))?; + let input_type = + parse_with_rest_client(self.rest_client.as_ref(), input, Some(external_parsers)) + .await + .map_err(|e| PaymentError::generic(&e.to_string()))?; let res = match input_type { InputType::LiquidAddress { ref address } => match &address.asset_id { @@ -3691,6 +3855,9 @@ mod tests { }; use paste::paste; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + struct NewSwapArgs { direction: Direction, accepts_zero_conf: bool, @@ -3811,7 +3978,7 @@ mod tests { }}; } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_receive_swap_update_tracking() -> Result<()> { create_persister!(persister); let swapper = Arc::new(MockSwapper::default()); @@ -3819,14 +3986,14 @@ mod tests { let liquid_chain_service = Arc::new(MockLiquidChainService::new()); let bitcoin_chain_service = Arc::new(MockBitcoinChainService::new()); - let sdk = Arc::new(new_liquid_sdk_with_chain_services( + let sdk = new_liquid_sdk_with_chain_services( persister.clone(), swapper.clone(), status_stream.clone(), liquid_chain_service.clone(), bitcoin_chain_service.clone(), None, - )?); + )?; LiquidSdk::track_swap_updates(&sdk); @@ -3927,7 +4094,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_send_swap_update_tracking() -> Result<()> { create_persister!(persister); let swapper = Arc::new(MockSwapper::default()); @@ -3983,7 +4150,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_chain_swap_update_tracking() -> Result<()> { create_persister!(persister); let swapper = Arc::new(MockSwapper::default()); @@ -3991,14 +4158,14 @@ mod tests { let liquid_chain_service = Arc::new(MockLiquidChainService::new()); let bitcoin_chain_service = Arc::new(MockBitcoinChainService::new()); - let sdk = Arc::new(new_liquid_sdk_with_chain_services( + let sdk = new_liquid_sdk_with_chain_services( persister.clone(), swapper.clone(), status_stream.clone(), liquid_chain_service.clone(), bitcoin_chain_service.clone(), None, - )?); + )?; LiquidSdk::track_swap_updates(&sdk); @@ -4214,7 +4381,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_zero_amount_chain_swap_zero_leeway() -> Result<()> { let user_lockup_sat = 50_000; @@ -4224,14 +4391,14 @@ mod tests { let liquid_chain_service = Arc::new(MockLiquidChainService::new()); let bitcoin_chain_service = Arc::new(MockBitcoinChainService::new()); - let sdk = Arc::new(new_liquid_sdk_with_chain_services( + let sdk = new_liquid_sdk_with_chain_services( persister.clone(), swapper.clone(), status_stream.clone(), liquid_chain_service.clone(), bitcoin_chain_service.clone(), None, - )?); + )?; LiquidSdk::track_swap_updates(&sdk); @@ -4274,7 +4441,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_zero_amount_chain_swap_with_leeway() -> Result<()> { let user_lockup_sat = 50_000; let onchain_fee_rate_leeway_sat_per_vbyte = 5; @@ -4285,14 +4452,14 @@ mod tests { let liquid_chain_service = Arc::new(MockLiquidChainService::new()); let bitcoin_chain_service = Arc::new(MockBitcoinChainService::new()); - let sdk = Arc::new(new_liquid_sdk_with_chain_services( + let sdk = new_liquid_sdk_with_chain_services( persister.clone(), swapper.clone(), status_stream.clone(), liquid_chain_service.clone(), bitcoin_chain_service.clone(), Some(onchain_fee_rate_leeway_sat_per_vbyte), - )?); + )?; LiquidSdk::track_swap_updates(&sdk); diff --git a/lib/core/src/send_swap.rs b/lib/core/src/send_swap.rs index 4df93fe..fb1435b 100644 --- a/lib/core/src/send_swap.rs +++ b/lib/core/src/send_swap.rs @@ -2,7 +2,6 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::{str::FromStr, sync::Arc}; use anyhow::{anyhow, Result}; -use async_trait::async_trait; use boltz_client::swaps::boltz; use boltz_client::swaps::{boltz::CreateSubmarineResponse, boltz::SubSwapStates}; use futures_util::TryFutureExt; @@ -38,7 +37,7 @@ pub(crate) struct SendSwapHandler { subscription_notifier: broadcast::Sender, } -#[async_trait] +#[sdk_macros::async_trait] impl BlockListener for SendSwapHandler { async fn on_bitcoin_block(&self, _height: u32) {} @@ -610,7 +609,10 @@ mod tests { }, }; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_send_swap_state_transitions() -> Result<()> { create_persister!(storage); let send_swap_handler = new_send_swap_handler(storage.clone())?; diff --git a/lib/core/src/signer.rs b/lib/core/src/signer.rs index d07a643..e77b947 100644 --- a/lib/core/src/signer.rs +++ b/lib/core/src/signer.rs @@ -299,6 +299,9 @@ mod tests { }; use std::collections::BTreeMap; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + fn get_descriptor( signer: &S, is_mainnet: bool, @@ -363,7 +366,7 @@ mod tests { pset } - #[test] + #[sdk_macros::test_all] fn test_invalid_signer() { let mut rng = rand::thread_rng(); @@ -382,7 +385,7 @@ mod tests { assert!(SdkSigner::new_with_seed(seed2.to_vec(), false).is_ok()); } - #[test] + #[sdk_macros::test_all] fn test_sign() { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let (sw_signer, sdk_signer) = create_signers(mnemonic); @@ -408,7 +411,7 @@ mod tests { assert_eq!(tx_sw, tx_sdk); } - #[test] + #[sdk_macros::test_all] fn test_slip77_master_blinding_key() { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let (sw_signer, sdk_signer) = create_signers(mnemonic); @@ -422,7 +425,7 @@ mod tests { ); } - #[test] + #[sdk_macros::test_all] fn test_derive_xpub() { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let (sw_signer, sdk_signer) = create_signers(mnemonic); @@ -434,7 +437,7 @@ mod tests { assert_eq!(sw_xpub, sdk_xpub, "Derived xpubs should be identical"); } - #[test] + #[sdk_macros::test_all] fn test_identifier() { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let (sw_signer, sdk_signer) = create_signers(mnemonic); @@ -448,7 +451,7 @@ mod tests { ); } - #[test] + #[sdk_macros::test_all] fn test_fingerprint() { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let (sw_signer, sdk_signer) = create_signers(mnemonic); @@ -469,7 +472,7 @@ mod tests { ); } - #[test] + #[sdk_macros::test_all] fn test_sdk_signer_vs_sw_signer() { // Use a test mnemonic (don't use this in production!) let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; diff --git a/lib/core/src/swapper/boltz/mod.rs b/lib/core/src/swapper/boltz/mod.rs index 1113a9f..c92ac38 100644 --- a/lib/core/src/swapper/boltz/mod.rs +++ b/lib/core/src/swapper/boltz/mod.rs @@ -6,7 +6,6 @@ use crate::{ prelude::{ChainSwap, Config, Direction, LiquidNetwork, SendSwap, Swap, Transaction, Utxo}, }; use anyhow::Result; -use async_trait::async_trait; use boltz_client::{ boltz::{ BoltzApiClientV2, ChainPair, Cooperative, CreateChainRequest, CreateChainResponse, @@ -154,7 +153,7 @@ impl BoltzSwapper

{ } } -#[async_trait] +#[sdk_macros::async_trait] impl Swapper for BoltzSwapper

{ /// Create a new chain swap async fn create_chain_swap( diff --git a/lib/core/src/swapper/boltz/proxy.rs b/lib/core/src/swapper/boltz/proxy.rs index 3bc5090..a97a835 100644 --- a/lib/core/src/swapper/boltz/proxy.rs +++ b/lib/core/src/swapper/boltz/proxy.rs @@ -1,7 +1,6 @@ use std::sync::{Arc, OnceLock}; use anyhow::Result; -use async_trait::async_trait; use sdk_common::prelude::BreezServer; use url::Url; @@ -37,7 +36,7 @@ impl BoltzProxyFetcher { } } -#[async_trait] +#[sdk_macros::async_trait] impl ProxyUrlFetcher for BoltzProxyFetcher { async fn fetch(&self) -> Result<&Option> { if let Some(swapper_proxy_url) = self.url.get() { diff --git a/lib/core/src/swapper/mod.rs b/lib/core/src/swapper/mod.rs index 46c3d6d..17d7962 100644 --- a/lib/core/src/swapper/mod.rs +++ b/lib/core/src/swapper/mod.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use anyhow::Result; -use async_trait::async_trait; use boltz_client::{ boltz::{ ChainPair, CreateChainRequest, CreateChainResponse, CreateReverseRequest, @@ -23,7 +22,7 @@ pub(crate) use subscription_handler::*; pub(crate) mod boltz; pub(crate) mod subscription_handler; -#[async_trait] +#[sdk_macros::async_trait] pub trait Swapper: Send + Sync { /// Create a new chain swap async fn create_chain_swap( @@ -144,7 +143,7 @@ pub trait SwapperStatusStream: Send + Sync { fn subscribe_swap_updates(&self) -> broadcast::Receiver; } -#[async_trait] +#[sdk_macros::async_trait] pub(crate) trait ProxyUrlFetcher: Send + Sync + 'static { async fn fetch(&self) -> Result<&Option>; } diff --git a/lib/core/src/swapper/subscription_handler.rs b/lib/core/src/swapper/subscription_handler.rs index 4cf2054..a069f03 100644 --- a/lib/core/src/swapper/subscription_handler.rs +++ b/lib/core/src/swapper/subscription_handler.rs @@ -1,13 +1,12 @@ use std::sync::Arc; -use async_trait::async_trait; use log::{error, info}; use crate::persist::Persister; use super::SwapperStatusStream; -#[async_trait] +#[sdk_macros::async_trait] pub trait SubscriptionHandler: Send + Sync { async fn subscribe_swaps(&self); } @@ -30,7 +29,7 @@ impl SwapperSubscriptionHandler { } } -#[async_trait] +#[sdk_macros::async_trait] impl SubscriptionHandler for SwapperSubscriptionHandler { async fn subscribe_swaps(&self) { match self.persister.list_ongoing_swaps() { diff --git a/lib/core/src/sync/client.rs b/lib/core/src/sync/client.rs index af282d7..b550340 100644 --- a/lib/core/src/sync/client.rs +++ b/lib/core/src/sync/client.rs @@ -2,7 +2,6 @@ use std::time::Duration; use anyhow::{anyhow, Error, Result}; -use async_trait::async_trait; use log::debug; use tokio::sync::Mutex; use tonic::{ @@ -17,7 +16,7 @@ use super::model::{ ListenChangesRequest, Notification, SetRecordReply, SetRecordRequest, }; -#[async_trait] +#[sdk_macros::async_trait] pub(crate) trait SyncerClient: Send + Sync { async fn connect(&self, connect_url: String) -> Result<()>; async fn push(&self, req: SetRecordRequest) -> Result; @@ -78,7 +77,7 @@ impl BreezSyncerClient { } } -#[async_trait] +#[sdk_macros::async_trait] impl SyncerClient for BreezSyncerClient { async fn connect(&self, connect_url: String) -> Result<()> { let mut grpc_channel = self.grpc_channel.lock().await; diff --git a/lib/core/src/sync/mod.rs b/lib/core/src/sync/mod.rs index 9dd7b0f..e3364de 100644 --- a/lib/core/src/sync/mod.rs +++ b/lib/core/src/sync/mod.rs @@ -556,7 +556,10 @@ mod tests { use super::model::{data::SyncData, Record, RecordType}; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_incoming_sync_create_and_update() -> Result<()> { create_persister!(persister); let signer: Arc> = Arc::new(Box::new(MockSigner::new()?)); @@ -656,7 +659,7 @@ mod tests { Ok(record) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_outgoing_sync() -> Result<()> { create_persister!(persister); let signer: Arc> = Arc::new(Box::new(MockSigner::new()?)); @@ -776,7 +779,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_sync_clean() -> Result<()> { create_persister!(persister); let signer: Arc> = Arc::new(Box::new(MockSigner::new()?)); @@ -843,7 +846,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[sdk_macros::async_test_all] async fn test_last_derivation_index_update() -> Result<()> { create_persister!(persister); let signer: Arc> = Arc::new(Box::new(MockSigner::new()?)); diff --git a/lib/core/src/test_utils/chain.rs b/lib/core/src/test_utils/chain.rs index 7e8d8c7..1ec074d 100644 --- a/lib/core/src/test_utils/chain.rs +++ b/lib/core/src/test_utils/chain.rs @@ -3,7 +3,6 @@ use std::sync::Mutex; use anyhow::Result; -use async_trait::async_trait; use boltz_client::{ elements::{ hex::FromHex, OutPoint as ElementsOutPoint, Script as ElementsScript, @@ -67,7 +66,7 @@ impl MockLiquidChainService { } } -#[async_trait] +#[sdk_macros::async_trait] impl LiquidChainService for MockLiquidChainService { async fn tip(&self) -> Result { Ok(0) @@ -165,7 +164,7 @@ impl MockBitcoinChainService { } } -#[async_trait] +#[sdk_macros::async_trait] impl BitcoinChainService for MockBitcoinChainService { fn tip(&self) -> Result { Ok(HeaderNotification { diff --git a/lib/core/src/test_utils/sdk.rs b/lib/core/src/test_utils/sdk.rs index 4169e1f..c1c5c2f 100644 --- a/lib/core/src/test_utils/sdk.rs +++ b/lib/core/src/test_utils/sdk.rs @@ -1,21 +1,14 @@ #![cfg(test)] use anyhow::{anyhow, Result}; -use sdk_common::prelude::{BreezServer, STAGING_BREEZSERVER_URL}; +use sdk_common::prelude::{MockRestClient, RestClient, STAGING_BREEZSERVER_URL}; use std::sync::Arc; -use tokio::sync::{watch, RwLock}; - use crate::{ - buy::BuyBitcoinService, - chain_swap::ChainSwapHandler, - event::EventManager, model::{Config, Signer}, persist::Persister, - receive_swap::ReceiveSwapHandler, recover::recoverer::Recoverer, - sdk::LiquidSdk, - send_swap::SendSwapHandler, + sdk::{LiquidSdk, LiquidSdkBuilder}, }; use super::{ @@ -30,7 +23,7 @@ pub(crate) fn new_liquid_sdk( persister: Arc, swapper: Arc, status_stream: Arc, -) -> Result { +) -> Result> { let liquid_chain_service = Arc::new(MockLiquidChainService::new()); let bitcoin_chain_service = Arc::new(MockBitcoinChainService::new()); @@ -51,7 +44,7 @@ pub(crate) fn new_liquid_sdk_with_chain_services( liquid_chain_service: Arc, bitcoin_chain_service: Arc, onchain_fee_rate_leeway_sat_per_vbyte: Option, -) -> Result { +) -> Result> { let mut config = Config::testnet(None); config.working_dir = persister .get_database_dir() @@ -61,33 +54,8 @@ pub(crate) fn new_liquid_sdk_with_chain_services( config.onchain_fee_rate_leeway_sat_per_vbyte = onchain_fee_rate_leeway_sat_per_vbyte; let signer: Arc> = Arc::new(Box::new(MockSigner::new()?)); + let rest_client: Arc = Arc::new(MockRestClient::new()); let onchain_wallet = Arc::new(MockWallet::new(signer.clone())?); - - let send_swap_handler = SendSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - ); - - let receive_swap_handler = ReceiveSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - ); - - let chain_swap_handler = Arc::new(ChainSwapHandler::new( - config.clone(), - onchain_wallet.clone(), - persister.clone(), - swapper.clone(), - liquid_chain_service.clone(), - bitcoin_chain_service.clone(), - )?); - let recoverer = Arc::new(Recoverer::new( signer.slip77_master_blinding_key()?, swapper.clone(), @@ -96,38 +64,19 @@ pub(crate) fn new_liquid_sdk_with_chain_services( bitcoin_chain_service.clone(), )?); - let event_manager = Arc::new(EventManager::new()); - let (shutdown_sender, shutdown_receiver) = watch::channel::<()>(()); - - let breez_server = Arc::new(BreezServer::new(STAGING_BREEZSERVER_URL.into(), None)?); - - let buy_bitcoin_service = - Arc::new(BuyBitcoinService::new(config.clone(), breez_server.clone())); - let (_incoming_tx, _outgoing_records, sync_service) = new_sync_service(persister.clone(), recoverer.clone(), signer.clone())?; - let sync_service = Some(Arc::new(sync_service)); + let sync_service = Arc::new(sync_service); - Ok(LiquidSdk { - config, - onchain_wallet, - signer, - persister, - event_manager, - status_stream, - swapper, - recoverer, - liquid_chain_service, - bitcoin_chain_service, - fiat_api: breez_server, - is_started: RwLock::new(true), - shutdown_sender, - shutdown_receiver, - send_swap_handler, - receive_swap_handler, - sync_service, - chain_swap_handler, - buy_bitcoin_service, - external_input_parsers: Vec::new(), - }) + LiquidSdkBuilder::new(config, STAGING_BREEZSERVER_URL.into(), signer)? + .bitcoin_chain_service(bitcoin_chain_service) + .liquid_chain_service(liquid_chain_service) + .onchain_wallet(onchain_wallet) + .persister(persister) + .recoverer(recoverer) + .rest_client(rest_client) + .status_stream(status_stream) + .swapper(swapper) + .sync_service(sync_service) + .build() } diff --git a/lib/core/src/test_utils/swapper.rs b/lib/core/src/test_utils/swapper.rs index 878b25c..277af76 100644 --- a/lib/core/src/test_utils/swapper.rs +++ b/lib/core/src/test_utils/swapper.rs @@ -1,7 +1,6 @@ #![cfg(test)] use anyhow::Result; -use async_trait::async_trait; use boltz_client::{ boltz::{ ChainFees, ChainMinerFees, ChainPair, ChainSwapDetails, CreateChainResponse, @@ -113,7 +112,7 @@ impl MockSwapper { } } -#[async_trait] +#[sdk_macros::async_trait] impl Swapper for MockSwapper { async fn create_chain_swap( &self, @@ -385,7 +384,7 @@ impl MockProxyUrlFetcher { } } -#[async_trait] +#[sdk_macros::async_trait] impl ProxyUrlFetcher for MockProxyUrlFetcher { async fn fetch(&self) -> Result<&Option> { Ok(&None) diff --git a/lib/core/src/test_utils/sync.rs b/lib/core/src/test_utils/sync.rs index 7ae4dc6..11931cd 100644 --- a/lib/core/src/test_utils/sync.rs +++ b/lib/core/src/test_utils/sync.rs @@ -17,7 +17,6 @@ use crate::{ }, }; use anyhow::Result; -use async_trait::async_trait; use tokio::sync::{ mpsc::{self, Receiver, Sender}, Mutex, @@ -41,7 +40,7 @@ impl MockSyncerClient { } } -#[async_trait] +#[sdk_macros::async_trait] impl SyncerClient for MockSyncerClient { async fn connect(&self, _connect_url: String) -> Result<()> { todo!() diff --git a/lib/core/src/test_utils/wallet.rs b/lib/core/src/test_utils/wallet.rs index 10427d8..f0ad2d1 100644 --- a/lib/core/src/test_utils/wallet.rs +++ b/lib/core/src/test_utils/wallet.rs @@ -10,7 +10,6 @@ use crate::{ wallet::OnchainWallet, }; use anyhow::Result; -use async_trait::async_trait; use bip39::Mnemonic; use boltz_client::{Keypair, Secp256k1}; use lazy_static::lazy_static; @@ -42,7 +41,7 @@ impl MockWallet { } } -#[async_trait] +#[sdk_macros::async_trait] impl OnchainWallet for MockWallet { async fn transactions(&self) -> Result, PaymentError> { Ok(vec![]) diff --git a/lib/core/src/utils.rs b/lib/core/src/utils.rs index c59bc9a..b5bc217 100644 --- a/lib/core/src/utils.rs +++ b/lib/core/src/utils.rs @@ -176,7 +176,10 @@ mod tests { use crate::error::PaymentError; use crate::utils::verify_payment_hash; - #[test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::test_all] fn test_verify_payment_hash() -> anyhow::Result<()> { let bolt11_invoice = "lnbc10u1pnczjaupp55392fur38rc2y9vzmhdy0tclvfels0lvlmzgvmhpg6q2mndxzmrsdqqcqzzsxqyz5vqsp5ya6pvchlsvl3mzqh3zw4hg3tz5pww77q6rcwfr52qchyrp7s6krs9p4gqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqysgqgnp0sskk0ljjew8vkc3udhzgquzs79evf5wezfaex9q4gjk5qcn8m3luauyte93lgassd8skh5m90glhtt52ry2wtftzrjn4h076z7sqdjry3d"; let bolt11_preimage = "c17a0a28d0523596ec909c2d439c0c2315b5bd996bf4ff48be50b2df08fb8ac1"; diff --git a/lib/core/src/wallet.rs b/lib/core/src/wallet.rs index e1085e7..94601e3 100644 --- a/lib/core/src/wallet.rs +++ b/lib/core/src/wallet.rs @@ -6,7 +6,6 @@ use std::time::Instant; use std::{path::Path, str::FromStr, sync::Arc}; use anyhow::{anyhow, Result}; -use async_trait::async_trait; use boltz_client::ElementsAddress; use log::{debug, info, warn}; use lwk_common::Signer as LwkSigner; @@ -34,7 +33,7 @@ use lwk_wollet::secp256k1::Message; static LN_MESSAGE_PREFIX: &[u8] = b"Lightning Signed Message:"; -#[async_trait] +#[sdk_macros::async_trait] pub trait OnchainWallet: Send + Sync { /// List all transactions in the wallet async fn transactions(&self) -> Result, PaymentError>; @@ -183,7 +182,7 @@ impl LiquidOnchainWallet { } } -#[async_trait] +#[sdk_macros::async_trait] impl OnchainWallet for LiquidOnchainWallet { /// List all transactions in the wallet async fn transactions(&self) -> Result, PaymentError> { @@ -441,7 +440,10 @@ mod tests { use anyhow::Result; use tempdir::TempDir; - #[tokio::test] + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + + #[sdk_macros::async_test_all] async fn test_sign_and_check_message() -> Result<()> { let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; let sdk_signer: Box = Box::new(SdkSigner::new(mnemonic, "", false).unwrap()); diff --git a/lib/wasm/Cargo.toml b/lib/wasm/Cargo.toml index 29a0012..c23626d 100644 --- a/lib/wasm/Cargo.toml +++ b/lib/wasm/Cargo.toml @@ -11,6 +11,13 @@ crate-type = ["cdylib"] workspace = true [dependencies] +anyhow = { workspace = true } breez-sdk-liquid = { path = "../core" } +console_log = "1" +js-sys = "0.3.77" +log = { workspace = true } +sdk-macros = { workspace = true } +serde = { workspace = true } +tsify-next = "0.5.5" wasm-bindgen = "0.2.100" wasm-bindgen-futures = "0.4.50" diff --git a/lib/wasm/Makefile b/lib/wasm/Makefile new file mode 100644 index 0000000..c8e0b99 --- /dev/null +++ b/lib/wasm/Makefile @@ -0,0 +1,23 @@ +UNAME := $(shell uname) + +ifeq ($(UNAME), Darwin) + CLANG_PREFIX += AR=$(shell brew --prefix llvm)/bin/llvm-ar CC=$(shell brew --prefix llvm)/bin/clang +endif + +init: + cargo install wasm-pack + +clippy: + $(CLANG_PREFIX) cargo clippy --target=wasm32-unknown-unknown -- -D warnings + +pack: + $(CLANG_PREFIX) wasm-pack build --weak-refs --target web --scope @breeztech + +test: + $(CLANG_PREFIX) wasm-pack test --headless --firefox + +test-chrome: + $(CLANG_PREFIX) wasm-pack test --headless --chrome + +test-safari: + $(CLANG_PREFIX) wasm-pack test --headless --safari diff --git a/lib/wasm/src/error.rs b/lib/wasm/src/error.rs new file mode 100644 index 0000000..e6eaf56 --- /dev/null +++ b/lib/wasm/src/error.rs @@ -0,0 +1,51 @@ +use breez_sdk_liquid::{ + error::{PaymentError, SdkError}, + LnUrlAuthError, LnUrlPayError, LnUrlWithdrawError, +}; +use std::fmt::Display; +use wasm_bindgen::{JsError, JsValue}; + +#[derive(Clone, Debug)] +pub struct WasmError(JsValue); + +impl WasmError { + pub fn new(val: T) -> Self { + WasmError(JsValue::from(format!("{}", val))) + } +} + +impl From for JsValue { + fn from(err: WasmError) -> Self { + err.0 + } +} + +impl From for WasmError { + fn from(err: JsValue) -> Self { + Self(err) + } +} + +macro_rules! wasm_error_wrapper { + ($($t:ty),*) => { + $( + impl From<$t> for WasmError { + fn from(err: $t) -> Self { + WasmError(JsError::new(format!("{}", err).as_str()).into()) + } + } + )* + } +} + +wasm_error_wrapper!( + anyhow::Error, + LnUrlAuthError, + LnUrlPayError, + LnUrlWithdrawError, + log::ParseLevelError, + PaymentError, + SdkError, + &str, + String +); diff --git a/lib/wasm/src/event.rs b/lib/wasm/src/event.rs new file mode 100644 index 0000000..8bfb49f --- /dev/null +++ b/lib/wasm/src/event.rs @@ -0,0 +1,27 @@ +use wasm_bindgen::prelude::*; + +use crate::model::SdkEvent; + +pub struct WasmEventListener { + pub listener: EventListener, +} + +impl breez_sdk_liquid::prelude::EventListener for WasmEventListener { + fn on_event(&self, e: breez_sdk_liquid::prelude::SdkEvent) { + self.listener.on_event(e.into()); + } +} + +#[wasm_bindgen(typescript_custom_section)] +const EVENT_INTERFACE: &'static str = r#"export interface EventListener { + onEvent: (e: SdkEvent) => void; +}"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "EventListener")] + pub type EventListener; + + #[wasm_bindgen(structural, method, js_name = onEvent)] + pub fn on_event(this: &EventListener, e: SdkEvent); +} diff --git a/lib/wasm/src/lib.rs b/lib/wasm/src/lib.rs index d0cbe1a..1c1f9e6 100644 --- a/lib/wasm/src/lib.rs +++ b/lib/wasm/src/lib.rs @@ -1,6 +1,320 @@ +mod error; +mod event; +pub mod model; +mod signer; + +use std::str::FromStr; +use std::sync::Arc; + +use anyhow::anyhow; +use breez_sdk_liquid::sdk::LiquidSdk; +use log::Level; +use signer::{Signer, WasmSigner}; use wasm_bindgen::prelude::*; +use crate::event::{EventListener, WasmEventListener}; +use crate::model::*; + #[wasm_bindgen] -pub struct LiquidSdk { - _inner: breez_sdk_liquid::sdk::LiquidSdk, +pub struct BindingLiquidSdk { + sdk: Arc, +} + +#[wasm_bindgen(js_name = "connect")] +pub async fn connect(req: ConnectRequest) -> WasmResult { + let sdk = LiquidSdk::connect(req.into()).await?; + Ok(BindingLiquidSdk { sdk }) +} + +#[wasm_bindgen(js_name = "connectWithSigner")] +pub async fn connect_with_signer( + req: ConnectWithSignerRequest, + signer: Signer, +) -> WasmResult { + let wasm_signer = Box::new(WasmSigner { signer }); + let sdk = LiquidSdk::connect_with_signer(req.into(), wasm_signer).await?; + Ok(BindingLiquidSdk { sdk }) +} + +#[wasm_bindgen(js_name = "defaultConfig")] +pub fn default_config(network: LiquidNetwork, breez_api_key: Option) -> WasmResult { + Ok(LiquidSdk::default_config(network.into(), breez_api_key)?.into()) +} + +#[wasm_bindgen(js_name = "parseInvoice")] +pub fn parse_invoice(input: String) -> WasmResult { + Ok(LiquidSdk::parse_invoice(&input)?.into()) +} + +#[wasm_bindgen(js_name = "initLogger")] +pub fn init_logger(level: String) -> WasmResult<()> { + Ok(console_log::init_with_level(Level::from_str(&level)?) + .map_err(|_| anyhow!("Logger already created"))?) +} + +#[wasm_bindgen] +impl BindingLiquidSdk { + #[wasm_bindgen(js_name = "getInfo")] + pub async fn get_info(&self) -> WasmResult { + Ok(self.sdk.get_info().await?.into()) + } + + #[wasm_bindgen(js_name = "signMessage")] + pub fn sign_message(&self, req: SignMessageRequest) -> WasmResult { + Ok(self.sdk.sign_message(&req.into())?.into()) + } + + #[wasm_bindgen(js_name = "checkMessage")] + pub fn check_message(&self, req: CheckMessageRequest) -> WasmResult { + Ok(self.sdk.check_message(&req.into())?.into()) + } + + #[wasm_bindgen(js_name = "parse")] + pub async fn parse(&self, input: String) -> WasmResult { + Ok(self.sdk.parse(&input).await?.into()) + } + + #[wasm_bindgen(js_name = "addEventListener")] + pub async fn add_event_listener(&self, listener: EventListener) -> WasmResult { + Ok(self + .sdk + .add_event_listener(Box::new(WasmEventListener { listener })) + .await?) + } + + #[wasm_bindgen(js_name = "removeEventListener")] + pub async fn remove_event_listener(&self, id: String) -> WasmResult<()> { + self.sdk.remove_event_listener(id).await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "prepareSendPayment")] + pub async fn prepare_send_payment( + &self, + req: PrepareSendRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_send_payment(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "sendPayment")] + pub async fn send_payment(&self, req: SendPaymentRequest) -> WasmResult { + Ok(self.sdk.send_payment(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "preparePeceivePayment")] + pub async fn prepare_receive_payment( + &self, + req: PrepareReceiveRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_receive_payment(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "receivePayment")] + pub async fn receive_payment( + &self, + req: ReceivePaymentRequest, + ) -> WasmResult { + Ok(self.sdk.receive_payment(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "fetchLightningLimits")] + pub async fn fetch_lightning_limits(&self) -> WasmResult { + Ok(self.sdk.fetch_lightning_limits().await?.into()) + } + + #[wasm_bindgen(js_name = "fetchOnchainLimits")] + pub async fn fetch_onchain_limits(&self) -> WasmResult { + Ok(self.sdk.fetch_onchain_limits().await?.into()) + } + + #[wasm_bindgen(js_name = "preparePayOnchain")] + pub async fn prepare_pay_onchain( + &self, + req: PreparePayOnchainRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_pay_onchain(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "payOnchain")] + pub async fn pay_onchain(&self, req: PayOnchainRequest) -> WasmResult { + Ok(self.sdk.pay_onchain(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "prepareBuyBitcoin")] + pub async fn prepare_buy_bitcoin( + &self, + req: PrepareBuyBitcoinRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_buy_bitcoin(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "buyBitcoin")] + pub async fn buy_bitcoin(&self, req: BuyBitcoinRequest) -> WasmResult { + Ok(self.sdk.buy_bitcoin(&req.into()).await?) + } + + #[wasm_bindgen(js_name = "listPayments")] + pub async fn list_payments(&self, req: ListPaymentsRequest) -> WasmResult> { + Ok(self + .sdk + .list_payments(&req.into()) + .await? + .into_iter() + .map(|r| r.into()) + .collect()) + } + + #[wasm_bindgen(js_name = "getPayment")] + pub async fn get_payment(&self, req: GetPaymentRequest) -> WasmResult> { + Ok(self.sdk.get_payment(&req.into()).await?.map(|r| r.into())) + } + + #[wasm_bindgen(js_name = "fetchPaymentProposedFees")] + pub async fn fetch_payment_proposed_fees( + &self, + req: FetchPaymentProposedFeesRequest, + ) -> WasmResult { + Ok(self + .sdk + .fetch_payment_proposed_fees(&req.into()) + .await? + .into()) + } + + #[wasm_bindgen(js_name = "acceptPaymentProposedFees")] + pub async fn accept_payment_proposed_fees( + &self, + req: AcceptPaymentProposedFeesRequest, + ) -> WasmResult<()> { + self.sdk.accept_payment_proposed_fees(&req.into()).await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "prepareLnurlPay")] + pub async fn prepare_lnurl_pay( + &self, + req: PrepareLnUrlPayRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_lnurl_pay(req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "lnurlPay")] + pub async fn lnurl_pay(&self, req: LnUrlPayRequest) -> WasmResult { + Ok(self.sdk.lnurl_pay(req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "lnurlWithdraw")] + pub async fn lnurl_withdraw( + &self, + req: LnUrlWithdrawRequest, + ) -> WasmResult { + Ok(self.sdk.lnurl_withdraw(req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "lnurlAuth")] + pub async fn lnurl_auth( + &self, + req_data: LnUrlAuthRequestData, + ) -> WasmResult { + Ok(self.sdk.lnurl_auth(req_data.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "registerWebhook")] + pub async fn register_webhook(&self, webhook_url: String) -> WasmResult<()> { + self.sdk.register_webhook(webhook_url).await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "unregisterWebhook")] + pub async fn unregister_webhook(&self) -> WasmResult<()> { + self.sdk.unregister_webhook().await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "fetchFiatRates")] + pub async fn fetch_fiat_rates(&self) -> WasmResult> { + Ok(self + .sdk + .fetch_fiat_rates() + .await? + .into_iter() + .map(|r| r.into()) + .collect()) + } + + #[wasm_bindgen(js_name = "listFiatCurrencies")] + pub async fn list_fiat_currencies(&self) -> WasmResult> { + Ok(self + .sdk + .list_fiat_currencies() + .await? + .into_iter() + .map(|r| r.into()) + .collect()) + } + + #[wasm_bindgen(js_name = "listRefundables")] + pub async fn list_refundables(&self) -> WasmResult> { + Ok(self + .sdk + .list_refundables() + .await? + .into_iter() + .map(|r| r.into()) + .collect()) + } + + #[wasm_bindgen(js_name = "prepareRefund")] + pub async fn prepare_refund( + &self, + req: PrepareRefundRequest, + ) -> WasmResult { + Ok(self.sdk.prepare_refund(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "refund")] + pub async fn refund(&self, req: RefundRequest) -> WasmResult { + Ok(self.sdk.refund(&req.into()).await?.into()) + } + + #[wasm_bindgen(js_name = "rescanOnchainSwaps")] + pub async fn rescan_onchain_swaps(&self) -> WasmResult<()> { + self.sdk.rescan_onchain_swaps().await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "sync")] + pub async fn sync(&self) -> WasmResult<()> { + self.sdk.sync(false).await?; + Ok(()) + } + + #[wasm_bindgen(js_name = "recommendedFees")] + pub async fn recommended_fees(&self) -> WasmResult { + Ok(self.sdk.recommended_fees().await?.into()) + } + + #[wasm_bindgen(js_name = "emptyWalletCache")] + pub fn empty_wallet_cache(&self) -> WasmResult<()> { + self.sdk.empty_wallet_cache()?; + Ok(()) + } + + #[wasm_bindgen(js_name = "backup")] + pub fn backup(&self, req: BackupRequest) -> WasmResult<()> { + self.sdk.backup(req.into())?; + Ok(()) + } + + #[wasm_bindgen(js_name = "restore")] + pub fn restore(&self, req: RestoreRequest) -> WasmResult<()> { + self.sdk.restore(req.into())?; + Ok(()) + } + + #[wasm_bindgen(js_name = "disconnect")] + pub async fn disconnect(&self) -> WasmResult<()> { + self.sdk.disconnect().await?; + Ok(()) + } } diff --git a/lib/wasm/src/model.rs b/lib/wasm/src/model.rs new file mode 100644 index 0000000..3d47e9f --- /dev/null +++ b/lib/wasm/src/model.rs @@ -0,0 +1,798 @@ +use crate::error::WasmError; + +pub type WasmResult = Result; + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Network)] +pub enum Network { + Bitcoin, + Testnet, + Signet, + Regtest, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ExternalInputParser)] +pub struct ExternalInputParser { + pub provider_id: String, + pub input_regex: String, + pub parser_url: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LNInvoice)] +pub struct LNInvoice { + pub bolt11: String, + pub network: Network, + pub payee_pubkey: String, + pub payment_hash: String, + pub description: Option, + pub description_hash: Option, + pub amount_msat: Option, + pub timestamp: u64, + pub expiry: u64, + pub routing_hints: Vec, + pub payment_secret: Vec, + pub min_final_cltv_expiry_delta: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RouteHint)] +pub struct RouteHint { + pub hops: Vec, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RouteHintHop)] +pub struct RouteHintHop { + pub src_node_id: String, + pub short_channel_id: String, + pub fees_base_msat: u32, + pub fees_proportional_millionths: u32, + pub cltv_expiry_delta: u64, + pub htlc_minimum_msat: Option, + pub htlc_maximum_msat: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Amount)] +pub enum Amount { + Bitcoin { + amount_msat: u64, + }, + Currency { + iso4217_code: String, + fractional_amount: u64, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnOfferBlindedPath)] +pub struct LnOfferBlindedPath { + pub blinded_hops: Vec, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LNOffer)] +pub struct LNOffer { + pub offer: String, + pub chains: Vec, + pub min_amount: Option, + pub description: Option, + pub absolute_expiry: Option, + pub issuer: Option, + pub signing_pubkey: Option, + pub paths: Vec, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::InputType)] +pub enum InputType { + BitcoinAddress { + address: BitcoinAddressData, + }, + LiquidAddress { + address: LiquidAddressData, + }, + Bolt11 { + invoice: LNInvoice, + }, + Bolt12Offer { + offer: LNOffer, + bip353_address: Option, + }, + NodeId { + node_id: String, + }, + Url { + url: String, + }, + LnUrlPay { + data: LnUrlPayRequestData, + bip353_address: Option, + }, + LnUrlWithdraw { + data: LnUrlWithdrawRequestData, + }, + LnUrlAuth { + data: LnUrlAuthRequestData, + }, + LnUrlError { + data: LnUrlErrorData, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::BitcoinAddressData)] +pub struct BitcoinAddressData { + pub address: String, + pub network: breez_sdk_liquid::prelude::Network, + pub amount_sat: Option, + pub label: Option, + pub message: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LiquidAddressData)] +pub struct LiquidAddressData { + pub address: String, + pub network: Network, + pub asset_id: Option, + pub amount: Option, + pub amount_sat: Option, + pub label: Option, + pub message: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlPayRequestData)] +pub struct LnUrlPayRequestData { + pub callback: String, + pub min_sendable: u64, + pub max_sendable: u64, + pub metadata_str: String, + pub comment_allowed: u16, + pub domain: String, + pub allows_nostr: bool, + pub nostr_pubkey: Option, + pub ln_address: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SuccessAction)] +pub enum SuccessAction { + Aes { data: AesSuccessActionData }, + Message { data: MessageSuccessActionData }, + Url { data: UrlSuccessActionData }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SuccessActionProcessed)] +pub enum SuccessActionProcessed { + Aes { result: AesSuccessActionDataResult }, + Message { data: MessageSuccessActionData }, + Url { data: UrlSuccessActionData }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AesSuccessActionData)] +pub struct AesSuccessActionData { + pub description: String, + pub ciphertext: String, + pub iv: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AesSuccessActionDataResult)] +pub enum AesSuccessActionDataResult { + Decrypted { data: AesSuccessActionDataDecrypted }, + ErrorStatus { reason: String }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AesSuccessActionDataDecrypted)] +pub struct AesSuccessActionDataDecrypted { + pub description: String, + pub plaintext: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::MessageSuccessActionData)] +pub struct MessageSuccessActionData { + pub message: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::UrlSuccessActionData)] +pub struct UrlSuccessActionData { + pub description: String, + pub url: String, + pub matches_callback_domain: bool, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlPayErrorData)] +pub struct LnUrlPayErrorData { + pub payment_hash: String, + pub reason: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlWithdrawRequestData)] +pub struct LnUrlWithdrawRequestData { + pub callback: String, + pub k1: String, + pub default_description: String, + pub min_withdrawable: u64, + pub max_withdrawable: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlCallbackStatus)] +pub enum LnUrlCallbackStatus { + Ok, + #[serde(rename = "ERROR")] + ErrorStatus { + #[serde(flatten)] + data: LnUrlErrorData, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlAuthRequestData)] +pub struct LnUrlAuthRequestData { + pub k1: String, + pub action: Option, + pub domain: String, + pub url: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlErrorData)] +pub struct LnUrlErrorData { + pub reason: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlWithdrawRequest)] +pub struct LnUrlWithdrawRequest { + pub data: LnUrlWithdrawRequestData, + pub amount_msat: u64, + pub description: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlWithdrawSuccessData)] +pub struct LnUrlWithdrawSuccessData { + pub invoice: LNInvoice, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlWithdrawResult)] +pub enum LnUrlWithdrawResult { + Ok { data: LnUrlWithdrawSuccessData }, + Timeout { data: LnUrlWithdrawSuccessData }, + ErrorStatus { data: LnUrlErrorData }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Rate)] +pub struct Rate { + pub coin: String, + pub value: f64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::FiatCurrency)] +pub struct FiatCurrency { + pub id: String, + pub info: CurrencyInfo, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::CurrencyInfo)] +pub struct CurrencyInfo { + pub name: String, + pub fraction_size: u32, + pub spacing: Option, + pub symbol: Option, + pub uniq_symbol: Option, + pub localized_name: Vec, + pub locale_overrides: Vec, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LocaleOverrides)] +pub struct LocaleOverrides { + pub locale: String, + pub spacing: Option, + pub symbol: Symbol, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LocalizedName)] +pub struct LocalizedName { + pub locale: String, + pub name: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Symbol)] +pub struct Symbol { + pub grapheme: Option, + pub template: Option, + pub rtl: Option, + pub position: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Config)] +pub struct Config { + pub liquid_electrum_url: String, + pub bitcoin_electrum_url: String, + pub mempoolspace_url: String, + pub working_dir: String, + pub cache_dir: Option, + pub network: LiquidNetwork, + pub payment_timeout_sec: u64, + pub sync_service_url: Option, + pub zero_conf_max_amount_sat: Option, + pub breez_api_key: Option, + pub external_input_parsers: Option>, + pub use_default_external_input_parsers: bool, + pub onchain_fee_rate_leeway_sat_per_vbyte: Option, + pub asset_metadata: Option>, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LiquidNetwork)] +pub enum LiquidNetwork { + Mainnet, + Testnet, + Regtest, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SdkEvent)] +pub enum SdkEvent { + PaymentFailed { details: Payment }, + PaymentPending { details: Payment }, + PaymentRefundable { details: Payment }, + PaymentRefunded { details: Payment }, + PaymentRefundPending { details: Payment }, + PaymentSucceeded { details: Payment }, + PaymentWaitingConfirmation { details: Payment }, + PaymentWaitingFeeAcceptance { details: Payment }, + Synced, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ConnectRequest)] +pub struct ConnectRequest { + pub config: Config, + pub mnemonic: Option, + pub passphrase: Option, + pub seed: Option>, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ConnectWithSignerRequest)] +pub struct ConnectWithSignerRequest { + pub config: Config, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PaymentMethod)] +pub enum PaymentMethod { + Lightning, + BitcoinAddress, + LiquidAddress, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ReceiveAmount)] +pub enum ReceiveAmount { + Bitcoin { + payer_amount_sat: u64, + }, + Asset { + asset_id: String, + payer_amount: Option, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareReceiveRequest)] +pub struct PrepareReceiveRequest { + pub payment_method: PaymentMethod, + pub amount: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareReceiveResponse)] +pub struct PrepareReceiveResponse { + pub payment_method: PaymentMethod, + pub amount: Option, + pub fees_sat: u64, + pub min_payer_amount_sat: Option, + pub max_payer_amount_sat: Option, + pub swapper_feerate: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ReceivePaymentRequest)] +pub struct ReceivePaymentRequest { + pub prepare_response: PrepareReceiveResponse, + pub description: Option, + pub use_description_hash: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ReceivePaymentResponse)] +pub struct ReceivePaymentResponse { + pub destination: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Limits)] +pub struct Limits { + pub min_sat: u64, + pub max_sat: u64, + pub max_zero_conf_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LightningPaymentLimitsResponse)] +pub struct LightningPaymentLimitsResponse { + pub send: Limits, + pub receive: Limits, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::OnchainPaymentLimitsResponse)] +pub struct OnchainPaymentLimitsResponse { + pub send: Limits, + pub receive: Limits, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareSendRequest)] +pub struct PrepareSendRequest { + pub destination: String, + pub amount: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SendDestination)] +pub enum SendDestination { + LiquidAddress { + address_data: LiquidAddressData, + }, + Bolt11 { + invoice: LNInvoice, + bip353_address: Option, + }, + Bolt12 { + offer: LNOffer, + receiver_amount_sat: u64, + bip353_address: Option, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareSendResponse)] +pub struct PrepareSendResponse { + pub destination: SendDestination, + pub fees_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SendPaymentRequest)] +pub struct SendPaymentRequest { + pub prepare_response: PrepareSendResponse, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SendPaymentResponse)] +pub struct SendPaymentResponse { + pub payment: Payment, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PayAmount)] +pub enum PayAmount { + Bitcoin { + receiver_amount_sat: u64, + }, + Asset { + asset_id: String, + receiver_amount: f64, + }, + Drain, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PreparePayOnchainRequest)] +pub struct PreparePayOnchainRequest { + pub amount: PayAmount, + pub fee_rate_sat_per_vbyte: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PreparePayOnchainResponse)] +pub struct PreparePayOnchainResponse { + pub receiver_amount_sat: u64, + pub claim_fees_sat: u64, + pub total_fees_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PayOnchainRequest)] +pub struct PayOnchainRequest { + pub address: String, + pub prepare_response: PreparePayOnchainResponse, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareRefundRequest)] +pub struct PrepareRefundRequest { + pub swap_address: String, + pub refund_address: String, + pub fee_rate_sat_per_vbyte: u32, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareRefundResponse)] +pub struct PrepareRefundResponse { + pub tx_vsize: u32, + pub tx_fee_sat: u64, + pub last_refund_tx_id: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RefundRequest)] +pub struct RefundRequest { + pub swap_address: String, + pub refund_address: String, + pub fee_rate_sat_per_vbyte: u32, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RefundResponse)] +pub struct RefundResponse { + pub refund_tx_id: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AssetBalance)] +pub struct AssetBalance { + pub asset_id: String, + pub balance_sat: u64, + pub name: Option, + pub ticker: Option, + pub balance: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::BlockchainInfo)] +pub struct BlockchainInfo { + pub liquid_tip: u32, + pub bitcoin_tip: u32, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::WalletInfo)] +pub struct WalletInfo { + pub balance_sat: u64, + pub pending_send_sat: u64, + pub pending_receive_sat: u64, + pub fingerprint: String, + pub pubkey: String, + pub asset_balances: Vec, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::GetInfoResponse)] +pub struct GetInfoResponse { + pub wallet_info: WalletInfo, + pub blockchain_info: BlockchainInfo, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SignMessageRequest)] +pub struct SignMessageRequest { + pub message: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::SignMessageResponse)] +pub struct SignMessageResponse { + pub signature: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::CheckMessageRequest)] +pub struct CheckMessageRequest { + pub message: String, + pub pubkey: String, + pub signature: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::CheckMessageResponse)] +pub struct CheckMessageResponse { + pub is_valid: bool, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::BackupRequest)] +pub struct BackupRequest { + pub backup_path: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RestoreRequest)] +pub struct RestoreRequest { + pub backup_path: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ListPaymentsRequest)] +pub struct ListPaymentsRequest { + pub filters: Option>, + pub states: Option>, + pub from_timestamp: Option, + pub to_timestamp: Option, + pub offset: Option, + pub limit: Option, + pub details: Option, + pub sort_ascending: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::ListPaymentDetails)] +pub enum ListPaymentDetails { + Liquid { + asset_id: Option, + destination: Option, + }, + Bitcoin { + address: Option, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::GetPaymentRequest)] +pub enum GetPaymentRequest { + PaymentHash { payment_hash: String }, + SwapId { swap_id: String }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RefundableSwap)] +pub struct RefundableSwap { + pub swap_address: String, + pub timestamp: u32, + pub amount_sat: u64, + pub last_refund_tx_id: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PaymentState)] +pub enum PaymentState { + Created = 0, + Pending = 1, + Complete = 2, + Failed = 3, + TimedOut = 4, + Refundable = 5, + RefundPending = 6, + WaitingFeeAcceptance = 7, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PaymentType)] +pub enum PaymentType { + Receive = 0, + Send = 1, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PaymentStatus)] +pub enum PaymentStatus { + Pending = 0, + Complete = 1, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LnUrlInfo)] +pub struct LnUrlInfo { + pub ln_address: Option, + pub lnurl_pay_comment: Option, + pub lnurl_pay_domain: Option, + pub lnurl_pay_metadata: Option, + pub lnurl_pay_success_action: Option, + pub lnurl_pay_unprocessed_success_action: Option, + pub lnurl_withdraw_endpoint: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AssetMetadata)] +pub struct AssetMetadata { + pub asset_id: String, + pub name: String, + pub ticker: String, + pub precision: u8, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AssetInfo)] +pub struct AssetInfo { + pub name: String, + pub ticker: String, + pub amount: f64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PaymentDetails)] +#[allow(clippy::large_enum_variant)] +pub enum PaymentDetails { + Lightning { + swap_id: String, + description: String, + liquid_expiration_blockheight: u32, + preimage: Option, + invoice: Option, + bolt12_offer: Option, + payment_hash: Option, + destination_pubkey: Option, + lnurl_info: Option, + bip353_address: Option, + claim_tx_id: Option, + refund_tx_id: Option, + refund_tx_amount_sat: Option, + }, + Liquid { + destination: String, + description: String, + asset_id: String, + asset_info: Option, + }, + Bitcoin { + swap_id: String, + description: String, + auto_accepted_fees: bool, + liquid_expiration_blockheight: Option, + bitcoin_expiration_blockheight: Option, + claim_tx_id: Option, + refund_tx_id: Option, + refund_tx_amount_sat: Option, + }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::Payment)] +pub struct Payment { + pub destination: Option, + pub tx_id: Option, + pub unblinding_data: Option, + pub timestamp: u32, + pub amount_sat: u64, + pub fees_sat: u64, + pub swapper_fees_sat: Option, + pub payment_type: PaymentType, + pub status: PaymentState, + pub details: PaymentDetails, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::RecommendedFees)] +pub struct RecommendedFees { + pub fastest_fee: u64, + pub half_hour_fee: u64, + pub hour_fee: u64, + pub economy_fee: u64, + pub minimum_fee: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::BuyBitcoinProvider)] +pub enum BuyBitcoinProvider { + Moonpay, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareBuyBitcoinRequest)] +pub struct PrepareBuyBitcoinRequest { + pub provider: BuyBitcoinProvider, + pub amount_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareBuyBitcoinResponse)] +pub struct PrepareBuyBitcoinResponse { + pub provider: BuyBitcoinProvider, + pub amount_sat: u64, + pub fees_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::BuyBitcoinRequest)] +pub struct BuyBitcoinRequest { + pub prepare_response: PrepareBuyBitcoinResponse, + pub redirect_url: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::LogEntry)] +pub struct LogEntry { + pub line: String, + pub level: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareLnUrlPayRequest)] +pub struct PrepareLnUrlPayRequest { + pub data: LnUrlPayRequestData, + pub amount: PayAmount, + pub bip353_address: Option, + pub comment: Option, + pub validate_success_action_url: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareLnUrlPayResponse)] +pub struct PrepareLnUrlPayResponse { + pub destination: SendDestination, + pub fees_sat: u64, + pub data: LnUrlPayRequestData, + pub comment: Option, + pub success_action: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::model::LnUrlPayRequest)] +pub struct LnUrlPayRequest { + pub prepare_response: PrepareLnUrlPayResponse, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::model::LnUrlPayResult)] +#[allow(clippy::large_enum_variant)] +pub enum LnUrlPayResult { + EndpointSuccess { data: LnUrlPaySuccessData }, + EndpointError { data: LnUrlErrorData }, + PayError { data: LnUrlPayErrorData }, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::model::LnUrlPaySuccessData)] +pub struct LnUrlPaySuccessData { + pub payment: Payment, + pub success_action: Option, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::FetchPaymentProposedFeesRequest)] +pub struct FetchPaymentProposedFeesRequest { + pub swap_id: String, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::FetchPaymentProposedFeesResponse)] +pub struct FetchPaymentProposedFeesResponse { + pub swap_id: String, + pub fees_sat: u64, + pub payer_amount_sat: u64, + pub receiver_amount_sat: u64, +} + +#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::AcceptPaymentProposedFeesRequest)] +pub struct AcceptPaymentProposedFeesRequest { + pub response: FetchPaymentProposedFeesResponse, +} diff --git a/lib/wasm/src/signer.rs b/lib/wasm/src/signer.rs new file mode 100644 index 0000000..35f0f74 --- /dev/null +++ b/lib/wasm/src/signer.rs @@ -0,0 +1,120 @@ +use breez_sdk_liquid::prelude::SignerError; +use wasm_bindgen::prelude::*; + +pub struct WasmSigner { + pub signer: Signer, +} + +impl breez_sdk_liquid::prelude::Signer for WasmSigner { + fn xpub(&self) -> Result, SignerError> { + self.signer.xpub().map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn derive_xpub(&self, derivation_path: String) -> Result, SignerError> { + self.signer + .derive_xpub(derivation_path) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn sign_ecdsa(&self, msg: Vec, derivation_path: String) -> Result, SignerError> { + self.signer + .sign_ecdsa(msg, derivation_path) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn sign_ecdsa_recoverable(&self, msg: Vec) -> Result, SignerError> { + self.signer + .sign_ecdsa_recoverable(msg) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn slip77_master_blinding_key(&self) -> Result, SignerError> { + self.signer + .slip77_master_blinding_key() + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn hmac_sha256(&self, msg: Vec, derivation_path: String) -> Result, SignerError> { + self.signer + .hmac_sha256(msg, derivation_path) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn ecies_encrypt(&self, msg: Vec) -> Result, SignerError> { + self.signer + .ecies_encrypt(msg) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } + + fn ecies_decrypt(&self, msg: Vec) -> Result, SignerError> { + self.signer + .ecies_decrypt(msg) + .map_err(|e| SignerError::Generic { + err: e.to_string().into(), + }) + } +} + +#[wasm_bindgen(typescript_custom_section)] +const SIGNER_INTERFACE: &'static str = r#"export interface Signer { + xpub: () => number[]; + deriveXpub: (derivationPath: string) => number[]; + signEcdsa: (msg: number[], derivationPath: string) => number[]; + signEcdsaRecoverable: (msg: number[]) => number[]; + slip77MasterBlindingKey: () => number[]; + hmacSha256: (msg: number[], derivationPath: string) => number[]; + eciesEncrypt: (msg: number[]) => number[]; + eciesDecrypt: (msg: number[]) => number[]; +}"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "Signer")] + pub type Signer; + + #[wasm_bindgen(structural, catch, method, js_name = xpub)] + pub fn xpub(this: &Signer) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = deriveXpub)] + fn derive_xpub(this: &Signer, derivation_path: String) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = signEcdsa)] + fn sign_ecdsa( + this: &Signer, + msg: Vec, + derivation_path: String, + ) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = signEcdsaRecoverable)] + fn sign_ecdsa_recoverable(this: &Signer, msg: Vec) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = slip77MasterBlindingKey)] + fn slip77_master_blinding_key(this: &Signer) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = hmacSha256)] + fn hmac_sha256( + this: &Signer, + msg: Vec, + derivation_path: String, + ) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = eciesEncrypt)] + fn ecies_encrypt(this: &Signer, msg: Vec) -> Result, js_sys::Error>; + + #[wasm_bindgen(structural, catch, method, js_name = eciesDecrypt)] + fn ecies_decrypt(this: &Signer, msg: Vec) -> Result, js_sys::Error>; +}