import: implement import_backup()
This commit is contained in:
parent
b6f900355c
commit
d0d7007e83
481
Cargo.lock
generated
481
Cargo.lock
generated
@ -68,6 +68,49 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "age"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57fc171f4874fa10887e47088f81a55fcf030cd421aa31ec2b370cafebcc608a"
|
||||
dependencies = [
|
||||
"age-core",
|
||||
"base64 0.21.7",
|
||||
"bech32 0.9.1",
|
||||
"chacha20poly1305",
|
||||
"cookie-factory",
|
||||
"hmac",
|
||||
"i18n-embed",
|
||||
"i18n-embed-fl",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rust-embed",
|
||||
"scrypt",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"x25519-dalek",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "age-core"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"chacha20poly1305",
|
||||
"cookie-factory",
|
||||
"hkdf",
|
||||
"io_tee",
|
||||
"nom",
|
||||
"rand",
|
||||
"secrecy",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
@ -120,7 +163,7 @@ dependencies = [
|
||||
"ndk-context",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -168,6 +211,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@ -484,6 +533,15 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bdk_chain"
|
||||
version = "0.16.0"
|
||||
@ -508,6 +566,12 @@ dependencies = [
|
||||
"electrum-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.11.0"
|
||||
@ -516,13 +580,16 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
|
||||
|
||||
[[package]]
|
||||
name = "bip329"
|
||||
version = "0.1.1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdacd3f71820072c8d76eb077a8177b9a001bf03723d797783f97e9feefc0515"
|
||||
checksum = "8351c1cf438ae5814ad2a696f06fd07d7be4a1a133d889b1785260fa8797798c"
|
||||
dependencies = [
|
||||
"age",
|
||||
"bitcoin",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -579,7 +646,7 @@ dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"zeroize",
|
||||
]
|
||||
@ -592,7 +659,7 @@ checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026"
|
||||
dependencies = [
|
||||
"base58ck",
|
||||
"base64 0.21.7",
|
||||
"bech32",
|
||||
"bech32 0.11.0",
|
||||
"bitcoin-internals 0.3.0",
|
||||
"bitcoin-io",
|
||||
"bitcoin-units",
|
||||
@ -804,7 +871,7 @@ dependencies = [
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -938,7 +1005,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
@ -1049,6 +1116,15 @@ dependencies = [
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie-factory"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2"
|
||||
dependencies = [
|
||||
"futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@ -1136,7 +1212,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustybuzz",
|
||||
"self_cell",
|
||||
"self_cell 1.1.0",
|
||||
"swash",
|
||||
"sys-locale",
|
||||
"ttf-parser 0.21.1",
|
||||
@ -1275,6 +1351,20 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core 0.9.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.3.1"
|
||||
@ -1695,6 +1785,15 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-crate"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
@ -1723,6 +1822,50 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
|
||||
|
||||
[[package]]
|
||||
name = "fluent"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-bundle"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493"
|
||||
dependencies = [
|
||||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rustc-hash 1.1.0",
|
||||
"self_cell 0.10.3",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-langneg"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-syntax"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -2049,7 +2192,7 @@ checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
|
||||
dependencies = [
|
||||
"log",
|
||||
"presser",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"winapi",
|
||||
"windows",
|
||||
]
|
||||
@ -2171,7 +2314,7 @@ dependencies = [
|
||||
"com",
|
||||
"libc",
|
||||
"libloading 0.8.6",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"widestring",
|
||||
"winapi",
|
||||
]
|
||||
@ -2240,6 +2383,15 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
@ -2330,6 +2482,73 @@ dependencies = [
|
||||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i18n-config"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e88074831c0be5b89181b05e6748c4915f77769ecc9a4c372f88b169a8509c9"
|
||||
dependencies = [
|
||||
"basic-toml",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"thiserror 1.0.69",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i18n-embed"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0454970a5853f498e686cbd7bf9391aac2244928194780cb7a0af0f41937db6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"fluent",
|
||||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"i18n-embed-impl",
|
||||
"intl-memoizer",
|
||||
"log",
|
||||
"parking_lot 0.12.3",
|
||||
"rust-embed",
|
||||
"thiserror 1.0.69",
|
||||
"unic-langid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i18n-embed-fl"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7578cee2940492a648bd60fb49ca85ee8c821a63790e0ef5b604cfed353b2a"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"find-crate",
|
||||
"fluent",
|
||||
"fluent-syntax",
|
||||
"i18n-config",
|
||||
"i18n-embed",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.98",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i18n-embed-impl"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2"
|
||||
dependencies = [
|
||||
"find-crate",
|
||||
"i18n-config",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
@ -2365,7 +2584,7 @@ dependencies = [
|
||||
"iced_widget",
|
||||
"iced_winit",
|
||||
"image",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2383,7 +2602,7 @@ dependencies = [
|
||||
"palette",
|
||||
"rustc-hash 2.1.1",
|
||||
"smol_str",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@ -2434,7 +2653,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"raw-window-handle",
|
||||
"rustc-hash 2.1.1",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
@ -2448,7 +2667,7 @@ dependencies = [
|
||||
"iced_tiny_skia",
|
||||
"iced_wgpu",
|
||||
"log",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2461,7 +2680,7 @@ dependencies = [
|
||||
"iced_core",
|
||||
"iced_futures",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2499,7 +2718,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"resvg",
|
||||
"rustc-hash 2.1.1",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
@ -2516,7 +2735,7 @@ dependencies = [
|
||||
"ouroboros",
|
||||
"qrcode",
|
||||
"rustc-hash 2.1.1",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
@ -2531,7 +2750,7 @@ dependencies = [
|
||||
"iced_runtime",
|
||||
"log",
|
||||
"rustc-hash 2.1.1",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
@ -2731,6 +2950,25 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl-memoizer"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda"
|
||||
dependencies = [
|
||||
"type-map",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl_pluralrules"
|
||||
version = "7.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-kit-sys"
|
||||
version = "0.4.1"
|
||||
@ -2741,6 +2979,12 @@ dependencies = [
|
||||
"mach2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io_tee"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b3f7cef34251886990511df1c61443aa928499d598a9473929ab5a90a527304"
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.11.0"
|
||||
@ -2782,7 +3026,7 @@ dependencies = [
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
@ -2951,7 +3195,7 @@ dependencies = [
|
||||
"ledger-transport",
|
||||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3292,13 +3536,19 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniscript"
|
||||
version = "12.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bech32 0.11.0",
|
||||
"bitcoin",
|
||||
"serde",
|
||||
]
|
||||
@ -3377,7 +3627,7 @@ dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"spirv",
|
||||
"termcolor",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@ -3393,7 +3643,7 @@ dependencies = [
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3474,6 +3724,16 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@ -3945,6 +4205,16 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@ -4159,6 +4429,28 @@ dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
@ -4419,7 +4711,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4594,6 +4886,40 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b3aba5104622db5c9fc61098de54708feb732e7763d7faa2fa625899f00bf6f"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f198c73be048d2c5aa8e12f7960ad08443e56fd39cc26336719fdb4ea0ebaae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"syn 2.0.98",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a2fcdc9f40c8dc2922842ca9add611ad19f332227fc651d015881ad1552bd9a"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.19.0"
|
||||
@ -4736,6 +5062,15 @@ version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "salsa20"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -4757,6 +5092,17 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scrypt"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
|
||||
dependencies = [
|
||||
"pbkdf2",
|
||||
"salsa20",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.1"
|
||||
@ -4814,6 +5160,24 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
|
||||
dependencies = [
|
||||
"self_cell 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.1.0"
|
||||
@ -5033,7 +5397,7 @@ dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
"rustix",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-csd-frame",
|
||||
@ -5174,6 +5538,12 @@ dependencies = [
|
||||
"float-cmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
@ -5315,7 +5685,16 @@ version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5329,6 +5708,17 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
@ -5601,6 +5991,15 @@ version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
@ -5624,7 +6023,26 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44"
|
||||
dependencies = [
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-impl"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"tinystr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6112,7 +6530,7 @@ dependencies = [
|
||||
"raw-window-handle",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"web-sys",
|
||||
"wgpu-hal",
|
||||
"wgpu-types",
|
||||
@ -6156,7 +6574,7 @@ dependencies = [
|
||||
"renderdoc-sys",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"wgpu-types",
|
||||
@ -6234,7 +6652,7 @@ dependencies = [
|
||||
"clipboard_wayland",
|
||||
"clipboard_x11",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6602,6 +7020,7 @@ checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@ impl ExportModal {
|
||||
ImportExportType::ExportLabels => "Export Labels",
|
||||
ImportExportType::ImportPsbt => "Import PSBT",
|
||||
ImportExportType::ImportDescriptor => "Import Descriptor",
|
||||
ImportExportType::ImportBackup(..) => "Restore Backup",
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,12 +71,14 @@ impl ExportModal {
|
||||
ImportExportType::ImportPsbt => "psbt.psbt".into(),
|
||||
ImportExportType::ImportDescriptor => "descriptor.descriptor".into(),
|
||||
ImportExportType::ExportLabels => format!("liana-labels-{date}.jsonl"),
|
||||
ImportExportType::ExportBackup(_) => format!("liana-backup-{date}.json"),
|
||||
ImportExportType::ExportBackup(_) | ImportExportType::ImportBackup(_, _) => {
|
||||
format!("liana-backup-{date}.json")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn launch<M: From<ImportExportMessage> + Send + 'static>(&self) -> Task<M> {
|
||||
Task::perform(get_path(self.default_filename()), move |m| {
|
||||
pub fn launch<M: From<ImportExportMessage> + Send + 'static>(&self, write: bool) -> Task<M> {
|
||||
Task::perform(get_path(self.default_filename(), write), move |m| {
|
||||
ImportExportMessage::Path(m).into()
|
||||
})
|
||||
}
|
||||
@ -95,11 +98,21 @@ impl ExportModal {
|
||||
self.state = ImportExportState::Progress(p);
|
||||
}
|
||||
}
|
||||
Progress::Finished | Progress::Ended => {
|
||||
self.state = ImportExportState::Ended;
|
||||
Progress::Finished | Progress::Ended => self.state = ImportExportState::Ended,
|
||||
Progress::KeyAliasesConflict(ref sender) => {
|
||||
if let ImportExportType::ImportBackup(_, aliases) = &self.import_export_type {
|
||||
self.import_export_type =
|
||||
ImportExportType::ImportBackup(Some(sender.clone()), aliases.clone());
|
||||
}
|
||||
}
|
||||
Progress::LabelsConflict(ref sender) => {
|
||||
if let ImportExportType::ImportBackup(labels, _) = &self.import_export_type {
|
||||
self.import_export_type =
|
||||
ImportExportType::ImportBackup(labels.clone(), Some(sender.clone()));
|
||||
}
|
||||
}
|
||||
Progress::Error(e) => {
|
||||
self.error = Some(e);
|
||||
self.error = Some(e.clone());
|
||||
}
|
||||
Progress::None => {}
|
||||
Progress::Psbt(_) => {
|
||||
@ -130,6 +143,36 @@ impl ExportModal {
|
||||
}
|
||||
}
|
||||
ImportExportMessage::Close | ImportExportMessage::Open => { /* unreachable */ }
|
||||
ImportExportMessage::Overwrite => {
|
||||
if let ImportExportType::ImportBackup(labels, aliases) =
|
||||
&mut self.import_export_type
|
||||
{
|
||||
if let Some(sender) = labels.take() {
|
||||
if sender.send(true).is_err() {
|
||||
tracing::error!("ExportModal.update(): fail to send labels ACK");
|
||||
}
|
||||
} else if let Some(sender) = aliases.take() {
|
||||
if sender.send(true).is_err() {
|
||||
tracing::error!("ExportModal.update(): fail to send aliases ACK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImportExportMessage::Ignore => {
|
||||
if let ImportExportType::ImportBackup(labels, aliases) =
|
||||
&mut self.import_export_type
|
||||
{
|
||||
if let Some(sender) = labels.take() {
|
||||
if sender.send(false).is_err() {
|
||||
tracing::error!("ExportModal.update(): fail to send labels NACK");
|
||||
}
|
||||
} else if let Some(sender) = aliases.take() {
|
||||
if sender.send(false).is_err() {
|
||||
tracing::error!("ExportModal.update(): fail to send aliases NACK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@ -140,7 +183,12 @@ impl ExportModal {
|
||||
{
|
||||
let modal = Modal::new(
|
||||
content,
|
||||
export_modal(&self.state, self.error.as_ref(), self.modal_title()),
|
||||
export_modal(
|
||||
&self.state,
|
||||
self.error.as_ref(),
|
||||
self.modal_title(),
|
||||
&self.import_export_type,
|
||||
),
|
||||
);
|
||||
match self.state {
|
||||
ImportExportState::TimedOut
|
||||
|
||||
@ -183,8 +183,8 @@ impl ImportExportSettingsState {
|
||||
}
|
||||
|
||||
macro_rules! launch {
|
||||
($s:ident, $m: ident) => {
|
||||
let launch = $m.launch();
|
||||
($s:ident, $m: ident, $write:ident) => {
|
||||
let launch = $m.launch($write);
|
||||
$s.modal = Some($m);
|
||||
return launch
|
||||
};
|
||||
@ -239,19 +239,19 @@ impl State for ImportExportSettingsState {
|
||||
Some(daemon),
|
||||
ImportExportType::Descriptor(self.wallet.main_descriptor.clone()),
|
||||
);
|
||||
launch!(self, modal);
|
||||
launch!(self, modal, true);
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportTransactions)) => {
|
||||
if self.modal.is_none() {
|
||||
let modal = ExportModal::new(Some(daemon), ImportExportType::Transactions);
|
||||
launch!(self, modal);
|
||||
launch!(self, modal, true);
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportLabels)) => {
|
||||
if self.modal.is_none() {
|
||||
let modal = ExportModal::new(Some(daemon), ImportExportType::ExportLabels);
|
||||
launch!(self, modal);
|
||||
launch!(self, modal, true);
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ExportWallet)) => {
|
||||
@ -281,7 +281,7 @@ impl State for ImportExportSettingsState {
|
||||
backup,
|
||||
)))) => {
|
||||
let modal = ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
|
||||
launch!(self, modal);
|
||||
launch!(self, modal, true);
|
||||
}
|
||||
Message::View(view::Message::Settings(view::SettingsMessage::ImportWallet)) => {
|
||||
// TODO:
|
||||
|
||||
@ -254,7 +254,7 @@ impl State for WalletSettingsState {
|
||||
if self.modal.is_none() {
|
||||
let modal =
|
||||
ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
|
||||
let launch = modal.launch();
|
||||
let launch = modal.launch(true);
|
||||
self.modal = Modal::ImportExport(modal);
|
||||
launch
|
||||
} else {
|
||||
@ -267,7 +267,7 @@ impl State for WalletSettingsState {
|
||||
Some(daemon),
|
||||
ImportExportType::Descriptor(self.wallet.main_descriptor.clone()),
|
||||
);
|
||||
let launch = modal.launch();
|
||||
let launch = modal.launch(false);
|
||||
self.modal = Modal::ImportExport(modal);
|
||||
launch
|
||||
} else {
|
||||
|
||||
@ -273,7 +273,7 @@ impl State for TransactionsPanel {
|
||||
ImportExportType::Transactions,
|
||||
));
|
||||
if let TransactionsModal::Export(m) = &self.modal {
|
||||
return m.launch();
|
||||
return m.launch(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,15 +11,17 @@ use liana_ui::{
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use crate::export::{Error, ImportExportMessage, ImportExportState};
|
||||
use crate::export::ImportExportState;
|
||||
use crate::export::{Error, ImportExportMessage, ImportExportType};
|
||||
|
||||
/// Return the modal view for an export task
|
||||
pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'a>(
|
||||
state: &ImportExportState,
|
||||
error: Option<&'a Error>,
|
||||
export_type: &str,
|
||||
title: &str,
|
||||
import_export_type: &ImportExportType,
|
||||
) -> Element<'a, Message> {
|
||||
let button = match state {
|
||||
let cancel_close = match state {
|
||||
ImportExportState::Started | ImportExportState::Progress(_) => {
|
||||
Some(button::secondary(None, "Cancel").on_press(ImportExportMessage::UserStop.into()))
|
||||
}
|
||||
@ -27,7 +29,9 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'a>(
|
||||
Some(button::secondary(None, "Close").on_press(ImportExportMessage::Close.into()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
.map(Container::new);
|
||||
|
||||
let msg = if let Some(error) = error {
|
||||
format!("{:?}", error)
|
||||
} else {
|
||||
@ -41,10 +45,53 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'a>(
|
||||
ImportExportState::Progress(p) => format!("Progress: {}%", p.round()),
|
||||
ImportExportState::TimedOut => "Export failed: timeout".into(),
|
||||
ImportExportState::Aborted => "Export canceled".into(),
|
||||
ImportExportState::Ended => "Export successful!".into(),
|
||||
ImportExportState::Ended => import_export_type.end_message().into(),
|
||||
ImportExportState::Closed => "".into(),
|
||||
}
|
||||
};
|
||||
let labels_btn = (
|
||||
"Labels conflict, what do you want to do?".to_string(),
|
||||
Some(Container::new(
|
||||
Row::new()
|
||||
.push(
|
||||
button::secondary(None, "Overwrite")
|
||||
.on_press(ImportExportMessage::Overwrite.into()),
|
||||
)
|
||||
.push(Space::with_width(30))
|
||||
.push(
|
||||
button::secondary(None, "Ignore").on_press(ImportExportMessage::Ignore.into()),
|
||||
),
|
||||
)),
|
||||
);
|
||||
let aliases_btn = (
|
||||
"Aliases conflict, what do you want to do?".to_string(),
|
||||
Some(Container::new(
|
||||
Row::new()
|
||||
.push(
|
||||
button::secondary(None, "Overwrite")
|
||||
.on_press(ImportExportMessage::Overwrite.into()),
|
||||
)
|
||||
.push(Space::with_width(30))
|
||||
.push(
|
||||
button::secondary(None, "Ignore").on_press(ImportExportMessage::Ignore.into()),
|
||||
),
|
||||
)),
|
||||
);
|
||||
let (msg, button) = match (error.is_none(), import_export_type) {
|
||||
(true, ImportExportType::ImportBackup(labels, aliases)) => match (labels, aliases) {
|
||||
(Some(_), _) => labels_btn,
|
||||
|
||||
(_, Some(_)) => aliases_btn,
|
||||
_ => (msg, cancel_close),
|
||||
},
|
||||
_ => (msg, cancel_close),
|
||||
};
|
||||
let button = button.map(|b| {
|
||||
Container::new(b)
|
||||
.align_x(Horizontal::Center)
|
||||
.width(Length::Fill)
|
||||
});
|
||||
|
||||
let p = match state {
|
||||
ImportExportState::Init => 0.0,
|
||||
ImportExportState::ChoosePath | ImportExportState::Path(_) | ImportExportState::Started => {
|
||||
@ -63,17 +110,13 @@ pub fn export_modal<'a, Message: From<ImportExportMessage> + Clone + 'a>(
|
||||
card::simple(
|
||||
Column::new()
|
||||
.spacing(10)
|
||||
.push(Container::new(h4_bold(export_type)).width(Length::Fill))
|
||||
.push(Container::new(h4_bold(title)).width(Length::Fill))
|
||||
.push(Space::with_height(Length::Fill))
|
||||
.push(progress_bar_row)
|
||||
.push(Space::with_height(Length::Fill))
|
||||
.push(Row::new().push(text(msg)))
|
||||
.push(Space::with_height(Length::Fill))
|
||||
.push_maybe(button.map(|b| {
|
||||
Container::new(b)
|
||||
.align_x(Horizontal::Right)
|
||||
.width(Length::Fill)
|
||||
}))
|
||||
.push_maybe(button)
|
||||
.push(Space::with_height(5)),
|
||||
)
|
||||
.width(Length::Fixed(500.0))
|
||||
|
||||
@ -72,6 +72,12 @@ pub enum Error {
|
||||
TxTimeMissing,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DaemonError> for Error {
|
||||
fn from(value: DaemonError) -> Self {
|
||||
Error::Daemon(value.to_string())
|
||||
@ -437,7 +443,7 @@ impl Account {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Key {
|
||||
pub key: Fingerprint,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@ -450,7 +456,7 @@ pub struct Key {
|
||||
pub metadata: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub enum KeyRole {
|
||||
/// Key to be used in normal spending condition
|
||||
Main,
|
||||
@ -462,7 +468,7 @@ pub enum KeyRole {
|
||||
Cosigning,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub enum KeyType {
|
||||
/// Main user
|
||||
Internal,
|
||||
|
||||
@ -5,7 +5,7 @@ use std::{
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
mpsc::{channel, sync_channel, Receiver, Sender, SyncSender},
|
||||
Arc, Mutex,
|
||||
},
|
||||
time,
|
||||
@ -16,7 +16,10 @@ use liana::{
|
||||
descriptors::LianaDescriptor,
|
||||
miniscript::bitcoin::{Amount, Psbt, Txid},
|
||||
};
|
||||
use lianad::bip329::{error::ExportError, Labels};
|
||||
use lianad::{
|
||||
bip329::{error::ExportError, Labels},
|
||||
commands::LabelItem,
|
||||
};
|
||||
use tokio::{
|
||||
task::{JoinError, JoinHandle},
|
||||
time::sleep,
|
||||
@ -25,7 +28,11 @@ use tokio::{
|
||||
use iced::futures::{SinkExt, Stream};
|
||||
|
||||
use crate::{
|
||||
app::view,
|
||||
app::{
|
||||
settings::{KeySetting, Settings},
|
||||
view,
|
||||
},
|
||||
backup::Backup,
|
||||
daemon::{
|
||||
model::{HistoryTransaction, Labelled},
|
||||
Daemon, DaemonBackend, DaemonError,
|
||||
@ -61,7 +68,7 @@ macro_rules! send_progress {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! open_file {
|
||||
macro_rules! open_file_write {
|
||||
($path:ident, $sender:ident) => {{
|
||||
let dir = match $path.parent() {
|
||||
Some(dir) => dir,
|
||||
@ -86,6 +93,18 @@ macro_rules! open_file {
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! open_file_read {
|
||||
($path:ident, $sender:ident) => {{
|
||||
match File::open($path.as_path()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
send_error!($sender, e.into());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ImportExportMessage {
|
||||
Open,
|
||||
@ -94,6 +113,8 @@ pub enum ImportExportMessage {
|
||||
UserStop,
|
||||
Path(Option<PathBuf>),
|
||||
Close,
|
||||
Overwrite,
|
||||
Ignore,
|
||||
}
|
||||
|
||||
impl From<ImportExportMessage> for view::Message {
|
||||
@ -129,19 +150,53 @@ pub enum Error {
|
||||
ParsePsbt,
|
||||
ParseDescriptor,
|
||||
Bip329Export(String),
|
||||
BackupImport(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ImportExportType {
|
||||
Transactions,
|
||||
ExportPsbt(String),
|
||||
ExportBackup(String),
|
||||
ImportBackup(
|
||||
Option<SyncSender<bool>>, /*overwrite_labels*/
|
||||
Option<SyncSender<bool>>, /*overwrite_aliases*/
|
||||
),
|
||||
Descriptor(LianaDescriptor),
|
||||
ExportLabels,
|
||||
ImportPsbt,
|
||||
ImportDescriptor,
|
||||
}
|
||||
|
||||
impl ImportExportType {
|
||||
pub fn end_message(&self) -> &str {
|
||||
match self {
|
||||
ImportExportType::Transactions
|
||||
| ImportExportType::ExportPsbt(_)
|
||||
| ImportExportType::ExportBackup(_)
|
||||
| ImportExportType::Descriptor(_)
|
||||
| ImportExportType::ExportLabels => "Export successful!",
|
||||
ImportExportType::ImportBackup(_, _)
|
||||
| ImportExportType::ImportPsbt
|
||||
| ImportExportType::ImportDescriptor => "Import successful",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ImportExportType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::ExportPsbt(l0), Self::ExportPsbt(r0)) => l0 == r0,
|
||||
(Self::ExportBackup(l0), Self::ExportBackup(r0)) => l0 == r0,
|
||||
(Self::ImportBackup(l0, l1), Self::ImportBackup(r0, r1)) => {
|
||||
l0.is_some() == r0.is_some() && l1.is_some() == r1.is_some()
|
||||
}
|
||||
(Self::Descriptor(l0), Self::Descriptor(r0)) => l0 == r0,
|
||||
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JoinError> for Error {
|
||||
fn from(value: JoinError) -> Self {
|
||||
Error::JoinError(format!("{:?}", value))
|
||||
@ -183,6 +238,8 @@ pub enum Progress {
|
||||
None,
|
||||
Psbt(Psbt),
|
||||
Descriptor(LianaDescriptor),
|
||||
LabelsConflict(SyncSender<bool>),
|
||||
KeyAliasesConflict(SyncSender<bool>),
|
||||
}
|
||||
|
||||
pub struct Export {
|
||||
@ -225,6 +282,7 @@ impl Export {
|
||||
ImportExportType::ImportPsbt => import_psbt(sender, path),
|
||||
ImportExportType::ImportDescriptor => import_descriptor(sender, path),
|
||||
ImportExportType::ExportBackup(str) => export_string(sender, path, str),
|
||||
ImportExportType::ImportBackup(..) => import_backup(sender, path, daemon).await,
|
||||
};
|
||||
}
|
||||
|
||||
@ -335,7 +393,7 @@ pub async fn export_transactions(
|
||||
return;
|
||||
}
|
||||
};
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_write!(path, sender);
|
||||
|
||||
let header = "Date,Label,Value,Fee,Txid,Block\n".to_string();
|
||||
if let Err(e) = file.write_all(header.as_bytes()) {
|
||||
@ -488,7 +546,7 @@ pub async fn export_transactions(
|
||||
}
|
||||
|
||||
pub fn export_descriptor(sender: Sender<Progress>, path: PathBuf, descriptor: LianaDescriptor) {
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_write!(path, sender);
|
||||
|
||||
let descr_string = descriptor.to_string();
|
||||
if let Err(e) = file.write_all(descr_string.as_bytes()) {
|
||||
@ -500,7 +558,7 @@ pub fn export_descriptor(sender: Sender<Progress>, path: PathBuf, descriptor: Li
|
||||
}
|
||||
|
||||
pub fn export_string(sender: Sender<Progress>, path: PathBuf, psbt: String) {
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_write!(path, sender);
|
||||
|
||||
if let Err(e) = file.write_all(psbt.as_bytes()) {
|
||||
send_error!(sender, e.into());
|
||||
@ -511,7 +569,7 @@ pub fn export_string(sender: Sender<Progress>, path: PathBuf, psbt: String) {
|
||||
}
|
||||
|
||||
pub fn import_psbt(sender: Sender<Progress>, path: PathBuf) {
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_read!(path, sender);
|
||||
|
||||
let mut psbt_str = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut psbt_str) {
|
||||
@ -532,7 +590,7 @@ pub fn import_psbt(sender: Sender<Progress>, path: PathBuf) {
|
||||
}
|
||||
|
||||
pub fn import_descriptor(sender: Sender<Progress>, path: PathBuf) {
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_read!(path, sender);
|
||||
|
||||
let mut descr_str = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut descr_str) {
|
||||
@ -552,6 +610,336 @@ pub fn import_descriptor(sender: Sender<Progress>, path: PathBuf) {
|
||||
send_progress!(sender, Descriptor(descriptor));
|
||||
}
|
||||
|
||||
/// Import a backup in an already existing wallet:
|
||||
/// - Load backup from file
|
||||
/// - check if networks matches
|
||||
/// - check if descriptors matches
|
||||
/// - check if labels can be imported w/o conflict, if conflic ask user to ACK
|
||||
/// - check if aliases can be imported w/o conflict, if conflict ask user to ACK
|
||||
/// - update receive and change indexes
|
||||
/// - parse psbt from backup
|
||||
/// - import PSBTs
|
||||
/// - import labels if no conflict or user ACK
|
||||
/// - update aliases if no conflict or user ACK
|
||||
pub async fn import_backup(
|
||||
sender: Sender<Progress>,
|
||||
path: PathBuf,
|
||||
daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
) {
|
||||
let daemon = match daemon {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
send_error!(sender, Error::DaemonMissing);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: drop after support for restore to liana-connect
|
||||
if matches!(daemon.backend(), DaemonBackend::RemoteBackend) {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Restore to a Liana-connect backend is not yet supported!".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load backup from file
|
||||
let mut file = open_file_read!(path, sender);
|
||||
|
||||
let mut backup_str = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut backup_str) {
|
||||
send_error!(sender, e.into());
|
||||
return;
|
||||
}
|
||||
|
||||
let backup: Result<Backup, _> = serde_json::from_str(&backup_str);
|
||||
let backup = match backup {
|
||||
Ok(psbt) => psbt,
|
||||
Err(e) => {
|
||||
send_error!(sender, Error::BackupImport(format!("{:?}", e)));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// get backend info
|
||||
let info = match daemon.get_info().await {
|
||||
Ok(info) => info,
|
||||
Err(e) => {
|
||||
send_error!(sender, Error::Daemon(format!("{e:?}")));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// check if networks matches
|
||||
let network = info.network;
|
||||
if backup.network != network {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("The network of the backup don't match the wallet network!".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if descriptors matches
|
||||
let descriptor = info.descriptors.main;
|
||||
let account = match backup.accounts.len() {
|
||||
0 => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("There is no account in the backup!".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
1 => backup.accounts.first().expect("already checked"),
|
||||
_ => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport(
|
||||
"Liana is actually not supporting import of backup with several accounts!"
|
||||
.into()
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let backup_descriptor = match LianaDescriptor::from_str(&account.descriptor) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport(
|
||||
"The backup descriptor is not a valid Liana descriptor!".into()
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if backup_descriptor != descriptor {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("The backup descriptor do not match this wallet!".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: check if timestamp matches?
|
||||
|
||||
// check if labels can be imported w/o conflict
|
||||
let mut write_labels = true;
|
||||
let backup_labels = if let Some(labels) = account.labels.clone() {
|
||||
let db_labels = match daemon.get_labels_bip329(0, u32::MAX).await {
|
||||
Ok(l) => l,
|
||||
Err(_) => {
|
||||
send_error!(sender, Error::BackupImport("Fail to dump DB labels".into()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let labels_map = db_labels.clone().into_map();
|
||||
let backup_labels_map = labels.clone().into_map();
|
||||
|
||||
// if there is a conflict, we ask user to ACK before overwrite
|
||||
let (ack_sender, ack_receiver) = sync_channel(0);
|
||||
let mut conflict = false;
|
||||
for (k, l) in &backup_labels_map {
|
||||
if let Some(lab) = labels_map.get(k) {
|
||||
if lab != l {
|
||||
send_progress!(sender, LabelsConflict(ack_sender));
|
||||
conflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if conflict {
|
||||
write_labels = match ack_receiver.recv() {
|
||||
Ok(b) => b,
|
||||
Err(_) => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to receive labels ACK".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
labels.into_vec()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let datadir = match daemon.config() {
|
||||
Some(c) => match &c.data_dir {
|
||||
Some(dd) => dd,
|
||||
None => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to get Daemon config".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to get Daemon config".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// check if key aliases can be imported w/o conflict
|
||||
let mut write_aliases = true;
|
||||
let settings = if !account.keys.is_empty() {
|
||||
let settings = match Settings::from_file(datadir.to_path_buf(), network) {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to get App Settings".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let settings_aliases: HashMap<_, _> = match settings.wallets.len() {
|
||||
1 => settings
|
||||
.wallets
|
||||
.first()
|
||||
.expect("already checked")
|
||||
.keys
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|s| (s.master_fingerprint, s))
|
||||
.collect(),
|
||||
_ => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Settings.wallets.len() is not 1".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let (ack_sender, ack_receiver) = sync_channel(0);
|
||||
let mut conflict = false;
|
||||
for (fg, key) in &account.keys {
|
||||
if let Some(k) = settings_aliases.get(fg) {
|
||||
let ks = k.to_backup();
|
||||
if ks != *key {
|
||||
send_progress!(sender, KeyAliasesConflict(ack_sender));
|
||||
conflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if conflict {
|
||||
// wait for the user ACK/NACK
|
||||
write_aliases = match ack_receiver.recv() {
|
||||
Ok(a) => a,
|
||||
Err(_) => {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to receive aliases ACK".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Some((settings, settings_aliases))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// update receive & change index
|
||||
let db_receive = info.receive_index;
|
||||
let i = account.receive_index.unwrap_or(0);
|
||||
let receive = if db_receive < i { Some(i) } else { None };
|
||||
|
||||
let db_change = info.change_index;
|
||||
let i = account.change_index.unwrap_or(0);
|
||||
let change = if db_change < i { Some(i) } else { None };
|
||||
|
||||
if daemon.update_deriv_indexes(receive, change).await.is_err() {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to update derivation indexes".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse PSBTs
|
||||
let mut psbts = Vec::new();
|
||||
for psbt_str in &account.psbts {
|
||||
match Psbt::from_str(psbt_str) {
|
||||
Ok(p) => {
|
||||
psbts.push(p);
|
||||
}
|
||||
Err(_) => {
|
||||
send_error!(sender, Error::BackupImport("Fail to parse PSBT".into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// import PSBTs
|
||||
for psbt in psbts {
|
||||
if daemon.update_spend_tx(&psbt).await.is_err() {
|
||||
send_error!(sender, Error::BackupImport("Fail to store PSBT".into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// import labels if no conflict or user ACK
|
||||
if write_labels {
|
||||
let labels: HashMap<LabelItem, Option<String>> = backup_labels
|
||||
.into_iter()
|
||||
.filter_map(|l| {
|
||||
if let Some((item, label)) = LabelItem::from_bip329(&l, network) {
|
||||
Some((item, Some(label)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if daemon.update_labels(&labels).await.is_err() {
|
||||
send_error!(sender, Error::BackupImport("Fail to import labels".into()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// update aliases if no conflict or user ACK
|
||||
if let (true, Some((mut settings, mut settings_aliases))) = (write_aliases, settings) {
|
||||
for (k, v) in &account.keys {
|
||||
if let Some(ks) = KeySetting::from_backup(
|
||||
v.alias.clone().unwrap_or("".into()),
|
||||
*k,
|
||||
v.role.clone(),
|
||||
v.key_type.clone(),
|
||||
v.metadata.clone(),
|
||||
) {
|
||||
settings_aliases.insert(*k, ks);
|
||||
}
|
||||
}
|
||||
|
||||
settings.wallets.get_mut(0).expect("already checked").keys =
|
||||
settings_aliases.into_values().collect();
|
||||
if settings.to_file(datadir.to_path_buf(), network).is_err() {
|
||||
send_error!(
|
||||
sender,
|
||||
Error::BackupImport("Fail to import keys aliases".into())
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
send_progress!(sender, Progress(100.0));
|
||||
send_progress!(sender, Ended);
|
||||
}
|
||||
|
||||
pub async fn export_labels(
|
||||
sender: Sender<Progress>,
|
||||
daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
@ -590,7 +978,7 @@ pub async fn export_labels(
|
||||
return;
|
||||
}
|
||||
};
|
||||
let mut file = open_file!(path, sender);
|
||||
let mut file = open_file_write!(path, sender);
|
||||
|
||||
if let Err(e) = file.write_all(json.as_bytes()) {
|
||||
send_error!(sender, e.into());
|
||||
@ -600,11 +988,20 @@ pub async fn export_labels(
|
||||
send_progress!(sender, Ended);
|
||||
}
|
||||
|
||||
pub async fn get_path(filename: String) -> Option<PathBuf> {
|
||||
rfd::AsyncFileDialog::new()
|
||||
.set_title("Choose a location to export...")
|
||||
.set_file_name(filename)
|
||||
.save_file()
|
||||
.await
|
||||
.map(|fh| fh.path().to_path_buf())
|
||||
pub async fn get_path(filename: String, write: bool) -> Option<PathBuf> {
|
||||
if write {
|
||||
rfd::AsyncFileDialog::new()
|
||||
.set_title("Choose a location to export...")
|
||||
.set_file_name(filename)
|
||||
.save_file()
|
||||
.await
|
||||
.map(|fh| fh.path().to_path_buf())
|
||||
} else {
|
||||
rfd::AsyncFileDialog::new()
|
||||
.set_title("Choose a file to import...")
|
||||
.set_file_name(filename)
|
||||
.pick_file()
|
||||
.await
|
||||
.map(|fh| fh.path().to_path_buf())
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ impl Step for BackupDescriptor {
|
||||
}
|
||||
};
|
||||
let modal = ExportModal::new(None, ImportExportType::ExportBackup(str));
|
||||
let launch = modal.launch();
|
||||
let launch = modal.launch(true);
|
||||
self.modal = Some(modal);
|
||||
return launch;
|
||||
}
|
||||
|
||||
@ -55,4 +55,6 @@ rusqlite = { version = "0.30", features = ["bundled", "unlock_notify"] }
|
||||
|
||||
# To talk to bitcoind
|
||||
jsonrpc = { version = "0.17", features = ["minreq_http"], default-features = false }
|
||||
bip329 = {version = "0.1.1", default-features = false }
|
||||
|
||||
# import/export labels
|
||||
bip329 = "0.3.0"
|
||||
|
||||
@ -576,7 +576,7 @@ impl LabelItem {
|
||||
match label {
|
||||
bip329::Label::Transaction(tx_record) => {
|
||||
if let (Some(txid), Some(label)) = (
|
||||
Txid::from_str(&tx_record.ref_).ok(),
|
||||
Txid::from_str(&tx_record.ref_.to_string()).ok(),
|
||||
tx_record.label.clone(),
|
||||
) {
|
||||
Some((Self::Txid(txid), label))
|
||||
@ -586,7 +586,8 @@ impl LabelItem {
|
||||
}
|
||||
bip329::Label::Address(address_record) => {
|
||||
if let (Some(addr), Some(label)) = (
|
||||
Address::from_str(&address_record.ref_).ok(),
|
||||
Address::from_str(&address_record.ref_.clone().assume_checked().to_string())
|
||||
.ok(),
|
||||
address_record.label.clone(),
|
||||
) {
|
||||
if addr.is_valid_for_network(network) {
|
||||
@ -600,7 +601,7 @@ impl LabelItem {
|
||||
}
|
||||
bip329::Label::Output(output_record) => {
|
||||
if let (Some(outpoint), Some(label)) = (
|
||||
OutPoint::from_str(&output_record.ref_).ok(),
|
||||
OutPoint::from_str(&output_record.ref_.to_string()).ok(),
|
||||
output_record.label.clone(),
|
||||
) {
|
||||
Some((Self::OutPoint(outpoint), label))
|
||||
|
||||
@ -3,7 +3,14 @@ use liana::descriptors::LianaDescriptor;
|
||||
|
||||
use std::{convert::TryFrom, str::FromStr};
|
||||
|
||||
use miniscript::bitcoin::{self, address, bip32, consensus::encode, psbt::Psbt};
|
||||
use miniscript::bitcoin::{
|
||||
self,
|
||||
address::{self, NetworkUnchecked},
|
||||
bip32,
|
||||
consensus::encode,
|
||||
psbt::Psbt,
|
||||
Address, OutPoint,
|
||||
};
|
||||
|
||||
// Due to limitations of Sqlite's ALTER TABLE command and in order not to recreate
|
||||
// tables during migration:
|
||||
@ -376,14 +383,19 @@ impl From<DbLabel> for Label {
|
||||
Some(value.value)
|
||||
};
|
||||
match value.item_kind {
|
||||
DbLabelledKind::Address => Label::Address(bip329::AddressRecord { ref_, label }),
|
||||
DbLabelledKind::OutPoint => Label::Output(bip329::OutputRecord {
|
||||
ref_,
|
||||
DbLabelledKind::Address => Label::Address(bip329::AddressRecord {
|
||||
ref_: Address::<NetworkUnchecked>::from_str(&ref_)
|
||||
.expect("db contains valid adresses"),
|
||||
label,
|
||||
spendable: None,
|
||||
}),
|
||||
DbLabelledKind::OutPoint => Label::Output(bip329::OutputRecord {
|
||||
ref_: OutPoint::from_str(&ref_).expect(" db contais valid outpoints"),
|
||||
label,
|
||||
spendable: true,
|
||||
}),
|
||||
DbLabelledKind::Txid => Label::Transaction(bip329::TransactionRecord {
|
||||
ref_,
|
||||
ref_: bitcoin::consensus::encode::deserialize_hex(&ref_)
|
||||
.expect("db contains valid txid"),
|
||||
label,
|
||||
// FIXME: "Optional key origin information referencing the wallet associated with the label"
|
||||
origin: None,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user