WASM: db backups (#851)

* WASM: db backups

* Address review feedback

* Log backup recovery errors and proceed
This commit is contained in:
Daniel Granhão
2025-04-06 10:03:33 +01:00
committed by GitHub
parent 59ab0578d6
commit 42a489722b
26 changed files with 733 additions and 107 deletions

330
lib/Cargo.lock generated
View File

@@ -2,6 +2,18 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "accessory"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb3791c4beae5b827e93558ac83a88e63a841aad61759a05d9b577ef16030470"
dependencies = [
"macroific",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "addr2line"
version = "0.24.2"
@@ -756,7 +768,7 @@ dependencies = [
"electrum-client",
"elements",
"env_logger 0.7.1",
"getrandom 0.2.14",
"getrandom 0.2.15",
"hex",
"js-sys",
"lightning-invoice 0.32.0",
@@ -786,12 +798,12 @@ dependencies = [
"derivative",
"ecies",
"electrum-client",
"env_logger 0.11.7",
"env_logger 0.11.8",
"esplora-client",
"flutter_rust_bridge",
"futures",
"futures-util",
"getrandom 0.2.14",
"getrandom 0.2.15",
"glob",
"gloo-timers",
"hex",
@@ -863,13 +875,21 @@ dependencies = [
"anyhow",
"breez-sdk-liquid",
"console_log",
"getrandom 0.2.15",
"indexed_db_futures",
"js-sys",
"log",
"rand 0.8.5",
"sdk-common",
"sdk-macros",
"serde",
"tokio",
"tsify-next",
"uuid",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test",
"web-time",
]
[[package]]
@@ -1038,9 +1058,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.32"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
dependencies = [
"clap_builder",
"clap_derive 4.5.32",
@@ -1048,9 +1068,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.32"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
dependencies = [
"anstream",
"anstyle",
@@ -1281,6 +1301,20 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "delegate-display"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9926686c832494164c33a36bf65118f4bd6e704000b58c94681bf62e9ad67a74"
dependencies = [
"impartial-ord",
"itoa",
"macroific",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "der-parser"
version = "9.0.0"
@@ -1315,6 +1349,27 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"unicode-xid",
]
[[package]]
name = "digest"
version = "0.9.0"
@@ -1358,9 +1413,9 @@ dependencies = [
[[package]]
name = "dnssec-prover"
version = "0.6.6"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96487aad690d45a83f2b9876828ba856c5430bbb143cb5730d8a5d04a4805179"
checksum = "48f9e1163868b86c37d43c586af9d917e699c87f1266ebfdf356ad1003458118"
[[package]]
name = "downcast"
@@ -1370,12 +1425,12 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
[[package]]
name = "ecies"
version = "0.2.7"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0206e602d2645ec8b24ed8307fadbc6c3110e2b11ab2f806fc02fee49327079"
checksum = "011318cc6f4f1906c1dae015013fd381e92deac290a29ddcd9f2e0dd14786037"
dependencies = [
"aes-gcm",
"getrandom 0.2.14",
"getrandom 0.2.15",
"hkdf",
"libsecp256k1",
"once_cell",
@@ -1490,9 +1545,9 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.11.7"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
@@ -1543,6 +1598,18 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fancy_constructor"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fac0fd7f4636276b4bd7b3148d0ba2c1c3fbede2b5214e47e7fedb70b02cde44"
dependencies = [
"macroific",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "fastrand"
version = "2.3.0"
@@ -1701,9 +1768,9 @@ dependencies = [
[[package]]
name = "fragile"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
[[package]]
name = "fs-err"
@@ -1830,9 +1897,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@@ -2332,9 +2399,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
dependencies = [
"bytes",
"futures-channel",
@@ -2342,6 +2409,7 @@ dependencies = [
"http 1.3.1",
"http-body 1.0.1",
"hyper 1.6.0",
"libc",
"pin-project-lite",
"socket2",
"tokio",
@@ -2418,9 +2486,9 @@ dependencies = [
[[package]]
name = "iana-time-zone"
version = "0.1.62"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -2428,7 +2496,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
"windows-core 0.61.0",
]
[[package]]
@@ -2481,9 +2549,9 @@ dependencies = [
[[package]]
name = "icu_locid_transform_data"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
[[package]]
name = "icu_normalizer"
@@ -2505,9 +2573,9 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
[[package]]
name = "icu_properties"
@@ -2526,9 +2594,9 @@ dependencies = [
[[package]]
name = "icu_properties_data"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
[[package]]
name = "icu_provider"
@@ -2579,6 +2647,17 @@ dependencies = [
"icu_properties",
]
[[package]]
name = "impartial-ord"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "include_dir"
version = "0.7.4"
@@ -2598,6 +2677,40 @@ dependencies = [
"quote",
]
[[package]]
name = "indexed_db_futures"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94eebf0199c01a1560770d964efb1fb09183a3afc0b1c1397fac1bfdbfa7d6cf"
dependencies = [
"accessory",
"cfg-if 1.0.0",
"delegate-display",
"derive_more",
"fancy_constructor",
"indexed_db_futures_macros_internal",
"js-sys",
"sealed",
"smallvec",
"thiserror 2.0.12",
"tokio",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "indexed_db_futures_macros_internal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caeba94923b68f254abef921cea7e7698bf4675fdd89d7c58bf1ed885b49a27d"
dependencies = [
"macroific",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -2968,7 +3081,7 @@ dependencies = [
"base64 0.21.7",
"elements",
"elements-miniscript",
"getrandom 0.2.14",
"getrandom 0.2.15",
"qr_code",
"rand 0.8.5",
"thiserror 1.0.69",
@@ -3018,6 +3131,54 @@ dependencies = [
"web-sys",
]
[[package]]
name = "macroific"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285"
dependencies = [
"macroific_attr_parse",
"macroific_core",
"macroific_macro",
]
[[package]]
name = "macroific_attr_parse"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9"
dependencies = [
"proc-macro2",
"quote",
"sealed",
"syn 2.0.100",
]
[[package]]
name = "macroific_core"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3"
dependencies = [
"proc-macro2",
"quote",
"sealed",
"syn 2.0.100",
]
[[package]]
name = "macroific_macro"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b"
dependencies = [
"macroific_attr_parse",
"macroific_core",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "macros"
version = "0.0.0"
@@ -3093,9 +3254,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniscript"
version = "12.3.0"
version = "12.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d"
checksum = "82911d2fb527bb9aacd2446d2f517aff3f8e3846ace1b3c24258b61ea3cce2bc"
dependencies = [
"bech32 0.11.0",
"bitcoin 0.32.5",
@@ -3262,9 +3423,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.21.1"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
dependencies = [
"critical-section",
"portable-atomic",
@@ -3536,7 +3697,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b122a615d72104fb3d8b26523fdf9232cd8ee06949fb37e4ce3ff964d15dffd"
dependencies = [
"getrandom 0.2.14",
"getrandom 0.2.15",
]
[[package]]
@@ -3824,9 +3985,9 @@ dependencies = [
[[package]]
name = "quinn-udp"
version = "0.5.10"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944"
checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
dependencies = [
"cfg_aliases",
"libc",
@@ -3927,7 +4088,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.14",
"getrandom 0.2.15",
]
[[package]]
@@ -4177,7 +4338,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if 1.0.0",
"getrandom 0.2.14",
"getrandom 0.2.15",
"libc",
"untrusted 0.9.0",
"windows-sys 0.52.0",
@@ -4291,9 +4452,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.3"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
dependencies = [
"bitflags 2.9.0",
"errno",
@@ -4336,7 +4497,7 @@ dependencies = [
"once_cell",
"ring 0.17.14",
"rustls-pki-types",
"rustls-webpki 0.103.0",
"rustls-webpki 0.103.1",
"subtle",
"zeroize",
]
@@ -4392,9 +4553,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.103.0"
version = "0.103.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f"
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
dependencies = [
"ring 0.17.14",
"rustls-pki-types",
@@ -4536,7 +4697,7 @@ dependencies = [
"cbc",
"dns-parser",
"elements",
"getrandom 0.2.14",
"getrandom 0.2.15",
"hex",
"hickory-resolver",
"lazy_static",
@@ -4577,6 +4738,17 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "sealed"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "secp256k1"
version = "0.24.3"
@@ -4840,9 +5012,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "socket2"
version = "0.5.8"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
dependencies = [
"libc",
"windows-sys 0.52.0",
@@ -5030,7 +5202,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.2",
"once_cell",
"rustix 1.0.3",
"rustix 1.0.5",
"windows-sys 0.59.0",
]
@@ -5648,6 +5820,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "uniffi"
version = "0.23.0"
@@ -5670,7 +5848,7 @@ checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f"
dependencies = [
"anyhow",
"camino",
"clap 4.5.32",
"clap 4.5.35",
"uniffi_bindgen 0.25.3",
"uniffi_build 0.25.3",
"uniffi_core 0.25.3",
@@ -5686,7 +5864,7 @@ dependencies = [
"anyhow",
"camino",
"cargo_metadata",
"clap 4.5.32",
"clap 4.5.35",
"uniffi_bindgen 0.28.3",
"uniffi_build 0.28.3",
"uniffi_core 0.28.3",
@@ -5727,7 +5905,7 @@ dependencies = [
"askama 0.12.1",
"camino",
"cargo_metadata",
"clap 4.5.32",
"clap 4.5.35",
"fs-err",
"glob",
"goblin 0.6.1",
@@ -5773,7 +5951,7 @@ dependencies = [
"anyhow",
"askama 0.12.1",
"camino",
"clap 4.5.32",
"clap 4.5.35",
"heck 0.4.1",
"include_dir",
"paste",
@@ -6403,7 +6581,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
dependencies = [
"windows-core",
"windows-core 0.52.0",
"windows-targets 0.52.6",
]
@@ -6416,6 +6594,41 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings 0.4.0",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "windows-link"
version = "0.1.1"
@@ -6429,7 +6642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result",
"windows-strings",
"windows-strings 0.3.1",
"windows-targets 0.53.0",
]
@@ -6451,6 +6664,15 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@@ -14,6 +14,7 @@ frb = ["dep:flutter_rust_bridge"]
uniffi-25 = []
uniffi-28 = []
regtest = [] # Enable regtest tests
test-utils = ["sdk-common/test-utils"]
[lints]
workspace = true
@@ -31,10 +32,6 @@ log = { workspace = true }
lwk_common = "0.9.0"
lwk_signer = { version = "0.9.0", default-features = false }
mockall = "0.13.1"
rusqlite = { git = "https://github.com/Spxg/rusqlite", rev = "e36644127f31fa6e7ea0999b59432deb4a07f220", features = [
"backup",
"bundled",
] }
tokio = { version = "1", default-features = false, features = ["rt", "macros"] }
tokio_with_wasm = { version = "0.8.2", features = [
"macros",
@@ -80,6 +77,10 @@ prost = "^0.11"
tonic = { version = "^0.8", features = ["tls", "tls-webpki-roots"] }
uuid = { version = "1.8.0", features = ["v4"] }
boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", rev = "f78e159fe72e1c357e7830bc08d2b9e42a65362c", features = ["electrum"] }
rusqlite = { git = "https://github.com/Spxg/rusqlite", rev = "e36644127f31fa6e7ea0999b59432deb4a07f220", features = [
"backup",
"bundled",
] }
# Wasm dependencies
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
@@ -95,6 +96,11 @@ tonic = { version = "0.12", default-features = false, features = [
"prost",
] }
boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", rev = "f78e159fe72e1c357e7830bc08d2b9e42a65362c" }
rusqlite = { git = "https://github.com/Spxg/rusqlite", rev = "e36644127f31fa6e7ea0999b59432deb4a07f220", features = [
"backup",
"bundled",
"serialize"
] }
[dev-dependencies]
sdk-common = { workspace = true, features = ["test-utils"] }

View File

@@ -186,6 +186,10 @@ pub(crate) mod send_swap;
pub(crate) mod signer;
pub(crate) mod swapper;
pub(crate) mod sync;
#[cfg(feature = "test-utils")]
pub mod test_utils;
#[cfg(test)]
#[cfg(not(feature = "test-utils"))]
pub(crate) mod test_utils;
#[allow(hidden_glob_reexports)]
pub(crate) mod utils;

View File

@@ -248,11 +248,7 @@ impl Config {
}
}
pub(crate) fn get_wallet_dir(
&self,
base_dir: &str,
fingerprint_hex: &str,
) -> anyhow::Result<String> {
pub fn get_wallet_dir(&self, base_dir: &str, fingerprint_hex: &str) -> anyhow::Result<String> {
Ok(PathBuf::from(base_dir)
.join(match self.network {
LiquidNetwork::Mainnet => "mainnet",

View File

@@ -19,10 +19,11 @@ use crate::sync::model::RecordType;
use crate::{get_invoice_description, utils};
use anyhow::{anyhow, Result};
use boltz_client::boltz::{ChainPair, ReversePair, SubmarinePair};
use log::warn;
use log::{error, warn};
use lwk_wollet::WalletTx;
use migrations::current_migrations;
use model::PaymentTxDetails;
use rusqlite::backup::Backup;
use rusqlite::{
params, params_from_iter, Connection, OptionalExtension, Row, ToSql, TransactionBehavior,
};
@@ -72,7 +73,7 @@ impl Persister {
if !main_db_dir.exists() {
std::fs::create_dir_all(&main_db_dir)?;
}
Self::new_inner(main_db_dir, network, sync_enabled, asset_metadata)
Self::new_inner(main_db_dir, network, sync_enabled, asset_metadata, None)
}
/// Creates a new Persister that only keeps data in memory.
@@ -85,9 +86,29 @@ impl Persister {
network: LiquidNetwork,
sync_enabled: bool,
asset_metadata: Option<Vec<AssetMetadata>>,
backup_bytes: Option<Vec<u8>>,
) -> Result<Self> {
let main_db_dir = PathBuf::from_str(database_id)?;
Self::new_inner(main_db_dir, network, sync_enabled, asset_metadata)
let backup_con = backup_bytes
.map(|data| {
let size = data.len();
let cursor = std::io::Cursor::new(data);
let mut conn = Connection::open_in_memory()?;
conn.deserialize_read_exact(rusqlite::DatabaseName::Main, cursor, size, false)?;
Ok::<Connection, anyhow::Error>(conn)
})
.transpose()
.unwrap_or_else(|e| {
error!("Failed to deserialize backup data: {e} - proceeding without it");
None
});
Self::new_inner(
main_db_dir,
network,
sync_enabled,
asset_metadata,
backup_con,
)
}
fn new_inner(
@@ -95,6 +116,7 @@ impl Persister {
network: LiquidNetwork,
sync_enabled: bool,
asset_metadata: Option<Vec<AssetMetadata>>,
backup_con: Option<Connection>,
) -> Result<Self> {
let mut sync_trigger = None;
if sync_enabled {
@@ -108,6 +130,17 @@ impl Persister {
sync_trigger,
};
if let Some(backup_con) = backup_con {
if let Err(e) = (|| {
let mut dst_con = persister.get_connection()?;
let backup = Backup::new(&backup_con, &mut dst_con)?;
backup.step(-1)?;
Ok::<(), anyhow::Error>(())
})() {
error!("Failed to restore from backup: {e} - proceeding without it");
}
}
persister.init()?;
persister.replace_asset_metadata(asset_metadata)?;
@@ -125,7 +158,14 @@ impl Persister {
Ok(())
}
#[cfg(test)]
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub fn serialize(&self) -> Result<Vec<u8>> {
let con = self.get_connection()?;
let db_bytes = con.serialize(rusqlite::DatabaseName::Main)?;
Ok(db_bytes.to_vec())
}
#[cfg(any(test, feature = "test-utils"))]
pub(crate) fn get_database_dir(&self) -> &PathBuf {
&self.main_db_dir
}
@@ -1133,3 +1173,22 @@ mod tests {
Ok(())
}
}
#[cfg(feature = "test-utils")]
pub mod test_helpers {
use super::*;
impl Persister {
pub fn test_insert_or_update_send_swap(&self, swap: &SendSwap) -> Result<()> {
self.insert_or_update_send_swap(swap)
}
pub fn test_insert_or_update_receive_swap(&self, swap: &ReceiveSwap) -> Result<()> {
self.insert_or_update_receive_swap(swap)
}
pub fn test_list_ongoing_swaps(&self) -> Result<Vec<Swap>> {
self.list_ongoing_swaps()
}
}
}

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use std::sync::Mutex;
use crate::{

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use anyhow::Result;
use hex::FromHex;
use lazy_static::lazy_static;

View File

@@ -1,10 +1,10 @@
#![cfg(test)]
#![cfg_attr(feature = "test-utils", allow(dead_code))]
use bip39::rand::{self, distributions::Alphanumeric, Rng};
pub(crate) mod chain;
pub(crate) mod chain_swap;
pub(crate) mod persist;
pub mod persist;
pub(crate) mod receive_swap;
pub(crate) mod recover;
pub(crate) mod sdk;

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use bip39::rand::{self, RngCore};
use sdk_common::{
bitcoin::{
@@ -25,7 +23,7 @@ fn new_secret_key() -> SecretKey {
SecretKey::from_slice(&buf).expect("Expected valid secret key")
}
pub(crate) fn new_send_swap(
pub fn new_send_swap(
payment_state: Option<PaymentState>,
receiver_amount_sat: Option<u64>,
) -> SendSwap {
@@ -95,7 +93,7 @@ pub(crate) fn new_send_swap(
}
}
pub(crate) fn new_receive_swap(
pub fn new_receive_swap(
payment_state: Option<PaymentState>,
receiver_amount_sat: Option<u64>,
) -> ReceiveSwap {
@@ -124,6 +122,7 @@ pub(crate) fn new_receive_swap(
}
}
#[macro_export]
macro_rules! create_persister {
($name:ident) => {
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
@@ -137,11 +136,12 @@ macro_rules! create_persister {
.collect();
res
};
sdk_common::utils::Arc::new(crate::persist::Persister::new_in_memory(
sdk_common::utils::Arc::new($crate::persist::Persister::new_in_memory(
&db_id,
crate::model::LiquidNetwork::Testnet,
$crate::model::LiquidNetwork::Testnet,
true,
None,
None,
)?)
};
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
@@ -151,16 +151,16 @@ macro_rules! create_persister {
.to_str()
.ok_or(anyhow::anyhow!("Could not create temporary directory"))?
.to_string();
sdk_common::utils::Arc::new(crate::persist::Persister::new_using_fs(
sdk_common::utils::Arc::new($crate::persist::Persister::new_using_fs(
&temp_dir_path,
crate::model::LiquidNetwork::Testnet,
$crate::model::LiquidNetwork::Testnet,
true,
None,
)?)
};
};
}
pub(crate) use create_persister;
pub use create_persister;
pub(crate) fn new_payment_tx_data(
network: LiquidNetwork,

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use anyhow::Result;
use sdk_common::utils::Arc;

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use anyhow::{anyhow, Result};
use sdk_common::prelude::{MockRestClient, RestClient, STAGING_BREEZSERVER_URL};
use sdk_common::utils::Arc;

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use crate::{
model::{Config, Signer},
persist::Persister,

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use anyhow::Result;
use boltz_client::boltz;
use sdk_common::utils::Arc;

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use anyhow::Result;
use boltz_client::{
boltz::{

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use std::collections::HashMap;
use crate::{

View File

@@ -1,5 +1,3 @@
#![cfg(test)]
use std::{collections::HashMap, str::FromStr, sync::Mutex};
use crate::{

View File

@@ -1,7 +1,7 @@
[package]
name = "breez-sdk-liquid-wasm"
edition = "2021"
version.workspace = true
version = { workspace = true }
[lib]
name = "breez_sdk_liquid_wasm"
@@ -18,6 +18,21 @@ js-sys = "0.3.77"
log = { workspace = true }
sdk-macros = { workspace = true }
serde = { workspace = true }
tokio = { version = "1", default-features = false }
tsify-next = "0.5.5"
wasm-bindgen = "0.2.100"
wasm-bindgen-futures = "0.4.50"
web-time = "1.1.0"
indexed_db_futures = "0.6.1"
[dev-dependencies]
breez-sdk-liquid = { path = "../core", features = ["test-utils"] }
rand = "0.8"
getrandom = { version = "0.2", features = ["js"] }
sdk-common = { workspace = true, features = ["test-utils"] }
wasm-bindgen-test = "0.3.33"
uuid = "1.16.0"
[features]
node-js = []
browser-tests = []

View File

@@ -8,9 +8,14 @@ init:
cargo install wasm-pack
rustup target add wasm32-unknown-unknown
clippy:
clippy: clippy-base clippy-node
clippy-base:
$(CLANG_PREFIX) cargo clippy --all-targets --target=wasm32-unknown-unknown -- -D warnings
clippy-node:
$(CLANG_PREFIX) cargo clippy --all-targets --target=wasm32-unknown-unknown --features node-js -- -D warnings
build: build-bundle build-deno build-node build-web
build-bundle:
@@ -20,16 +25,21 @@ build-deno:
$(CLANG_PREFIX) wasm-pack build --target deno --release --out-dir pkg/deno
build-node:
$(CLANG_PREFIX) wasm-pack build --target nodejs --release --out-dir pkg/node
$(CLANG_PREFIX) wasm-pack build --target nodejs --release --out-dir pkg/node --features node-js
build-web:
$(CLANG_PREFIX) wasm-pack build --target web --release --out-dir pkg/web
test:
$(CLANG_PREFIX) wasm-pack test --headless --firefox
test: test-firefox test-node
test-node:
$(CLANG_PREFIX) wasm-pack test --node --features node-js
test-firefox:
$(CLANG_PREFIX) wasm-pack test --headless --firefox --features browser-tests
test-chrome:
$(CLANG_PREFIX) wasm-pack test --headless --chrome
$(CLANG_PREFIX) wasm-pack test --headless --chrome --features browser-tests
test-safari:
$(CLANG_PREFIX) wasm-pack test --headless --safari
$(CLANG_PREFIX) wasm-pack test --headless --safari --features browser-tests

View File

@@ -0,0 +1,71 @@
use anyhow::Result;
use indexed_db_futures::{
database::Database, query_source::QuerySource, transaction::TransactionMode, Build,
};
use js_sys::{global, Reflect};
const IDB_STORE_NAME: &str = "BREEZ_SDK_LIQUID_DB_BACKUP_STORE";
pub(crate) fn is_indexed_db_supported() -> bool {
let global = global();
Reflect::get(&global, &"indexedDB".into()).is_ok_and(|v| !v.is_undefined())
}
pub(crate) async fn backup_to_indexed_db(db_bytes: Vec<u8>, db_name: &str) -> Result<()> {
let idb = open_indexed_db(db_name).await?;
let tx = idb
.transaction([IDB_STORE_NAME])
.with_mode(TransactionMode::Readwrite)
.build()
.map_err(|e| anyhow::anyhow!("Failed to build transaction: {}", e))?;
let store = tx
.object_store(IDB_STORE_NAME)
.map_err(|e| anyhow::anyhow!("Failed to open object store: {}", e))?;
store
.put(db_bytes)
.with_key(1)
.await
.map_err(|e| anyhow::anyhow!("Failed to put key in db: {}", e))?;
tx.commit()
.await
.map_err(|e| anyhow::anyhow!("Failed to commit transaction: {}", e))?;
Ok(())
}
pub(crate) async fn load_indexed_db_backup(db_name: &str) -> Result<Option<Vec<u8>>> {
let idb = open_indexed_db(db_name).await?;
let tx = idb
.transaction([IDB_STORE_NAME])
.with_mode(TransactionMode::Readonly)
.build()
.map_err(|e| anyhow::anyhow!("Failed to build transaction: {}", e))?;
let store = tx
.object_store(IDB_STORE_NAME)
.map_err(|e| anyhow::anyhow!("Failed to open object store: {}", e))?;
store
.get(1)
.await
.map_err(|e| anyhow::anyhow!("Failed to get data: {}", e))
}
pub(crate) async fn open_indexed_db(name: &str) -> Result<Database> {
let db = Database::open(name)
.with_version(1u32)
.with_on_upgrade_needed(|event, db| {
if let (0.0, Some(1.0)) = (event.old_version(), event.new_version()) {
db.create_object_store(IDB_STORE_NAME).build()?;
}
Ok(())
})
.await
.map_err(|e| anyhow::anyhow!("Failed to open IndexedDB: {}", e))?;
Ok(db)
}

136
lib/wasm/src/backup/mod.rs Normal file
View File

@@ -0,0 +1,136 @@
mod indexed_db;
mod node_fs;
use crate::utils::PathExt;
use anyhow::Result;
use breez_sdk_liquid::model::{EventListener, SdkEvent};
use breez_sdk_liquid::persist::Persister;
use indexed_db::{backup_to_indexed_db, is_indexed_db_supported, load_indexed_db_backup};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use tokio::sync::mpsc::{Receiver, Sender};
pub(crate) struct ForwardingEventListener {
sender: Sender<SdkEvent>,
}
impl ForwardingEventListener {
pub fn new(sender: Sender<SdkEvent>) -> Self {
Self { sender }
}
}
impl EventListener for ForwardingEventListener {
fn on_event(&self, e: SdkEvent) {
if let Err(e) = self.sender.try_send(e) {
log::error!("Failed to forward event: {:?}", e);
}
}
}
pub(crate) fn start_backup_task(
persister: Rc<Persister>,
mut receiver: Receiver<SdkEvent>,
backup_dir_path: PathBuf,
) {
wasm_bindgen_futures::spawn_local(async move {
while let Some(e) = receiver.recv().await {
let res = match e {
SdkEvent::Synced => backup(&persister, &backup_dir_path).await,
SdkEvent::DataSynced {
did_pull_new_records,
} if did_pull_new_records => backup(&persister, &backup_dir_path).await,
_ => continue,
};
if let Err(e) = res {
log::error!("Failed to backup to IndexedDB: {:?}", e);
};
}
});
}
async fn backup(persister: &Rc<Persister>, backup_dir_path: &Path) -> Result<()> {
let start = web_time::Instant::now();
let db_bytes = persister.serialize()?;
if is_indexed_db_supported() {
backup_to_indexed_db(db_bytes, backup_dir_path.to_str_safe()?).await?;
} else {
#[cfg(not(feature = "node-js"))]
return Err(anyhow::anyhow!("No backup mechanism available"));
#[cfg(feature = "node-js")]
node_fs::backup_to_file_system(db_bytes, backup_dir_path)?;
}
let backup_duration_ms = start.elapsed().as_millis();
log::info!("Backup completed successfully ({backup_duration_ms} ms)");
Ok(())
}
pub(crate) async fn load_backup(backup_dir_path: &Path) -> Result<Option<Vec<u8>>> {
let maybe_data = if is_indexed_db_supported() {
load_indexed_db_backup(backup_dir_path.to_str_safe()?).await?
} else {
#[cfg(not(feature = "node-js"))]
return Err(anyhow::anyhow!("No backup restore mechanism available"));
#[cfg(feature = "node-js")]
node_fs::load_file_system_backup(backup_dir_path)?
};
Ok(maybe_data)
}
#[cfg(test)]
mod tests {
use crate::backup::backup;
use crate::backup::load_backup;
use std::path::PathBuf;
use std::str::FromStr;
use breez_sdk_liquid::model::PaymentState;
use breez_sdk_liquid::persist::Persister;
use breez_sdk_liquid::prelude::LiquidNetwork;
use breez_sdk_liquid::test_utils::persist::{
create_persister, new_receive_swap, new_send_swap,
};
#[cfg(feature = "browser-tests")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[sdk_macros::async_test_wasm]
async fn test_backup_and_restore() -> anyhow::Result<()> {
create_persister!(local);
local.test_insert_or_update_send_swap(&new_send_swap(Some(PaymentState::Pending), None))?;
local.test_insert_or_update_receive_swap(&new_receive_swap(
Some(PaymentState::Pending),
None,
))?;
assert_eq!(local.test_list_ongoing_swaps()?.len(), 2);
let backup_dir_path = PathBuf::from_str(&format!("/tmp/{}", uuid::Uuid::new_v4()))?;
backup(&local, &backup_dir_path).await?;
let backup_bytes = load_backup(&backup_dir_path).await?;
let remote =
Persister::new_in_memory("remote", LiquidNetwork::Testnet, false, None, backup_bytes)?;
assert_eq!(remote.test_list_ongoing_swaps()?.len(), 2);
// Try again to verify that a new backup overwrites an old one
local.test_insert_or_update_send_swap(&new_send_swap(Some(PaymentState::Pending), None))?;
local.test_insert_or_update_receive_swap(&new_receive_swap(
Some(PaymentState::Pending),
None,
))?;
assert_eq!(local.test_list_ongoing_swaps()?.len(), 4);
backup(&local, &backup_dir_path).await?;
let backup_bytes = load_backup(&backup_dir_path).await?;
let remote =
Persister::new_in_memory("remote", LiquidNetwork::Testnet, false, None, backup_bytes)?;
assert_eq!(remote.test_list_ongoing_swaps()?.len(), 4);
Ok(())
}
}

View File

@@ -0,0 +1,77 @@
#![cfg(feature = "node-js")]
use crate::utils::PathExt;
use anyhow::Result;
use js_sys::Reflect;
use std::path::{Path, PathBuf};
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "fs")]
extern "C" {
#[wasm_bindgen(js_name = writeFileSync, catch)]
fn write_file_sync(path: &str, data: &js_sys::Uint8Array) -> Result<(), JsValue>;
#[wasm_bindgen(js_name = readFileSync, catch)]
fn read_file_sync(path: &str) -> Result<JsValue, JsValue>;
#[wasm_bindgen(js_name = existsSync)]
fn exists_sync(path: &str) -> bool;
#[wasm_bindgen(js_name = mkdirSync, catch)]
fn mkdir_sync(path: &str, options: &JsValue) -> Result<(), JsValue>;
}
fn get_backup_file_path(backup_dir_path: &Path) -> PathBuf {
backup_dir_path.join("backup.sql")
}
pub fn ensure_dir_exists(path: &str) -> Result<(), JsValue> {
if !exists_sync(path) {
let options = js_sys::Object::new();
Reflect::set(&options, &"recursive".into(), &true.into())?;
mkdir_sync(path, &options)?;
}
Ok(())
}
pub(crate) fn backup_to_file_system(db_bytes: Vec<u8>, backup_dir_path: &Path) -> Result<()> {
let uint8_array = js_sys::Uint8Array::from(db_bytes.as_slice());
ensure_dir_exists(backup_dir_path.to_str_safe()?)
.map_err(|e| anyhow::anyhow!("Failed to create backup directory: {:?}", e))?;
let backup_file_path = get_backup_file_path(backup_dir_path);
write_file_sync(backup_file_path.to_str_safe()?, &uint8_array).map_err(|e| {
anyhow::anyhow!(
"Failed to write backup to file system using fs.writeFileSync: {:?}",
e
)
})?;
Ok(())
}
pub(crate) fn load_file_system_backup(backup_dir_path: &Path) -> Result<Option<Vec<u8>>> {
let backup_file_path = get_backup_file_path(backup_dir_path);
let backup_file_path_str = backup_file_path.to_str_safe()?;
if !exists_sync(backup_file_path_str) {
log::debug!("Backup file '{backup_file_path:?}' not found.");
return Ok(None);
}
log::debug!("Backup file '{backup_file_path:?}' found, attempting to read.",);
let buffer = read_file_sync(backup_file_path_str).map_err(|e| {
anyhow::anyhow!("Failed to read backup file using fs.readFileSync: {:?}", e)
})?;
if !buffer.is_undefined() && !buffer.is_null() {
let uint8_array = js_sys::Uint8Array::new(&buffer);
let mut data = vec![0; uint8_array.length() as usize];
uint8_array.copy_to(&mut data);
Ok(Some(data))
} else {
Err(anyhow::anyhow!(
"readFileSync returned null or undefined for '{backup_file_path:?}'"
))
}
}

View File

@@ -1,14 +1,20 @@
mod backup;
mod error;
mod event;
mod logger;
pub mod model;
mod signer;
mod utils;
use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
use crate::event::{EventListener, WasmEventListener};
use crate::model::*;
use anyhow::anyhow;
use breez_sdk_liquid::bitcoin::bip32::{Fingerprint, Xpub};
use breez_sdk_liquid::elements::hex::ToHex;
use breez_sdk_liquid::persist::Persister;
use breez_sdk_liquid::sdk::{LiquidSdk, LiquidSdkBuilder};
use breez_sdk_liquid::wallet::LiquidOnchainWallet;
@@ -51,25 +57,50 @@ async fn connect_inner(
Rc::clone(&signer),
)?;
let fingerprint: Fingerprint = Xpub::decode(
&signer
.xpub()
.map_err(|e| anyhow!("Failed to get xpub: {e}"))?,
)
.map_err(|e| anyhow!(e.to_string()))?
.identifier()[0..4]
.try_into()
.map_err(|e| anyhow!("Failed to get fingerprint: {e}"))?;
let fingerprint = fingerprint.to_hex();
let wallet_dir = PathBuf::from_str(&config.get_wallet_dir(&config.working_dir, &fingerprint)?)
.map_err(|e| anyhow!(e.to_string()))?;
let maybe_backup_bytes = backup::load_backup(&wallet_dir).await.unwrap_or_else(|e| {
log::error!("Failed to load backup: {:?}", e);
None
});
let persister = Rc::new(Persister::new_in_memory(
&config.working_dir,
config.network,
config.sync_enabled(),
config.asset_metadata.clone(),
maybe_backup_bytes,
)?);
let onchain_wallet = Rc::new(LiquidOnchainWallet::new_in_memory(
config,
config.clone(),
Rc::clone(&persister),
signer,
)?);
sdk_builder.persister(persister);
sdk_builder.persister(persister.clone());
sdk_builder.onchain_wallet(onchain_wallet);
let sdk = sdk_builder.build()?;
sdk.start().await?;
let (sender, receiver) = tokio::sync::mpsc::channel(20);
let listener = backup::ForwardingEventListener::new(sender);
sdk.add_event_listener(Box::new(listener)).await?;
backup::start_backup_task(persister, receiver, wallet_dir);
Ok(BindingLiquidSdk { sdk })
}

13
lib/wasm/src/utils.rs Normal file
View File

@@ -0,0 +1,13 @@
use anyhow::anyhow;
use std::path::Path;
pub trait PathExt {
fn to_str_safe(&self) -> anyhow::Result<&str>;
}
impl PathExt for Path {
fn to_str_safe(&self) -> anyhow::Result<&str> {
self.to_str()
.ok_or_else(|| anyhow!("Invalid UTF-8 sequence in path: {:?}", self))
}
}

View File

@@ -85,7 +85,8 @@ const initSdk = async () => {
const mnemonic = process.env.MNEMONIC
// Connect using the config
const config = await defaultConfig('mainnet', breezApiKey)
let config = defaultConfig('mainnet', breezApiKey)
config.workingDir = "./.data"
console.log(`defaultConfig: ${JSON.stringify(config)}`)
const sdk = await connect({ config, mnemonic })

View File

@@ -14,6 +14,8 @@ dist
dist-ssr
*.local
.data
# Editor directories and files
.vscode/*
!.vscode/extensions.json

View File

@@ -145,7 +145,8 @@ const initSdk = async () => {
const mnemonic = process.env.MNEMONIC
// Connect using the config
const config = defaultConfig('mainnet', breezApiKey)
let config = defaultConfig('mainnet', breezApiKey)
config.workingDir = "./.data"
sdk = await connect({ config, mnemonic })