From 35dbb47bc1212b07859438fe989d4598e7eeb3e9 Mon Sep 17 00:00:00 2001 From: edouard Date: Wed, 29 Mar 2023 10:09:13 +0200 Subject: [PATCH 1/4] gui: update liana with multipath support --- gui/Cargo.lock | 1092 ++++++++++++++---------- gui/src/app/mod.rs | 4 +- gui/src/app/state/coins.rs | 4 +- gui/src/app/state/mod.rs | 4 +- gui/src/app/state/recovery.rs | 4 +- gui/src/app/state/settings/bitcoind.rs | 6 +- gui/src/app/state/spend/mod.rs | 2 +- gui/src/app/state/spend/step.rs | 4 +- gui/src/app/view/coins.rs | 10 +- gui/src/app/view/home.rs | 9 +- gui/src/app/view/spend/detail.rs | 12 +- gui/src/app/view/spend/mod.rs | 30 +- gui/src/app/view/spend/step.rs | 6 +- gui/src/app/wallet.rs | 6 +- gui/src/daemon/embedded.rs | 2 +- gui/src/daemon/model.rs | 18 +- gui/src/installer/step/descriptor.rs | 7 +- gui/src/installer/step/mnemonic.rs | 6 +- 18 files changed, 710 insertions(+), 516 deletions(-) diff --git a/gui/Cargo.lock b/gui/Cargo.lock index e697d4d7..68451450 100644 --- a/gui/Cargo.lock +++ b/gui/Cargo.lock @@ -31,9 +31,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "ab_glyph" -version = "0.2.15" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" +checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -41,15 +41,15 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "addr2line" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ "gimli", ] @@ -60,12 +60,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - [[package]] name = "ahash" version = "0.3.8" @@ -85,9 +79,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -118,9 +112,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -136,9 +130,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "ash" -version = "0.37.0+1.3.209" +version = "0.37.2+1.3.238" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6" +checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03" dependencies = [ "libloading", ] @@ -165,13 +159,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -182,9 +176,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ "addr2line", "cc", @@ -197,9 +191,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64-compat" @@ -218,12 +212,11 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bip39" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ - "bitcoin_hashes 0.9.7", - "rand_core 0.4.2", + "bitcoin_hashes", "serde", "unicode-normalization", ] @@ -245,25 +238,19 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" -version = "0.29.1" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cb36de3b18ad25f396f9168302e36fb7e1e8923298ab3127da252d288d5af9d" +checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ "base64", "bech32", - "bitcoin_hashes 0.11.0", + "bitcoin_hashes", "core2", "hashbrown 0.8.2", "secp256k1", "serde", ] -[[package]] -name = "bitcoin_hashes" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1" - [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -288,28 +275,28 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytemuck" -version = "1.11.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.1.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd2f4180c5721da6335cc9e9061cce522b87a35e51cc57636d28d22a9863c80" +checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -320,18 +307,18 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "calloop" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bcf530afb40e45e14440701e5e996d7fd139e84a912a4d83a8d6a0fb3e58663" +checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192" dependencies = [ "log", - "nix 0.25.0", + "nix 0.25.1", "slotmap", "thiserror", "vec_map", @@ -339,9 +326,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -372,22 +359,24 @@ checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "time", + "wasm-bindgen", "winapi", ] [[package]] name = "clipboard-win" -version = "4.4.2" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" dependencies = [ "error-code", "str-buf", @@ -426,18 +415,18 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.49" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] [[package]] name = "cocoa" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ "bitflags", "block", @@ -451,9 +440,9 @@ dependencies = [ [[package]] name = "cocoa-foundation" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ "bitflags", "block", @@ -476,9 +465,9 @@ dependencies = [ [[package]] name = "const_panic" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed2b28323eee4fb66bb824401daa3e46bd445b9a9298a3d382b320710ba69dd" +checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf" [[package]] name = "core-foundation" @@ -492,9 +481,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "core-graphics" @@ -553,9 +542,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -563,9 +552,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -574,26 +563,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", - "once_cell", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -625,6 +612,50 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "cxx" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.13", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + [[package]] name = "d3d12" version = "0.5.0" @@ -657,7 +688,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] @@ -668,7 +699,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -680,22 +711,22 @@ dependencies = [ "matches", ] -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", -] - [[package]] name = "dirs" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd" +dependencies = [ + "dirs-sys 0.4.0", ] [[package]] @@ -709,6 +740,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b" +dependencies = [ + "libc", + "redox_users", + "windows-sys 0.45.0", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -752,9 +794,9 @@ dependencies = [ [[package]] name = "either" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encase" @@ -785,7 +827,7 @@ checksum = "0f2f4de457d974f548d2c2a16f709ebd81013579e543bd1a9b19ced88132c2cf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -800,9 +842,9 @@ dependencies = [ [[package]] name = "euclid" -version = "0.22.7" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" dependencies = [ "num-traits", ] @@ -831,9 +873,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fern" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" dependencies = [ "log", ] @@ -849,9 +891,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "miniz_oxide", @@ -910,13 +952,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -955,9 +997,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -970,9 +1012,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -980,15 +1022,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -998,38 +1040,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1064,9 +1106,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -1075,9 +1117,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.2" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "gl_generator" @@ -1139,7 +1181,7 @@ dependencies = [ "once_cell", "osmesa-sys", "parking_lot 0.12.1", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "wayland-client", "wayland-egl", "winapi", @@ -1187,13 +1229,12 @@ dependencies = [ [[package]] name = "glyph_brush" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69c65dd1f1fbb6209aa00f78636e436ad0a55b7d8e5de886d00720dcad9c6e2" +checksum = "4edefd123f28a0b1d41ec4a489c2b43020b369180800977801611084f342978d" dependencies = [ "glyph_brush_draw_cache", "glyph_brush_layout", - "log", "ordered-float", "rustc-hash", "twox-hash", @@ -1245,13 +1286,13 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" +checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags", "gpu-descriptor-types", - "hashbrown 0.11.2", + "hashbrown 0.12.3", ] [[package]] @@ -1297,6 +1338,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] [[package]] name = "hashlink" @@ -1309,15 +1353,15 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] @@ -1336,13 +1380,38 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "hidapi" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d26e1151deaab68f34fbfd16d491a2a0170cf98d69d3efa23873b567a4199e1" +checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" dependencies = [ "cc", "libc", "pkg-config", + "winapi", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", ] [[package]] @@ -1429,7 +1498,7 @@ dependencies = [ "log", "lyon", "qrcode", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "resvg", "thiserror", "tiny-skia 0.6.6", @@ -1487,7 +1556,7 @@ dependencies = [ "iced_graphics", "iced_native", "log", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "wgpu", "wgpu_glyph", ] @@ -1517,9 +1586,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1539,9 +1608,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jni-sys" @@ -1557,9 +1626,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1658,12 +1727,12 @@ dependencies = [ [[package]] name = "liana" version = "0.3.0" -source = "git+https://github.com/wizardsardine/liana?branch=master#9c6059c9969c8f258854f2aad47b4c20ca4079af" +source = "git+https://github.com/wizardsardine/liana?branch=master#045182e7eae5846d33934adeb2018ab6857173ae" dependencies = [ "backtrace", "base64", "bip39", - "dirs", + "dirs 5.0.0", "fern", "getrandom", "jsonrpc", @@ -1684,7 +1753,7 @@ dependencies = [ "backtrace", "base64", "chrono", - "dirs", + "dirs 3.0.2", "iced", "iced_lazy", "iced_native", @@ -1710,15 +1779,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libloading" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", "winapi", @@ -1761,6 +1830,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1769,9 +1847,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -1798,9 +1876,9 @@ dependencies = [ [[package]] name = "lyon_algorithms" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb7a1845c15729d73d25d42cb650b647f73c3494453a5c3cd3aae0df3ac5c6c" +checksum = "00a0349cd8f0270781bb93a824b63df6178e3b4a27794e7be3ce3763f5a44d6e" dependencies = [ "lyon_path", "num-traits", @@ -1808,9 +1886,9 @@ dependencies = [ [[package]] name = "lyon_geom" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5237e77afe5a112d5ce8060e3473e78b09b5f8cea722a251dcafa1254711f440" +checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" dependencies = [ "arrayvec 0.7.2", "euclid", @@ -1819,9 +1897,9 @@ dependencies = [ [[package]] name = "lyon_path" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2a6c0d4a27bb3fe8b747184caf79a57b8bd2caeee49c0f9e59d068d30f7a0d" +checksum = "7da8358c012e5651e4619cfd0b5b75c0f77866181a01b0909aab4bae14adf660" dependencies = [ "lyon_geom", "num-traits", @@ -1829,9 +1907,9 @@ dependencies = [ [[package]] name = "lyon_tessellation" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba55cb38c7c601bc578e30164ec0f806a3e731c2593c8702500901cd4c363a4" +checksum = "7d2124218d5428149f9e09520b9acc024334a607e671f032d06567b61008977c" dependencies = [ "float_next_after", "lyon_path", @@ -1867,15 +1945,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" @@ -1894,9 +1966,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.5" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -1910,6 +1982,24 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "metal" version = "0.24.0" @@ -1941,34 +2031,34 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.45.0", ] [[package]] name = "mio-serial" -version = "5.0.2" +version = "5.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531e0f6dc55a5aa7b8d320407c5c4ced464e23815c60f6a1e6d9e225d2b45905" +checksum = "20a4c60ca5c9c0e114b3bd66ff4aa5f9b2b175442be51ca6c4365d687a97a2ac" dependencies = [ "log", "mio", - "nix 0.23.1", + "nix 0.26.2", "serialport", "winapi", ] @@ -2003,7 +2093,7 @@ dependencies = [ "jni-sys", "ndk-sys", "num_enum", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "thiserror", ] @@ -2039,7 +2129,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2061,44 +2151,46 @@ dependencies = [ "cc", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] name = "nix" -version = "0.23.1" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "nix" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ "bitflags", "cfg-if", "libc", + "memoffset 0.6.5", ] [[package]] name = "nix" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", "bitflags", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", + "static_assertions", ] [[package]] @@ -2109,9 +2201,9 @@ checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -2149,9 +2241,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ "hermit-abi", "libc", @@ -2159,23 +2251,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2219,24 +2311,24 @@ dependencies = [ [[package]] name = "object" -version = "0.29.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "ordered-float" -version = "3.0.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bcbab4bfea7a59c2c0fe47211a1ac4e3e96bea6eb446d704f310bc5c732ae2" +checksum = "13a384337e997e6860ffbaa83708b2ef329fd8c54cb67a5f64d421e0f943254f" dependencies = [ "num-traits", ] @@ -2271,7 +2363,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2282,11 +2374,11 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owned_ttf_parser" -version = "0.15.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" +checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228" dependencies = [ - "ttf-parser 0.15.2", + "ttf-parser 0.18.1", ] [[package]] @@ -2310,7 +2402,7 @@ dependencies = [ "find-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2321,7 +2413,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -2331,41 +2423,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.7", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", "libc", "redox_syscall", - "smallvec 1.9.0", + "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", - "smallvec 1.9.0", - "windows-sys 0.42.0", + "smallvec", + "windows-sys 0.45.0", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "phf" @@ -2397,7 +2489,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2429,36 +2521,36 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "png" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ "bitflags", "crc32fast", - "deflate", + "flate2", "miniz_oxide", ] [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "thiserror", - "toml", + "once_cell", + "toml_edit", ] [[package]] @@ -2470,7 +2562,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -2487,18 +2579,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.41" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc2916cde080c1876ff40292a396541241fe0072ef928cd76582e9ea5d60d2" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f61dcf0b917cd75d4521d7343d1ffff3d1583054133c9b5cbea3375c703c40d" +checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df" [[package]] name = "qrcode" @@ -2511,9 +2603,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -2526,7 +2618,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.3", + "rand_core", ] [[package]] @@ -2536,29 +2628,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core", ] [[package]] name = "rand_core" -version = "0.4.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "range-alloc" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" [[package]] name = "raw-window-handle" @@ -2581,30 +2667,25 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "rayon" -version = "1.5.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2624,14 +2705,14 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e233b642160555c1aa1ff7a78443c6139342f411b6fa6602af2ebbfee9e166bb" dependencies = [ - "rand_core 0.6.3", + "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -2649,9 +2730,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -2660,9 +2741,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "renderdoc-sys" @@ -2688,9 +2769,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.33" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b221de559e4a29df3b957eec92bc0de6bc8eaf6ca9cfed43e5e1d67ff65a34" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" dependencies = [ "bytemuck", ] @@ -2716,14 +2797,14 @@ dependencies = [ "hashlink", "libsqlite3-sys", "memchr", - "smallvec 1.9.0", + "smallvec", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustc-hash" @@ -2739,7 +2820,7 @@ checksum = "44561062e583c4873162861261f16fd1d85fe927c4904d71329a4fe43dc355ef" dependencies = [ "bitflags", "bytemuck", - "smallvec 1.9.0", + "smallvec", "ttf-parser 0.12.3", "unicode-bidi-mirroring", "unicode-ccc", @@ -2749,9 +2830,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "safe_arch" @@ -2764,9 +2845,9 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" @@ -2774,6 +2855,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + [[package]] name = "sctk-adwaita" version = "0.4.3" @@ -2788,11 +2875,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.0" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ - "bitcoin_hashes 0.11.0", + "bitcoin_hashes", "secp256k1-sys", "serde", ] @@ -2808,29 +2895,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.140" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -2849,7 +2936,7 @@ dependencies = [ "cfg-if", "libudev", "mach 0.3.2", - "nix 0.24.2", + "nix 0.24.3", "regex", "winapi", ] @@ -2896,9 +2983,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -2920,9 +3007,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2938,18 +3025,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "0.6.14" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smithay-client-toolkit" @@ -2962,8 +3040,8 @@ dependencies = [ "dlib", "lazy_static", "log", - "memmap2 0.5.5", - "nix 0.24.2", + "memmap2 0.5.10", + "nix 0.24.3", "pkg-config", "wayland-client", "wayland-cursor", @@ -2982,9 +3060,9 @@ dependencies = [ [[package]] name = "snafu" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ba99b054b22972ee794cf04e5ef572da1229e33b65f3c57abbff0525a454" +checksum = "cb0656e7e3ffb70f6c39b3c2a86332bb74aa3c679da781642590f3c1118c5045" dependencies = [ "doc-comment", "snafu-derive", @@ -2992,21 +3070,21 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5e79cdebbabaebb06a9bdbaedc7f159b410461f63611d4d0e3fb0fab8fed850" +checksum = "475b3bbe5245c26f2d8a6f62d67c1f30eb9fffeccee721c45d162c3ebbdf81b2" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -3064,18 +3142,29 @@ dependencies = [ [[package]] name = "svgtypes" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc802f68b144cdf4d8ff21301f9a7863e837c627fde46537e29c05e8a18c85c1" +checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564" dependencies = [ "siphasher", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" dependencies = [ "proc-macro2", "quote", @@ -3084,31 +3173,31 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] @@ -3123,9 +3212,9 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -3172,40 +3261,54 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "1.21.2" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.45.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.13", ] [[package]] name = "tokio-serial" -version = "5.4.3" +version = "5.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5488e0c75c70e880823aebc3ad4ac0a6da6f48d95bc1b9a52bd3200d6f1e724" +checksum = "aa6e2e4cf0520a99c5f87d5abb24172b5bd220de57c3181baaaa5440540c64aa" dependencies = [ "cfg-if", "futures", @@ -3216,13 +3319,30 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.37" @@ -3243,7 +3363,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3275,7 +3395,7 @@ checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ "nu-ansi-term", "sharded-slab", - "smallvec 1.9.0", + "smallvec", "thread_local", "tracing-core", "tracing-log", @@ -3289,9 +3409,9 @@ checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" [[package]] name = "ttf-parser" -version = "0.15.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" +checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "twox-hash" @@ -3306,9 +3426,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-bidi-mirroring" @@ -3330,30 +3450,30 @@ checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.9" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ - "smallvec 0.6.14", + "tinyvec", ] [[package]] name = "unicode-script" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dd944fd05f2f0b5c674917aea8a4df6af84f2d8de3fe8d988b95d28fb8fb09" +checksum = "7d817255e1bed6dfd4ca47258685d14d2bdcfbc64fdc9e3819bd5848057b8ecc" [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-vo" @@ -3363,9 +3483,9 @@ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -3438,9 +3558,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3448,24 +3568,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -3475,9 +3595,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3485,22 +3605,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-timer" @@ -3519,14 +3639,14 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" dependencies = [ "bitflags", "downcast-rs", "libc", - "nix 0.22.3", + "nix 0.24.3", "scoped-tls", "wayland-commons", "wayland-scanner", @@ -3535,32 +3655,32 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" dependencies = [ - "nix 0.22.3", + "nix 0.24.3", "once_cell", - "smallvec 1.9.0", + "smallvec", "wayland-sys", ] [[package]] name = "wayland-cursor" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" dependencies = [ - "nix 0.22.3", + "nix 0.24.3", "wayland-client", "xcursor", ] [[package]] name = "wayland-egl" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" +checksum = "402de949f81a012926d821a2d659f930694257e76dd92b6e0042ceb27be4107d" dependencies = [ "wayland-client", "wayland-sys", @@ -3568,9 +3688,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" dependencies = [ "bitflags", "wayland-client", @@ -3580,9 +3700,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" dependencies = [ "proc-macro2", "quote", @@ -3591,9 +3711,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" dependencies = [ "dlib", "lazy_static", @@ -3602,9 +3722,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -3612,17 +3732,17 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2272b17bffc8a0c7d53897435da7c1db587c87d3a14e8dae9cdb8d1d210fc0f" +checksum = "81f643110d228fd62a60c5ed2ab56c4d5b3704520bd50561174ec4ec74932937" dependencies = [ "arrayvec 0.7.2", "js-sys", "log", "naga", "parking_lot 0.12.1", - "raw-window-handle 0.5.0", - "smallvec 1.9.0", + "raw-window-handle 0.5.2", + "smallvec", "static_assertions", "wasm-bindgen", "wasm-bindgen-futures", @@ -3634,9 +3754,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d14cad393054caf992ee02b7da6a372245d39a484f7461c1f44f6f6359bd28" +checksum = "6000d1284ef8eec6076fd5544a73125fd7eb9b635f18dceeb829d826f41724ca" dependencies = [ "arrayvec 0.7.2", "bit-vec", @@ -3648,8 +3768,8 @@ dependencies = [ "naga", "parking_lot 0.12.1", "profiling", - "raw-window-handle 0.5.0", - "smallvec 1.9.0", + "raw-window-handle 0.5.2", + "smallvec", "thiserror", "web-sys", "wgpu-hal", @@ -3685,9 +3805,9 @@ dependencies = [ "parking_lot 0.12.1", "profiling", "range-alloc", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "renderdoc-sys", - "smallvec 1.9.0", + "smallvec", "thiserror", "wasm-bindgen", "web-sys", @@ -3758,9 +3878,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47d7fb4df5cd1fea61e5ee3841380f54359bac814e227d8f72709f4f193f8cf" +checksum = "015dd4474dc6aa96fe19aae3a24587a088bd90331dba5a5cc60fb3a180234c4d" dependencies = [ "clipboard-win", "clipboard_macos", @@ -3770,6 +3890,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + [[package]] name = "windows-sys" version = "0.36.1" @@ -3785,24 +3914,54 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" @@ -3812,9 +3971,15 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" @@ -3824,9 +3989,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" @@ -3836,9 +4007,15 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" @@ -3848,15 +4025,27 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" @@ -3866,9 +4055,15 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winit" @@ -3892,7 +4087,7 @@ dependencies = [ "parking_lot 0.12.1", "percent-encoding", "raw-window-handle 0.4.3", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "sctk-adwaita", "smithay-client-toolkit", "wasm-bindgen", @@ -3903,6 +4098,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "wio" version = "0.2.2" @@ -3914,12 +4118,12 @@ dependencies = [ [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" dependencies = [ - "lazy_static", "libc", + "once_cell", "pkg-config", ] @@ -3958,9 +4162,9 @@ checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" [[package]] name = "xmlparser" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" +checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" [[package]] name = "xmlwriter" diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 5160edc1..c02a4c55 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -71,13 +71,13 @@ impl App { menu::Menu::Home => Home::new(self.wallet.clone(), &self.cache.coins).into(), menu::Menu::Coins => CoinsPanel::new( &self.cache.coins, - self.wallet.main_descriptor.timelock_value(), + self.wallet.main_descriptor.first_timelock_value(), ) .into(), menu::Menu::Recovery => RecoveryPanel::new( self.wallet.clone(), &self.cache.coins, - self.wallet.main_descriptor.timelock_value(), + self.wallet.main_descriptor.first_timelock_value(), self.cache.blockheight as u32, ) .into(), diff --git a/gui/src/app/state/coins.rs b/gui/src/app/state/coins.rs index 83119eca..0a56d9c1 100644 --- a/gui/src/app/state/coins.rs +++ b/gui/src/app/state/coins.rs @@ -15,11 +15,11 @@ pub struct CoinsPanel { selected: Vec, warning: Option, /// timelock value to pass for the heir to consume a coin. - timelock: u32, + timelock: u16, } impl CoinsPanel { - pub fn new(coins: &[Coin], timelock: u32) -> Self { + pub fn new(coins: &[Coin], timelock: u16) -> Self { let mut panel = Self { coins: Vec::new(), selected: Vec::new(), diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index 9ffd6b17..3d7dfd74 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -124,12 +124,12 @@ impl State for Home { for coin in coins { if coin.spend_info.is_none() && coin.block_height.is_some() { self.balance += coin.amount; - let timelock = self.wallet.main_descriptor.timelock_value(); + let timelock = self.wallet.main_descriptor.first_timelock_value(); let seq = remaining_sequence(&coin, cache.blockheight as u32, timelock); if seq == 0 { recovery_alert.0 += coin.amount; recovery_alert.1 += 1; - } else if seq < timelock * 10 / 100 { + } else if seq < timelock as u32 * 10 / 100 { recovery_warning.0 += coin.amount; recovery_warning.1 += 1; } diff --git a/gui/src/app/state/recovery.rs b/gui/src/app/state/recovery.rs index f6d9ac32..f2be2064 100644 --- a/gui/src/app/state/recovery.rs +++ b/gui/src/app/state/recovery.rs @@ -33,11 +33,11 @@ pub struct RecoveryPanel { recipient: form::Value, generated: Option, /// timelock value to pass for the heir to consume a coin. - timelock: u32, + timelock: u16, } impl RecoveryPanel { - pub fn new(wallet: Arc, coins: &[Coin], timelock: u32, blockheight: u32) -> Self { + pub fn new(wallet: Arc, coins: &[Coin], timelock: u16, blockheight: u32) -> Self { let mut locked_coins = (0, Amount::from_sat(0)); let mut recoverable_coins = (0, Amount::from_sat(0)); for coin in coins { diff --git a/gui/src/app/state/settings/bitcoind.rs b/gui/src/app/state/settings/bitcoind.rs index 1d7d2431..a31ab761 100644 --- a/gui/src/app/state/settings/bitcoind.rs +++ b/gui/src/app/state/settings/bitcoind.rs @@ -302,13 +302,13 @@ impl Setting for RescanSetting { } } view::SettingsEditMessage::Confirm => { - let date_time = NaiveDate::from_ymd( + let date_time = NaiveDate::from_ymd_opt( i32::from_str(&self.year.value).unwrap_or(1), u32::from_str(&self.month.value).unwrap_or(1), u32::from_str(&self.day.value).unwrap_or(1), ) - .and_hms(0, 0, 0); - let t = date_time.timestamp() as u32; + .unwrap(); + let t = date_time.and_hms_opt(0, 0, 0).unwrap().timestamp() as u32; self.processing = true; info!("Asking deamon to rescan with timestamp: {}", t); return Command::perform( diff --git a/gui/src/app/state/spend/mod.rs b/gui/src/app/state/spend/mod.rs index 771a9e88..3204ecb5 100644 --- a/gui/src/app/state/spend/mod.rs +++ b/gui/src/app/state/spend/mod.rs @@ -138,7 +138,7 @@ pub struct CreateSpendPanel { impl CreateSpendPanel { pub fn new(wallet: Arc, coins: &[Coin], blockheight: u32) -> Self { let descriptor = wallet.main_descriptor.clone(); - let timelock = descriptor.timelock_value(); + let timelock = descriptor.first_timelock_value(); Self { draft: step::TransactionDraft::default(), current: 0, diff --git a/gui/src/app/state/spend/step.rs b/gui/src/app/state/spend/step.rs index 6e136725..56ab745c 100644 --- a/gui/src/app/state/spend/step.rs +++ b/gui/src/app/state/spend/step.rs @@ -224,7 +224,7 @@ impl Recipient { pub struct ChooseCoins { descriptor: LianaDescriptor, - timelock: u32, + timelock: u16, coins: Vec<(Coin, bool)>, recipients: Vec<(Address, Amount)>, @@ -238,7 +238,7 @@ impl ChooseCoins { pub fn new( descriptor: LianaDescriptor, coins: Vec, - timelock: u32, + timelock: u16, blockheight: u32, ) -> Self { let mut coins: Vec<(Coin, bool)> = coins diff --git a/gui/src/app/view/coins.rs b/gui/src/app/view/coins.rs index 15e7a00f..5a62548b 100644 --- a/gui/src/app/view/coins.rs +++ b/gui/src/app/view/coins.rs @@ -19,7 +19,7 @@ use crate::{ pub fn coins_view<'a>( cache: &Cache, coins: &'a [Coin], - timelock: u32, + timelock: u16, selected: &[usize], ) -> Element<'a, Message> { Column::new() @@ -55,7 +55,7 @@ pub fn coins_view<'a>( #[allow(clippy::collapsible_else_if)] fn coin_list_view( coin: &Coin, - timelock: u32, + timelock: u16, blockheight: u32, index: usize, collapsed: bool, @@ -84,7 +84,7 @@ fn coin_list_view( ) .align_items(Alignment::Center), )) - } else if seq < timelock * 10 / 100 { + } else if seq < timelock as u32 * 10 / 100 { Some(Container::new( Row::new() .spacing(5) @@ -138,7 +138,7 @@ fn coin_list_view( .spacing(5) .push_maybe(if coin.spend_info.is_none() { if let Some(b) = coin.block_height { - if blockheight > b as u32 + timelock { + if blockheight > b as u32 + timelock as u32 { Some(Container::new( text("The recovery path is available") .bold() @@ -147,7 +147,7 @@ fn coin_list_view( )) } else { Some(Container::new( - text(format!("The recovery path will be available in {} blocks", b as u32 + timelock - blockheight)) + text(format!("The recovery path will be available in {} blocks", b as u32 + timelock as u32 - blockheight)) .bold() .small(), )) diff --git a/gui/src/app/view/home.rs b/gui/src/app/view/home.rs index 7b4a30a2..19dd6c22 100644 --- a/gui/src/app/view/home.rs +++ b/gui/src/app/view/home.rs @@ -127,8 +127,11 @@ fn event_list_view<'a>(i: usize, event: &HistoryTransaction) -> Element<'a, Mess }) .push(if let Some(t) = event.time { Container::new( - text(format!("{}", NaiveDateTime::from_timestamp(t as i64, 0))) - .small(), + text(format!( + "{}", + NaiveDateTime::from_timestamp_opt(t as i64, 0).unwrap(), + )) + .small(), ) } else { badge::unconfirmed() @@ -186,7 +189,7 @@ pub fn event_view<'a>(cache: &Cache, event: &'a HistoryTransaction) -> Element<' .push(card::simple( Column::new() .push_maybe(event.time.map(|t| { - let date = NaiveDateTime::from_timestamp(t as i64, 0); + let date = NaiveDateTime::from_timestamp_opt(t as i64, 0).unwrap(); Row::new() .width(Length::Fill) .push(Container::new(text("Date:").bold()).width(Length::Fill)) diff --git a/gui/src/app/view/spend/detail.rs b/gui/src/app/view/spend/detail.rs index 3bb0f0d8..a02b66e2 100644 --- a/gui/src/app/view/spend/detail.rs +++ b/gui/src/app/view/spend/detail.rs @@ -203,7 +203,7 @@ fn spend_header<'a>(tx: &SpendTx) -> Element<'a, Message> { .push( Row::new() .push(badge::Badge::new(icon::send_icon()).style(theme::Badge::Standard)) - .push(if tx.sigs.recovery_path().is_some() { + .push(if !tx.sigs.recovery_paths().is_empty() { text("Recovery").bold() } else { text("Spend").bold() @@ -363,8 +363,8 @@ pub fn signatures<'a>( Column::new() .padding(15) .spacing(10) - .push(text(if tx.sigs.recovery_path().is_some() { - "2 spending paths available. Finalizing this transaction requires either:" + .push(text(if !tx.sigs.recovery_paths().is_empty() { + "Multiple spending paths available. Finalizing this transaction requires either:" } else { "1 spending path available. Finalizing this transaction requires:" })) @@ -373,9 +373,9 @@ pub fn signatures<'a>( tx.sigs.primary_path(), keys_aliases, )) - .push_maybe(tx.sigs.recovery_path().as_ref().map(|path| { - let (_, keys) = desc_info.recovery_path(); - path_view(keys, path, keys_aliases) + .push(tx.sigs.recovery_paths().iter().fold(Column::new().spacing(10), |col, (seq, path)| { + let keys = &desc_info.recovery_paths()[seq]; + col.push(path_view(keys, path, keys_aliases)) })), ), ) diff --git a/gui/src/app/view/spend/mod.rs b/gui/src/app/view/spend/mod.rs index 465d2e60..ccd7315a 100644 --- a/gui/src/app/view/spend/mod.rs +++ b/gui/src/app/view/spend/mod.rs @@ -110,30 +110,12 @@ fn spend_tx_list_view<'a>(i: usize, tx: &SpendTx) -> Element<'a, Message> { .push( Row::new() .push(badge::spend()) - .push(if let Some(sigs) = tx.sigs.recovery_path() { - Row::new() - .spacing(10) - .align_items(Alignment::Center) - .push( - Row::new() - .spacing(5) - .align_items(Alignment::Center) - .push(text(format!( - "{}/{}", - if sigs.sigs_count <= sigs.threshold { - sigs.sigs_count - } else { - sigs.threshold - }, - sigs.threshold - ))) - .push(icon::key_icon()), - ) - .push( - Container::new(text(" Recovery ").small()) - .padding(3) - .style(theme::Container::Pill(theme::Pill::Simple)), - ) + .push(if !tx.sigs.recovery_paths().is_empty() { + Row::new().push( + Container::new(text(" Recovery ").small()) + .padding(3) + .style(theme::Container::Pill(theme::Pill::Simple)), + ) } else { let sigs = tx.sigs.primary_path(); Row::new() diff --git a/gui/src/app/view/spend/step.rs b/gui/src/app/view/spend/step.rs index c151223a..3adc5d85 100644 --- a/gui/src/app/view/spend/step.rs +++ b/gui/src/app/view/spend/step.rs @@ -120,7 +120,7 @@ pub fn recipient_view<'a>( pub fn choose_coins_view<'a>( cache: &Cache, - timelock: u32, + timelock: u16, coins: &[(Coin, bool)], amount_left: Option<&Amount>, feerate: &form::Value, @@ -192,7 +192,7 @@ pub fn choose_coins_view<'a>( fn coin_list_view<'a>( i: usize, coin: &Coin, - timelock: u32, + timelock: u16, blockheight: u32, selected: bool, ) -> Element<'a, Message> { @@ -223,7 +223,7 @@ fn coin_list_view<'a>( ) .align_items(Alignment::Center), )) - } else if seq < timelock * 10 / 100 { + } else if seq < timelock as u32 * 10 / 100 { Some(Container::new( Row::new() .spacing(5) diff --git a/gui/src/app/wallet.rs b/gui/src/app/wallet.rs index 421b8798..e8907740 100644 --- a/gui/src/app/wallet.rs +++ b/gui/src/app/wallet.rs @@ -55,8 +55,10 @@ impl Wallet { for (fingerprint, _) in info.primary_path().thresh_origins().1.iter() { descriptor_keys.insert(*fingerprint); } - for (fingerprint, _) in info.recovery_path().1.thresh_origins().1.iter() { - descriptor_keys.insert(*fingerprint); + for path in info.recovery_paths().values() { + for (fingerprint, _) in path.thresh_origins().1.iter() { + descriptor_keys.insert(*fingerprint); + } } descriptor_keys } diff --git a/gui/src/daemon/embedded.rs b/gui/src/daemon/embedded.rs index 079ad0f6..973c71f7 100644 --- a/gui/src/daemon/embedded.rs +++ b/gui/src/daemon/embedded.rs @@ -201,7 +201,7 @@ impl Daemon for EmbeddedDaemon { .read() .unwrap() .control - .create_recovery(address, feerate_vb) + .create_recovery(address, feerate_vb, None) .map_err(|e| DaemonError::Unexpected(e.to_string())) .map(|res| res.psbt) } diff --git a/gui/src/daemon/model.rs b/gui/src/daemon/model.rs index 7443f60d..2f57da14 100644 --- a/gui/src/daemon/model.rs +++ b/gui/src/daemon/model.rs @@ -9,15 +9,15 @@ pub use liana::{ pub type Coin = ListCoinsEntry; -pub fn remaining_sequence(coin: &Coin, blockheight: u32, timelock: u32) -> u32 { +pub fn remaining_sequence(coin: &Coin, blockheight: u32, timelock: u16) -> u32 { if let Some(coin_blockheight) = coin.block_height { - if blockheight > coin_blockheight as u32 + timelock { + if blockheight > coin_blockheight as u32 + timelock as u32 { 0 } else { - coin_blockheight as u32 + timelock - blockheight + coin_blockheight as u32 + timelock as u32 - blockheight } } else { - timelock + timelock as u32 } } @@ -89,12 +89,10 @@ impl SpendTx { if path.sigs_count >= path.threshold { return Some(path); } - if let Some(path) = self.sigs.recovery_path() { - if path.sigs_count >= path.threshold { - return Some(path); - } - } - None + self.sigs + .recovery_paths() + .values() + .find(|&path| path.sigs_count >= path.threshold) } } diff --git a/gui/src/installer/step/descriptor.rs b/gui/src/installer/step/descriptor.rs index 33d5f0c6..c977e950 100644 --- a/gui/src/installer/step/descriptor.rs +++ b/gui/src/installer/step/descriptor.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; @@ -424,7 +424,10 @@ impl Step for DefineDescriptor { PathInfo::Multi(self.recovery_threshold, recovery_keys) }; - let policy = match LianaPolicy::new(spending_keys, recovery_keys, sequence.unwrap()) { + let mut recovery_paths = BTreeMap::new(); + recovery_paths.insert(sequence.unwrap(), recovery_keys); + + let policy = match LianaPolicy::new(spending_keys, recovery_paths) { Ok(policy) => policy, Err(e) => { self.error = Some(e.to_string()); diff --git a/gui/src/installer/step/mnemonic.rs b/gui/src/installer/step/mnemonic.rs index a3831eff..1f0b7c4a 100644 --- a/gui/src/installer/step/mnemonic.rs +++ b/gui/src/installer/step/mnemonic.rs @@ -136,8 +136,10 @@ impl Step for RecoverMnemonic { for (fingerprint, _) in info.primary_path().thresh_origins().1.iter() { descriptor_keys.insert(*fingerprint); } - for (fingerprint, _) in info.recovery_path().1.thresh_origins().1.iter() { - descriptor_keys.insert(*fingerprint); + for (_, path) in info.recovery_paths().iter() { + for (fingerprint, _) in path.thresh_origins().1.iter() { + descriptor_keys.insert(*fingerprint); + } } if !descriptor_keys.contains(&fingerprint) { self.error = From 13248dbd026ef85bee147adbb0c6213c6fd017ec Mon Sep 17 00:00:00 2001 From: edouard Date: Wed, 29 Mar 2023 17:28:14 +0200 Subject: [PATCH 2/4] installer: add multipath support --- gui/src/installer/message.rs | 40 +- gui/src/installer/prompt.rs | 8 +- gui/src/installer/step/descriptor.rs | 685 +++++++++++++++++---------- gui/src/installer/view.rs | 475 +++++++++++-------- gui/ui/src/icon.rs | 8 + gui/ui/src/theme.rs | 80 +++- 6 files changed, 834 insertions(+), 462 deletions(-) diff --git a/gui/src/installer/message.rs b/gui/src/installer/message.rs index f403f469..e80856cd 100644 --- a/gui/src/installer/message.rs +++ b/gui/src/installer/message.rs @@ -43,16 +43,21 @@ pub enum DefineBitcoind { #[derive(Debug, Clone)] pub enum DefineDescriptor { ImportDescriptor(String), - /// AddKey(is_recovery) - AddKey(bool), - Key(bool, usize, DefineKey), - HWXpubImported(Result), - XPubEdited(String), - EditName, - NameEdited(String), - SequenceEdited(String), - ThresholdEdited(bool, usize), - ConfirmXpub, + PrimaryPath(DefinePath), + RecoveryPath(usize, DefinePath), + AddRecoveryPath, + KeyModal(ImportKeyModal), + SequenceModal(SequenceModal), +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum DefinePath { + AddKey, + Key(usize, DefineKey), + ThresholdEdited(usize), + SequenceEdited(u16), + EditSequence, } #[derive(Debug, Clone)] @@ -62,3 +67,18 @@ pub enum DefineKey { Clipboard(String), Edited(String, DescriptorPublicKey), } + +#[derive(Debug, Clone)] +pub enum ImportKeyModal { + HWXpubImported(Result), + XPubEdited(String), + EditName, + NameEdited(String), + ConfirmXpub, +} + +#[derive(Debug, Clone)] +pub enum SequenceModal { + SequenceEdited(String), + ConfirmSequence, +} diff --git a/gui/src/installer/prompt.rs b/gui/src/installer/prompt.rs index 4bbd862e..64b00599 100644 --- a/gui/src/installer/prompt.rs +++ b/gui/src/installer/prompt.rs @@ -1,9 +1,9 @@ pub const BACKUP_DESCRIPTOR_MESSAGE: &str = "The descriptor is necessary to recover your funds. The backup of your key (via mnemonics, sometimes called 'seed words') is not enough. Please make sure you have backed up both your private key and your descriptor."; pub const BACKUP_DESCRIPTOR_HELP: &str = "In Bitcoin, the coins are locked using a Script (related to the 'address'). In order to recover your funds you need both to know the Scripts you have participated in (your 'addresses'), and be able to sign a transaction that spends from those. For the ability to sign you backup your private key, this is your mnemonics ('seed words'). For finding the coins that belongs to you you backup a template of your Script ( / 'addresses'), this is your descriptor. Note however the descriptor needs not be as securely stored as the private key. A thief that steals your descriptor but not your private key will not be able to steal your funds."; -pub const DEFINE_DESCRIPTOR_PRIMATRY_PATH_TOOLTIP: &str = - "This is the keys that can spend received coins immediately,\n with no time restriction."; -pub const DEFINE_DESCRIPTOR_SEQUENCE_TOOLTIP: &str = - "Number of blocks after a coin is received \nfor which the recovery path is not available"; +pub const DEFINE_DESCRIPTOR_PRIMARY_PATH_TOOLTIP: &str = + "Set key(s) that can be used to spend coins immediately, with no time restriction."; +pub const DEFINE_DESCRIPTOR_RECOVERY_PATH_TOOLTIP: &str = + "Set key(s) that can be used to spend coins after a defined period of time.\n Different sets of keys can be set to become available at different times."; pub const DEFINE_DESCRIPTOR_FINGERPRINT_TOOLTIP: &str = "The alias is applied on all the keys derived from the same seed"; pub const REGISTER_DESCRIPTOR_HELP: &str = "To be used with the wallet, a device needs the descriptor. If the descriptor contains one or more keys imported from an external signing device, the descriptor must be registered on it. Registration on a device is not a substitute for backing up the descriptor."; diff --git a/gui/src/installer/step/descriptor.rs b/gui/src/installer/step/descriptor.rs index c977e950..1196cf15 100644 --- a/gui/src/installer/step/descriptor.rs +++ b/gui/src/installer/step/descriptor.rs @@ -35,7 +35,7 @@ use crate::{ signer::Signer, }; -pub trait DescriptorKeyModal { +pub trait DescriptorEditModal { fn processing(&self) -> bool { false } @@ -45,16 +45,53 @@ pub trait DescriptorKeyModal { fn view(&self) -> Element; } +pub struct RecoveryPath { + keys: Vec, + threshold: usize, + sequence: u16, +} + +impl RecoveryPath { + pub fn new() -> Self { + Self { + keys: vec![DescriptorKey::default()], + threshold: 1, + sequence: u16::MAX, + } + } + + fn valid(&self) -> bool { + !self.keys.is_empty() && !self.keys.iter().any(|k| k.key.is_none()) + } + + fn check_network(&mut self, network: Network) { + for key in self.keys.iter_mut() { + key.check_network(network); + } + } + + fn view(&self) -> Element { + view::recovery_path_view( + self.sequence, + self.threshold, + self.keys + .iter() + .enumerate() + .map(|(i, key)| key.view().map(move |msg| message::DefinePath::Key(i, msg))) + .collect(), + ) + } +} + pub struct DefineDescriptor { network: Network, network_valid: bool, data_dir: Option, spending_keys: Vec, spending_threshold: usize, - recovery_keys: Vec, - recovery_threshold: usize, - sequence: form::Value, - modal: Option>, + recovery_paths: Vec, + + modal: Option>, signer: Arc, error: Option, @@ -68,9 +105,7 @@ impl DefineDescriptor { network_valid: true, spending_keys: vec![DescriptorKey::default()], spending_threshold: 1, - recovery_keys: vec![DescriptorKey::default()], - recovery_threshold: 1, - sequence: form::Value::default(), + recovery_paths: vec![RecoveryPath::new()], modal: None, signer: Arc::new(Signer::generate(Network::Bitcoin).unwrap()), error: None, @@ -79,10 +114,8 @@ impl DefineDescriptor { fn valid(&self) -> bool { !self.spending_keys.is_empty() - && !self.recovery_keys.is_empty() - && !self.sequence.value.is_empty() - && !self.spending_keys.iter().any(|k| k.key.is_none()) && !self.spending_keys.iter().any(|k| k.key.is_none()) + && !self.recovery_paths.iter().any(|path| !path.valid()) } fn set_network(&mut self, network: Network) { @@ -97,8 +130,8 @@ impl DefineDescriptor { for key in self.spending_keys.iter_mut() { key.check_network(self.network); } - for key in self.recovery_keys.iter_mut() { - key.check_network(self.network); + for path in self.recovery_paths.iter_mut() { + path.check_network(self.network); } } @@ -126,19 +159,21 @@ impl DefineDescriptor { } } } - for recovery_key in &self.recovery_keys { - if let Some(key) = &recovery_key.key { - if let Some(fg) = all_names.get(&recovery_key.name) { - if fg != &key.master_fingerprint() { - duplicate_names.insert(recovery_key.name.clone()); + for path in &self.recovery_paths { + for recovery_key in &path.keys { + if let Some(key) = &recovery_key.key { + if let Some(fg) = all_names.get(&recovery_key.name) { + if fg != &key.master_fingerprint() { + duplicate_names.insert(recovery_key.name.clone()); + } + } else { + all_names.insert(recovery_key.name.clone(), key.master_fingerprint()); + } + if all_keys.contains(key) { + duplicate_keys.insert(key.clone()); + } else { + all_keys.insert(key.clone()); } - } else { - all_names.insert(recovery_key.name.clone(), key.master_fingerprint()); - } - if all_keys.contains(key) { - duplicate_keys.insert(key.clone()); - } else { - all_keys.insert(key.clone()); } } } @@ -148,9 +183,12 @@ impl DefineDescriptor { spending_key.duplicate_key = duplicate_keys.contains(key); } } - for recovery_key in self.recovery_keys.iter_mut() { - if let Some(key) = &recovery_key.key { - recovery_key.duplicate_key = duplicate_keys.contains(key); + + for path in &mut self.recovery_paths { + for recovery_key in path.keys.iter_mut() { + if let Some(key) = &recovery_key.key { + recovery_key.duplicate_key = duplicate_keys.contains(key); + } } } } @@ -161,9 +199,11 @@ impl DefineDescriptor { spending_key.name = name.clone(); } } - for recovery_key in &mut self.recovery_keys { - if recovery_key.key.as_ref().map(|k| k.master_fingerprint()) == Some(fingerprint) { - recovery_key.name = name.clone(); + for path in &mut self.recovery_paths { + for recovery_key in &mut path.keys { + if recovery_key.key.as_ref().map(|k| k.master_fingerprint()) == Some(fingerprint) { + recovery_key.name = name.clone(); + } } } } @@ -199,7 +239,10 @@ impl DefineDescriptor { } }; update_mapping(&self.spending_keys, &mut mapping); - update_mapping(&self.recovery_keys, &mut mapping); + + for path in &self.recovery_paths { + update_mapping(&path.keys, &mut mapping); + } mapping } @@ -210,9 +253,11 @@ impl DefineDescriptor { map.insert(key.master_fingerprint(), spending_key.name.clone()); } } - for recovery_key in &self.recovery_keys { - if let Some(key) = recovery_key.key.as_ref() { - map.insert(key.master_fingerprint(), recovery_key.name.clone()); + for path in &self.recovery_paths { + for recovery_key in &path.keys { + if let Some(key) = recovery_key.key.as_ref() { + map.insert(key.master_fingerprint(), recovery_key.name.clone()); + } } } map @@ -229,108 +274,146 @@ impl Step for DefineDescriptor { self.modal = None; } Message::Network(network) => self.set_network(network), - Message::DefineDescriptor(msg) => { - match msg { - message::DefineDescriptor::ThresholdEdited(is_recovery, value) => { - if is_recovery { - self.recovery_threshold = value; - } else { - self.spending_threshold = value; - } - } - message::DefineDescriptor::SequenceEdited(seq) => { - self.sequence.valid = true; - if seq.is_empty() || seq.parse::().is_ok() { - self.sequence.value = seq; - } - } - message::DefineDescriptor::AddKey(is_recovery) => { - if is_recovery { - self.recovery_keys.push(DescriptorKey::default()); - self.recovery_threshold += 1; - } else { - self.spending_keys.push(DescriptorKey::default()); - self.spending_threshold += 1; - } - } - message::DefineDescriptor::Key(is_recovery, i, msg) => match msg { - message::DefineKey::Clipboard(key) => { - return Command::perform(async move { key }, Message::Clibpboard); - } - message::DefineKey::Edited(name, imported_key) => { - self.edit_alias_for_key_with_same_fingerprint( - name.clone(), - imported_key.master_fingerprint(), - ); - if is_recovery { - if let Some(recovery_key) = self.recovery_keys.get_mut(i) { - recovery_key.name = name; - recovery_key.key = Some(imported_key); - recovery_key.check_network(self.network); - } - } else if let Some(spending_key) = self.spending_keys.get_mut(i) { - spending_key.name = name; - spending_key.key = Some(imported_key); - spending_key.check_network(self.network); - } - self.modal = None; - self.check_for_duplicate(); - } - message::DefineKey::Edit => { - if is_recovery { - if let Some(recovery_key) = self.recovery_keys.get(i) { - let modal = EditXpubModal::new( - recovery_key.name.clone(), - recovery_key.key.as_ref(), - i, - is_recovery, - self.network, - self.fingerprint_account_index_mappping(), - self.keys_aliases(), - self.signer.clone(), - ); - let cmd = modal.load(); - self.modal = Some(Box::new(modal)); - return cmd; - } - } else if let Some(spending_key) = self.spending_keys.get(i) { - let modal = EditXpubModal::new( - spending_key.name.clone(), - spending_key.key.as_ref(), - i, - is_recovery, - self.network, - self.fingerprint_account_index_mappping(), - self.keys_aliases(), - self.signer.clone(), - ); - let cmd = modal.load(); - self.modal = Some(Box::new(modal)); - return cmd; - } - } - message::DefineKey::Delete => { - if is_recovery { - self.recovery_keys.remove(i); - if self.recovery_threshold > self.recovery_keys.len() { - self.recovery_threshold -= 1; - } - } else { - self.spending_keys.remove(i); - if self.spending_threshold > self.spending_keys.len() { - self.spending_threshold -= 1; - } - } - self.check_for_duplicate(); - } - }, - _ => { - if let Some(modal) = &mut self.modal { - return modal.update(Message::DefineDescriptor(msg)); - } - } - }; + Message::DefineDescriptor(message::DefineDescriptor::AddRecoveryPath) => { + self.recovery_paths.push(RecoveryPath::new()); } + Message::DefineDescriptor(message::DefineDescriptor::PrimaryPath(msg)) => match msg { + message::DefinePath::ThresholdEdited(value) => { + self.spending_threshold = value; + } + message::DefinePath::AddKey => { + self.spending_keys.push(DescriptorKey::default()); + self.spending_threshold += 1; + } + message::DefinePath::Key(i, msg) => match msg { + message::DefineKey::Clipboard(key) => { + return Command::perform(async move { key }, Message::Clibpboard); + } + message::DefineKey::Edited(name, imported_key) => { + self.edit_alias_for_key_with_same_fingerprint( + name.clone(), + imported_key.master_fingerprint(), + ); + + if let Some(spending_key) = self.spending_keys.get_mut(i) { + spending_key.name = name; + spending_key.key = Some(imported_key); + spending_key.check_network(self.network); + } + self.modal = None; + self.check_for_duplicate(); + } + message::DefineKey::Edit => { + if let Some(spending_key) = self.spending_keys.get(i) { + let modal = EditXpubModal::new( + spending_key.name.clone(), + spending_key.key.as_ref(), + None, + i, + self.network, + self.fingerprint_account_index_mappping(), + self.keys_aliases(), + self.signer.clone(), + ); + let cmd = modal.load(); + self.modal = Some(Box::new(modal)); + return cmd; + } + } + message::DefineKey::Delete => { + self.spending_keys.remove(i); + if self.spending_threshold > self.spending_keys.len() { + self.spending_threshold -= 1; + } + self.check_for_duplicate(); + } + }, + _ => {} + }, + Message::DefineDescriptor(message::DefineDescriptor::RecoveryPath(i, msg)) => match msg + { + message::DefinePath::ThresholdEdited(value) => { + if let Some(path) = self.recovery_paths.get_mut(i) { + path.threshold = value; + } + } + message::DefinePath::SequenceEdited(seq) => { + self.modal = None; + if let Some(path) = self.recovery_paths.get_mut(i) { + path.sequence = seq; + } + } + message::DefinePath::EditSequence => { + if let Some(path) = self.recovery_paths.get(i) { + self.modal = Some(Box::new(EditSequenceModal::new(i, path.sequence))); + } + } + message::DefinePath::AddKey => { + if let Some(path) = self.recovery_paths.get_mut(i) { + path.keys.push(DescriptorKey::default()); + path.threshold += 1; + } + } + message::DefinePath::Key(j, msg) => match msg { + message::DefineKey::Clipboard(key) => { + return Command::perform(async move { key }, Message::Clibpboard); + } + message::DefineKey::Edited(name, imported_key) => { + self.edit_alias_for_key_with_same_fingerprint( + name.clone(), + imported_key.master_fingerprint(), + ); + + if let Some(key) = self + .recovery_paths + .get_mut(i) + .and_then(|path| path.keys.get_mut(j)) + { + key.name = name; + key.key = Some(imported_key); + key.check_network(self.network); + } + self.modal = None; + self.check_for_duplicate(); + } + message::DefineKey::Edit => { + if let Some(key) = + self.recovery_paths.get(i).and_then(|path| path.keys.get(j)) + { + let modal = EditXpubModal::new( + key.name.clone(), + key.key.as_ref(), + Some(i), + j, + self.network, + self.fingerprint_account_index_mappping(), + self.keys_aliases(), + self.signer.clone(), + ); + let cmd = modal.load(); + self.modal = Some(Box::new(modal)); + return cmd; + } + } + message::DefineKey::Delete => { + if let Some(path) = self.recovery_paths.get_mut(i) { + path.keys.remove(j); + if path.threshold > path.keys.len() { + path.threshold -= 1; + } + } + if self + .recovery_paths + .get(i) + .map(|path| path.keys.is_empty()) + .unwrap_or(false) + { + self.recovery_paths.remove(i); + } + self.check_for_duplicate(); + } + }, + }, _ => { if let Some(modal) = &mut self.modal { return modal.update(message); @@ -375,40 +458,45 @@ impl Step for DefineDescriptor { } } - let mut recovery_keys: Vec = Vec::new(); - for recovery_key in self.recovery_keys.iter().clone() { - if let Some(DescriptorPublicKey::XPub(xpub)) = recovery_key.key.as_ref() { - if let Some((master_fingerprint, _)) = xpub.origin { - ctx.keys.push(KeySetting { - master_fingerprint, - name: recovery_key.name.clone(), - }); - if master_fingerprint == self.signer.fingerprint() { - signer_is_used = true; + let mut recovery_paths = BTreeMap::new(); + + for path in self.recovery_paths.iter_mut() { + let mut recovery_keys: Vec = Vec::new(); + for recovery_key in path.keys.iter().clone() { + if let Some(DescriptorPublicKey::XPub(xpub)) = recovery_key.key.as_ref() { + if let Some((master_fingerprint, _)) = xpub.origin { + ctx.keys.push(KeySetting { + master_fingerprint, + name: recovery_key.name.clone(), + }); + if master_fingerprint == self.signer.fingerprint() { + signer_is_used = true; + } } + let xpub = DescriptorMultiXKey { + origin: xpub.origin.clone(), + xkey: xpub.xkey, + derivation_paths: DerivPaths::new(vec![ + DerivationPath::from_str("m/0").unwrap(), + DerivationPath::from_str("m/1").unwrap(), + ]) + .unwrap(), + wildcard: Wildcard::Unhardened, + }; + recovery_keys.push(DescriptorPublicKey::MultiXPub(xpub)); } - let xpub = DescriptorMultiXKey { - origin: xpub.origin.clone(), - xkey: xpub.xkey, - derivation_paths: DerivPaths::new(vec![ - DerivationPath::from_str("m/0").unwrap(), - DerivationPath::from_str("m/1").unwrap(), - ]) - .unwrap(), - wildcard: Wildcard::Unhardened, - }; - recovery_keys.push(DescriptorPublicKey::MultiXPub(xpub)); } + + let recovery_keys = if recovery_keys.len() == 1 { + PathInfo::Single(recovery_keys[0].clone()) + } else { + PathInfo::Multi(path.threshold, recovery_keys) + }; + + recovery_paths.insert(path.sequence, recovery_keys); } - let sequence = self.sequence.value.parse::(); - self.sequence.valid = sequence.is_ok(); - - if !self.network_valid - || !self.sequence.valid - || recovery_keys.is_empty() - || spending_keys.is_empty() - { + if !self.network_valid || spending_keys.is_empty() { return false; } @@ -418,15 +506,6 @@ impl Step for DefineDescriptor { PathInfo::Multi(self.spending_threshold, spending_keys) }; - let recovery_keys = if recovery_keys.len() == 1 { - PathInfo::Single(recovery_keys[0].clone()) - } else { - PathInfo::Multi(self.recovery_threshold, recovery_keys) - }; - - let mut recovery_paths = BTreeMap::new(); - recovery_paths.insert(sequence.unwrap(), recovery_keys); - let policy = match LianaPolicy::new(spending_keys, recovery_paths) { Ok(policy) => policy, Err(e) => { @@ -452,22 +531,22 @@ impl Step for DefineDescriptor { .enumerate() .map(|(i, key)| { key.view().map(move |msg| { - Message::DefineDescriptor(message::DefineDescriptor::Key(false, i, msg)) + Message::DefineDescriptor(message::DefineDescriptor::PrimaryPath( + message::DefinePath::Key(i, msg), + )) }) }) .collect(), - self.recovery_keys + self.spending_threshold, + self.recovery_paths .iter() .enumerate() - .map(|(i, key)| { - key.view().map(move |msg| { - Message::DefineDescriptor(message::DefineDescriptor::Key(true, i, msg)) + .map(|(i, path)| { + path.view().map(move |msg| { + Message::DefineDescriptor(message::DefineDescriptor::RecoveryPath(i, msg)) }) }) .collect(), - &self.sequence, - self.spending_threshold, - self.recovery_threshold, self.valid(), self.error.as_ref(), ); @@ -557,8 +636,69 @@ impl From for Box { } } +pub struct EditSequenceModal { + path_index: usize, + sequence: form::Value, +} + +impl EditSequenceModal { + pub fn new(path_index: usize, sequence: u16) -> Self { + Self { + path_index, + sequence: form::Value { + value: sequence.to_string(), + valid: true, + }, + } + } +} + +impl DescriptorEditModal for EditSequenceModal { + fn processing(&self) -> bool { + false + } + + fn update(&mut self, message: Message) -> Command { + if let Message::DefineDescriptor(message::DefineDescriptor::SequenceModal(msg)) = message { + match msg { + message::SequenceModal::SequenceEdited(seq) => { + if let Ok(s) = u16::from_str(&seq) { + self.sequence.valid = s != 0 + } else { + self.sequence.valid = false; + } + self.sequence.value = seq; + } + message::SequenceModal::ConfirmSequence => { + if self.sequence.valid { + if let Ok(sequence) = u16::from_str(&self.sequence.value) { + let path_index = self.path_index; + return Command::perform( + async move { (path_index, sequence) }, + |(path_index, sequence)| { + message::DefineDescriptor::RecoveryPath( + path_index, + message::DefinePath::SequenceEdited(sequence), + ) + }, + ) + .map(Message::DefineDescriptor); + } + } + } + } + } + Command::none() + } + + fn view(&self) -> Element { + view::edit_sequence_modal(&self.sequence) + } +} + pub struct EditXpubModal { - is_recovery: bool, + /// None if path is primary path + path_index: Option, key_index: usize, network: Network, error: Option, @@ -583,8 +723,8 @@ impl EditXpubModal { fn new( name: String, key: Option<&DescriptorPublicKey>, + path_index: Option, key_index: usize, - is_recovery: bool, network: Network, account_indexes: HashMap, keys_aliases: HashMap, @@ -601,7 +741,7 @@ impl EditXpubModal { }, keys_aliases, account_indexes, - is_recovery, + path_index, key_index, chosen_hw: None, processing: false, @@ -621,7 +761,7 @@ impl EditXpubModal { } } -impl DescriptorKeyModal for EditXpubModal { +impl DescriptorEditModal for EditXpubModal { fn processing(&self) -> bool { self.processing } @@ -650,8 +790,8 @@ impl DescriptorKeyModal for EditXpubModal { generate_derivation_path(self.network, account_index), ), |res| { - Message::DefineDescriptor(message::DefineDescriptor::HWXpubImported( - res, + Message::DefineDescriptor(message::DefineDescriptor::KeyModal( + message::ImportKeyModal::HWXpubImported(res), )) }, ); @@ -696,71 +836,89 @@ impl DescriptorKeyModal for EditXpubModal { self.signer.get_extended_pubkey(&derivation_path) ); } - Message::DefineDescriptor(message::DefineDescriptor::HWXpubImported(res)) => { - self.processing = false; - match res { - Ok(key) => { - if let Some(alias) = self.keys_aliases.get(&key.master_fingerprint()) { - self.form_name.valid = true; - self.form_name.value = alias.clone(); - self.edit_name = false; - } else { - self.edit_name = true; + Message::DefineDescriptor(message::DefineDescriptor::KeyModal(msg)) => match msg { + message::ImportKeyModal::HWXpubImported(res) => { + self.processing = false; + match res { + Ok(key) => { + if let Some(alias) = self.keys_aliases.get(&key.master_fingerprint()) { + self.form_name.valid = true; + self.form_name.value = alias.clone(); + self.edit_name = false; + } else { + self.edit_name = true; + } + self.chosen_signer = false; + self.form_xpub.valid = true; + self.form_xpub.value = key.to_string(); + } + Err(e) => { + self.chosen_hw = None; + self.error = Some(e); } - self.chosen_signer = false; - self.form_xpub.valid = true; - self.form_xpub.value = key.to_string(); - } - Err(e) => { - self.chosen_hw = None; - self.error = Some(e); } } - } - Message::DefineDescriptor(message::DefineDescriptor::EditName) => { - self.edit_name = true; - } - Message::DefineDescriptor(message::DefineDescriptor::NameEdited(name)) => { - self.form_name.valid = true; - self.form_name.value = name; - } - Message::DefineDescriptor(message::DefineDescriptor::XPubEdited(s)) => { - if let Ok(DescriptorPublicKey::XPub(key)) = DescriptorPublicKey::from_str(&s) { - if let Some((fingerprint, _)) = key.origin { - self.form_xpub.valid = true; - if let Some(alias) = self.keys_aliases.get(&fingerprint) { - self.form_name.valid = true; - self.form_name.value = alias.clone(); - self.edit_name = false; + message::ImportKeyModal::EditName => { + self.edit_name = true; + } + message::ImportKeyModal::NameEdited(name) => { + self.form_name.valid = true; + self.form_name.value = name; + } + message::ImportKeyModal::XPubEdited(s) => { + if let Ok(DescriptorPublicKey::XPub(key)) = DescriptorPublicKey::from_str(&s) { + if let Some((fingerprint, _)) = key.origin { + self.form_xpub.valid = true; + if let Some(alias) = self.keys_aliases.get(&fingerprint) { + self.form_name.valid = true; + self.form_name.value = alias.clone(); + self.edit_name = false; + } else { + self.edit_name = true; + } } else { - self.edit_name = true; + self.form_xpub.valid = false; } } else { self.form_xpub.valid = false; } - } else { - self.form_xpub.valid = false; + self.form_xpub.value = s; } - self.form_xpub.value = s; - } - Message::DefineDescriptor(message::DefineDescriptor::ConfirmXpub) => { - if let Ok(key) = DescriptorPublicKey::from_str(&self.form_xpub.value) { - let key_index = self.key_index; - let is_recovery = self.is_recovery; - let name = self.form_name.value.clone(); - return Command::perform( - async move { (is_recovery, key_index, key) }, - |(is_recovery, key_index, key)| { - message::DefineDescriptor::Key( - is_recovery, - key_index, - message::DefineKey::Edited(name, key), + message::ImportKeyModal::ConfirmXpub => { + if let Ok(key) = DescriptorPublicKey::from_str(&self.form_xpub.value) { + let key_index = self.key_index; + let name = self.form_name.value.clone(); + if let Some(path_index) = self.path_index { + return Command::perform( + async move { (path_index, key_index, key) }, + |(path_index, key_index, key)| { + message::DefineDescriptor::RecoveryPath( + path_index, + message::DefinePath::Key( + key_index, + message::DefineKey::Edited(name, key), + ), + ) + }, ) - }, - ) - .map(Message::DefineDescriptor); + .map(Message::DefineDescriptor); + } else { + return Command::perform( + async move { (key_index, key) }, + |(key_index, key)| { + message::DefineDescriptor::PrimaryPath( + message::DefinePath::Key( + key_index, + message::DefineKey::Edited(name, key), + ), + ) + }, + ) + .map(Message::DefineDescriptor); + } + } } - } + }, _ => {} }; Command::none() @@ -1321,22 +1479,25 @@ mod tests { // Edit primary key sandbox - .update(Message::DefineDescriptor(message::DefineDescriptor::Key( - false, - 0, - message::DefineKey::Edit, - ))) + .update(Message::DefineDescriptor( + message::DefineDescriptor::PrimaryPath(message::DefinePath::Key( + 0, + message::DefineKey::Edit, + )), + )) .await; sandbox.check(|step| assert!(step.modal.is_some())); sandbox.update(Message::UseHotSigner).await; sandbox .update(Message::DefineDescriptor( - message::DefineDescriptor::NameEdited("hot signer key".to_string()), + message::DefineDescriptor::KeyModal(message::ImportKeyModal::NameEdited( + "hot signer key".to_string(), + )), )) .await; sandbox .update(Message::DefineDescriptor( - message::DefineDescriptor::ConfirmXpub, + message::DefineDescriptor::KeyModal(message::ImportKeyModal::ConfirmXpub), )) .await; sandbox.check(|step| assert!(step.modal.is_none())); @@ -1344,30 +1505,38 @@ mod tests { // Edit sequence sandbox .update(Message::DefineDescriptor( - message::DefineDescriptor::SequenceEdited("1000".to_string()), + message::DefineDescriptor::RecoveryPath( + 0, + message::DefinePath::SequenceEdited(1000), + ), )) .await; // Edit recovery key sandbox - .update(Message::DefineDescriptor(message::DefineDescriptor::Key( - true, - 0, - message::DefineKey::Edit, - ))) + .update(Message::DefineDescriptor( + message::DefineDescriptor::RecoveryPath( + 0, + message::DefinePath::Key(0, message::DefineKey::Edit), + ), + )) .await; sandbox.check(|step| assert!(step.modal.is_some())); sandbox.update(Message::DefineDescriptor( - message::DefineDescriptor::XPubEdited("[f5acc2fd/48'/1'/0'/2']tpubDFAqEGNyad35aBCKUAXbQGDjdVhNueno5ZZVEn3sQbW5ci457gLR7HyTmHBg93oourBssgUxuWz1jX5uhc1qaqFo9VsybY1J5FuedLfm4dK".to_string()), + message::DefineDescriptor::KeyModal( + message::ImportKeyModal::XPubEdited("[f5acc2fd/48'/1'/0'/2']tpubDFAqEGNyad35aBCKUAXbQGDjdVhNueno5ZZVEn3sQbW5ci457gLR7HyTmHBg93oourBssgUxuWz1jX5uhc1qaqFo9VsybY1J5FuedLfm4dK".to_string()), + ) )).await; sandbox .update(Message::DefineDescriptor( - message::DefineDescriptor::NameEdited("external recovery key".to_string()), + message::DefineDescriptor::KeyModal(message::ImportKeyModal::NameEdited( + "External recovery key".to_string(), + )), )) .await; sandbox .update(Message::DefineDescriptor( - message::DefineDescriptor::ConfirmXpub, + message::DefineDescriptor::KeyModal(message::ImportKeyModal::ConfirmXpub), )) .await; sandbox.check(|step| { diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index ba6ab336..3a98152d 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -1,9 +1,9 @@ use iced::widget::{ - checkbox, container, pick_list, scrollable, scrollable::Properties, Space, TextInput, + checkbox, container, pick_list, scrollable, scrollable::Properties, slider, Space, TextInput, }; use iced::{alignment, Alignment, Length}; -use std::collections::HashSet; +use std::{collections::HashSet, str::FromStr}; use liana::miniscript::bitcoin; use liana_ui::{ @@ -142,10 +142,8 @@ pub fn define_descriptor<'a>( network: bitcoin::Network, network_valid: bool, spending_keys: Vec>, - recovery_keys: Vec>, - sequence: &form::Value, spending_threshold: usize, - recovery_threshold: usize, + recovery_paths: Vec>, valid: bool, error: Option<&String>, ) -> Element<'a, Message> { @@ -178,151 +176,58 @@ pub fn define_descriptor<'a>( .push( Row::new() .spacing(10) - .push(Space::with_width(Length::Units(40))) + .push(Space::with_width(Length::Units(5))) .push(text("Primary path:").bold()) - .push(tooltip(prompt::DEFINE_DESCRIPTOR_PRIMATRY_PATH_TOOLTIP)), + .push(tooltip(prompt::DEFINE_DESCRIPTOR_PRIMARY_PATH_TOOLTIP)), ) - .push(separation().width(Length::Fill)) - .push( - Container::new( - Row::new() - .align_items(Alignment::Center) - .push_maybe(if spending_keys.len() > 1 { - Some(threshsold_input::threshsold_input( - spending_threshold, - spending_keys.len(), - |value| { - Message::DefineDescriptor( - message::DefineDescriptor::ThresholdEdited(false, value), - ) - }, - )) - } else { - None - }) - .push( - scrollable( - Row::new() - .spacing(5) - .align_items(Alignment::Center) - .push(Row::with_children(spending_keys).spacing(5)) - .push( - Button::new( - Container::new(icon::plus_icon().size(50)) - .width(Length::Units(200)) - .height(Length::Units(200)) - .align_y(alignment::Vertical::Center) - .align_x(alignment::Horizontal::Center), - ) - .width(Length::Units(200)) - .height(Length::Units(200)) - .style(theme::Button::TransparentBorder) - .on_press( - Message::DefineDescriptor( - message::DefineDescriptor::AddKey(false), - ), - ), - ) - .padding(5), - ) - .horizontal_scroll(Properties::new().width(3).scroller_width(3)), - ), - ) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center), - ) - .spacing(10); - - let col_recovery_keys = Column::new() - .push( + .push(Container::new( Row::new() - .push(Space::with_width(Length::Units(50))) - .push(text("Recovery path:").bold()), - ) - .push(separation().width(Length::Fill)) - .push( - Container::new( - Row::new() - .align_items(Alignment::Center) - .push_maybe(if recovery_keys.len() > 1 { - Some(threshsold_input::threshsold_input( - recovery_threshold, - recovery_keys.len(), - |value| { - Message::DefineDescriptor( - message::DefineDescriptor::ThresholdEdited(true, value), + .align_items(Alignment::Center) + .push_maybe(if spending_keys.len() > 1 { + Some(threshsold_input::threshsold_input( + spending_threshold, + spending_keys.len(), + |value| { + Message::DefineDescriptor(message::DefineDescriptor::PrimaryPath( + message::DefinePath::ThresholdEdited(value), + )) + }, + )) + } else { + None + }) + .push( + scrollable( + Row::new() + .spacing(5) + .align_items(Alignment::Center) + .push(Row::with_children(spending_keys).spacing(5)) + .push( + Button::new( + Container::new(icon::plus_icon().size(50)) + .width(Length::Units(150)) + .height(Length::Units(150)) + .align_y(alignment::Vertical::Center) + .align_x(alignment::Horizontal::Center), ) - }, - )) - } else { - None - }) - .push( - scrollable( - Row::new() - .spacing(5) - .align_items(Alignment::Center) - .push(Row::with_children(recovery_keys).spacing(5)) - .push( - Button::new( - Container::new(icon::plus_icon().size(50)) - .width(Length::Units(200)) - .height(Length::Units(200)) - .align_y(alignment::Vertical::Center) - .align_x(alignment::Horizontal::Center), - ) - .width(Length::Units(200)) - .height(Length::Units(200)) - .style(theme::Button::TransparentBorder) - .on_press( - Message::DefineDescriptor( - message::DefineDescriptor::AddKey(true), + .width(Length::Units(150)) + .height(Length::Units(150)) + .style(theme::Button::TransparentBorder) + .on_press( + Message::DefineDescriptor( + message::DefineDescriptor::PrimaryPath( + message::DefinePath::AddKey, ), ), - ) - .padding(5), - ) - .horizontal_scroll(Properties::new().width(3).scroller_width(3)), - ), - ) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center), - ) + ), + ) + .padding(5), + ) + .horizontal_scroll(Properties::new().width(3).scroller_width(3)), + ), + )) .spacing(10); - let col_sequence = Container::new( - Row::new() - .spacing(50) - .align_items(Alignment::Center) - .push(Container::new(icon::arrow_down().size(50)).align_x(alignment::Horizontal::Right)) - .push( - Column::new() - .push( - Row::new() - .spacing(10) - .push(text("Blocks before recovery:").bold()) - .push(tooltip(prompt::DEFINE_DESCRIPTOR_SEQUENCE_TOOLTIP)), - ) - .push( - Container::new( - form::Form::new("Number of blocks", sequence, |msg| { - Message::DefineDescriptor( - message::DefineDescriptor::SequenceEdited(msg), - ) - }) - .warning("Please enter correct block number") - .size(20) - .padding(10), - ) - .width(Length::Units(150)), - ) - .spacing(10), - ) - .padding(20), - ) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center); - layout( progress, Column::new() @@ -330,19 +235,38 @@ pub fn define_descriptor<'a>( .push(text("Create the wallet").bold().size(50)) .push( Column::new() + .width(Length::Fill) + .align_items(Alignment::Center) .push(row_network) - .push(col_spending_keys) - .push(col_sequence) - .push(col_recovery_keys) + .push( + Column::new() + .spacing(25) + .push(col_spending_keys) + .push( + Row::new() + .spacing(10) + .push(Space::with_width(Length::Units(5))) + .push(text("Recovery paths:").bold()) + .push(tooltip(prompt::DEFINE_DESCRIPTOR_RECOVERY_PATH_TOOLTIP)), + ) + .push(Column::with_children(recovery_paths).spacing(10)), + ) .spacing(25), ) - .push(if !valid { - button::primary(None, "Next").width(Length::Units(200)) - } else { - button::primary(None, "Next") - .width(Length::Units(200)) - .on_press(Message::Next) - }) + .push( + Row::new() + .spacing(10) + .push(button::border(None, "Add a recovery path").on_press( + Message::DefineDescriptor(message::DefineDescriptor::AddRecoveryPath), + )) + .push(if !valid { + button::primary(None, "Next").width(Length::Units(200)) + } else { + button::primary(None, "Next") + .width(Length::Units(200)) + .on_press(Message::Next) + }), + ) .push_maybe(error.map(|e| card::error("Failed to create descriptor", e.to_string()))) .push(Space::with_height(Length::Units(20))) .width(Length::Fill) @@ -352,6 +276,54 @@ pub fn define_descriptor<'a>( ) } +pub fn recovery_path_view( + sequence: u16, + recovery_threshold: usize, + recovery_keys: Vec>, +) -> Element { + Container::new( + Column::new().push(defined_sequence(sequence)).push( + Row::new() + .align_items(Alignment::Center) + .push_maybe(if recovery_keys.len() > 1 { + Some(threshsold_input::threshsold_input( + recovery_threshold, + recovery_keys.len(), + message::DefinePath::ThresholdEdited, + )) + } else { + None + }) + .push( + scrollable( + Row::new() + .spacing(5) + .align_items(Alignment::Center) + .push(Row::with_children(recovery_keys).spacing(5)) + .push( + Button::new( + Container::new(icon::plus_icon().size(50)) + .width(Length::Units(150)) + .height(Length::Units(150)) + .align_y(alignment::Vertical::Center) + .align_x(alignment::Horizontal::Center), + ) + .width(Length::Units(150)) + .height(Length::Units(150)) + .style(theme::Button::TransparentBorder) + .on_press(message::DefinePath::AddKey), + ) + .padding(5), + ) + .horizontal_scroll(Properties::new().width(3).scroller_width(3)), + ), + ), + ) + .padding(5) + .style(theme::Container::Card(theme::Card::Border)) + .into() +} + pub fn import_descriptor<'a>( progress: (usize, usize), change_network: bool, @@ -1058,6 +1030,51 @@ pub fn install<'a>( ) } +pub fn defined_sequence<'a>(sequence: u16) -> Element<'a, message::DefinePath> { + let (n_years, n_months, n_days, n_hours, n_minutes) = duration_from_sequence(sequence); + Container::new( + Row::new() + .width(Length::Fill) + .align_items(Alignment::Center) + .push( + Container::new( + Column::new() + .spacing(5) + .push(text(format!("Available after {} blocks", sequence)).bold()) + .push( + [ + (n_years, "y"), + (n_months, "m"), + (n_days, "d"), + (n_hours, "h"), + (n_minutes, "mn"), + ] + .iter() + .fold( + Row::new().spacing(5), + |row, (n, unit)| { + row.push_maybe(if *n > 0 { + Some(text(format!("{}{}", n, unit,))) + } else { + None + }) + }, + ), + ), + ) + .padding(5) + .align_y(alignment::Vertical::Center), + ) + .push( + button::border(Some(icon::pencil_icon()), "Edit") + .on_press(message::DefinePath::EditSequence), + ) + .spacing(15), + ) + .padding(5) + .into() +} + pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> { card::simple( Column::new() @@ -1079,18 +1096,10 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> { .spacing(15) .align_items(Alignment::Center) .push( - scrollable( - icon::key_icon() - .style(color::DARK_GREY) - .size(50) - .width(Length::Units(50)), - ) - .horizontal_scroll(Properties::new().width(2).scroller_width(2)), - ) - .push( - icon::circle_check_icon() - .style(color::legacy::FOREGROUND) - .size(50), + icon::key_icon() + .style(color::DARK_GREY) + .size(30) + .width(Length::Units(50)), ), ) .height(Length::Fill) @@ -1102,8 +1111,8 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> { .push(Space::with_height(Length::Units(5))), ) .padding(5) - .height(Length::Units(200)) - .width(Length::Units(200)) + .height(Length::Units(150)) + .width(Length::Units(150)) .into() } @@ -1133,7 +1142,7 @@ pub fn defined_descriptor_key( .push( Container::new( Column::new() - .spacing(15) + .spacing(5) .align_items(Alignment::Center) .push( scrollable(text(name).bold()).horizontal_scroll( @@ -1143,7 +1152,7 @@ pub fn defined_descriptor_key( .push( icon::circle_check_icon() .style(color::legacy::SUCCESS) - .size(40) + .size(20) .width(Length::Units(50)), ), ) @@ -1161,8 +1170,8 @@ pub fn defined_descriptor_key( .push( card::invalid(col) .padding(5) - .height(Length::Units(200)) - .width(Length::Units(200)), + .height(Length::Units(150)) + .width(Length::Units(150)), ) .push( text("Key is for a different network") @@ -1176,8 +1185,8 @@ pub fn defined_descriptor_key( .push( card::invalid(col) .padding(5) - .height(Length::Units(200)) - .width(Length::Units(200)), + .height(Length::Units(150)) + .width(Length::Units(150)), ) .push(text("Duplicate key").small().style(color::legacy::ALERT)) .into() @@ -1187,16 +1196,16 @@ pub fn defined_descriptor_key( .push( card::invalid(col) .padding(5) - .height(Length::Units(200)) - .width(Length::Units(200)), + .height(Length::Units(150)) + .width(Length::Units(150)), ) .push(text("Duplicate name").small().style(color::legacy::ALERT)) .into() } else { card::simple(col) .padding(5) - .height(Length::Units(200)) - .width(Length::Units(200)) + .height(Length::Units(150)) + .width(Length::Units(150)) .into() } } @@ -1286,7 +1295,7 @@ pub fn edit_key_modal<'a>( .push( form::Form::new("Extended public key", form_xpub, |msg| { Message::DefineDescriptor( - message::DefineDescriptor::XPubEdited(msg), + message::DefineDescriptor::KeyModal(message::ImportKeyModal::XPubEdited(msg)), ) }) .warning(if network == bitcoin::Network::Bitcoin { @@ -1320,7 +1329,9 @@ pub fn edit_key_modal<'a>( .push(text(&form_name.value)), ) .push(button::border(Some(icon::pencil_icon()), "Edit").on_press( - Message::DefineDescriptor(message::DefineDescriptor::EditName), + Message::DefineDescriptor( + message::DefineDescriptor::KeyModal(message::ImportKeyModal::EditName), + ) )), ) } else if !form_xpub.value.is_empty() && form_xpub.valid { @@ -1335,8 +1346,8 @@ pub fn edit_key_modal<'a>( .push( form::Form::new("Alias", form_name, |msg| { Message::DefineDescriptor( - message::DefineDescriptor::NameEdited(msg), - ) + message::DefineDescriptor::KeyModal(message::ImportKeyModal::NameEdited(msg)), + ) }) .warning("Please enter correct alias") .size(20) @@ -1350,9 +1361,11 @@ pub fn edit_key_modal<'a>( if form_xpub.valid && !form_xpub.value.is_empty() && !form_name.value.is_empty() { button::primary(None, "Apply") - .on_press(Message::DefineDescriptor( - message::DefineDescriptor::ConfirmXpub, - )) + .on_press( + Message::DefineDescriptor( + message::DefineDescriptor::KeyModal(message::ImportKeyModal::ConfirmXpub), + ) + ) .width(Length::Units(200)) } else { button::primary(None, "Apply").width(Length::Units(100)) @@ -1364,6 +1377,92 @@ pub fn edit_key_modal<'a>( .into() } +/// returns y,m,d,h,m +fn duration_from_sequence(sequence: u16) -> (u32, u32, u32, u32, u32) { + let mut n_minutes = sequence as u32 * 10; + let n_years = n_minutes / 525960; + n_minutes -= n_years * 525960; + let n_months = n_minutes / 43830; + n_minutes -= n_months * 43830; + let n_days = n_minutes / 1440; + n_minutes -= n_days * 1440; + let n_hours = n_minutes / 60; + n_minutes -= n_hours * 60; + + (n_years, n_months, n_days, n_hours, n_minutes) +} + +pub fn edit_sequence_modal<'a>(sequence: &form::Value) -> Element<'a, Message> { + let mut col = Column::new() + .width(Length::Fill) + .spacing(20) + .align_items(Alignment::Center) + .push(text("Activate recovery path after:")) + .push( + Row::new() + .push( + Container::new( + form::Form::new("ex: 1000", sequence, |v| { + Message::DefineDescriptor(message::DefineDescriptor::SequenceModal( + message::SequenceModal::SequenceEdited(v), + )) + }) + .warning("Sequence must be superior to 0 and inferior to 65535"), + ) + .width(Length::Units(200)), + ) + .spacing(10) + .push(text("blocks").bold()), + ); + + if sequence.valid { + if let Ok(sequence) = u16::from_str(&sequence.value) { + let (n_years, n_months, n_days, n_hours, n_minutes) = duration_from_sequence(sequence); + col = col + .push( + [ + (n_years, "year"), + (n_months, "month"), + (n_days, "day"), + (n_hours, "hour"), + (n_minutes, "minute"), + ] + .iter() + .fold(Row::new().spacing(5), |row, (n, unit)| { + row.push_maybe(if *n > 0 { + Some( + text(format!("{} {}{}", n, unit, if *n > 1 { "s" } else { "" })) + .bold(), + ) + } else { + None + }) + }), + ) + .push( + Container::new(slider(1..=u16::MAX, sequence, |v| { + Message::DefineDescriptor(message::DefineDescriptor::SequenceModal( + message::SequenceModal::SequenceEdited(v.to_string()), + )) + })) + .width(Length::Units(500)), + ); + } + } + + card::simple(col.push(if sequence.valid { + button::primary(None, "Apply") + .on_press(Message::DefineDescriptor( + message::DefineDescriptor::SequenceModal(message::SequenceModal::ConfirmSequence), + )) + .width(Length::Units(200)) + } else { + button::primary(None, "Apply").width(Length::Units(200)) + })) + .width(Length::Units(800)) + .into() +} + fn hw_list_view( i: usize, hw: &HardwareWallet, @@ -1691,16 +1790,14 @@ mod threshsold_input { }; Column::new() - .height(Length::Units(200)) - .width(Length::Units(100)) - .push(button(icon::up_icon().size(40), Event::IncrementPressed)) + .width(Length::Units(150)) + .push(button(icon::up_icon().size(30), Event::IncrementPressed)) .push(text("Threshold:").small().bold()) .push( - Container::new(text(format!("{}/{}", self.value, self.max)).size(50)) - .height(Length::Fill) + Container::new(text(format!("{}/{}", self.value, self.max)).size(30)) .align_y(alignment::Vertical::Center), ) - .push(button(icon::down_icon().size(40), Event::DecrementPressed)) + .push(button(icon::down_icon().size(30), Event::DecrementPressed)) .align_items(Alignment::Center) .into() } diff --git a/gui/ui/src/icon.rs b/gui/ui/src/icon.rs index d71cb4c0..b5590c7e 100644 --- a/gui/ui/src/icon.rs +++ b/gui/ui/src/icon.rs @@ -18,6 +18,14 @@ pub fn arrow_down() -> Text<'static> { icon('\u{F128}') } +pub fn arrow_right() -> Text<'static> { + icon('\u{F138}') +} + +pub fn arrow_return_right() -> Text<'static> { + icon('\u{F132}') +} + pub fn chevron_right() -> Text<'static> { icon('\u{F285}') } diff --git a/gui/ui/src/theme.rs b/gui/ui/src/theme.rs index fbeabace..c58f084e 100644 --- a/gui/ui/src/theme.rs +++ b/gui/ui/src/theme.rs @@ -1,7 +1,8 @@ use iced::{ application, widget::{ - button, checkbox, container, pick_list, progress_bar, radio, scrollable, text, text_input, + button, checkbox, container, pick_list, progress_bar, radio, scrollable, slider, text, + text_input, }, }; @@ -210,6 +211,7 @@ impl From for Container { pub enum Card { #[default] Simple, + Border, Invalid, Warning, Error, @@ -223,6 +225,13 @@ impl Card { background: color::GREY.into(), ..container::Appearance::default() }, + Card::Border => container::Appearance { + background: iced::Color::TRANSPARENT.into(), + border_radius: 10.0, + border_color: color::GREY, + border_width: 1.0, + ..container::Appearance::default() + }, Card::Invalid => container::Appearance { background: color::GREY.into(), text_color: color::BLACK.into(), @@ -248,6 +257,13 @@ impl Card { background: color::LIGHT_BLACK.into(), ..container::Appearance::default() }, + Card::Border => container::Appearance { + background: iced::Color::TRANSPARENT.into(), + border_radius: 10.0, + border_color: color::LIGHT_GREY, + border_width: 1.0, + ..container::Appearance::default() + }, Card::Invalid => container::Appearance { background: color::LIGHT_BLACK.into(), text_color: color::BLACK.into(), @@ -276,6 +292,13 @@ impl Card { border_width: 1.0, ..container::Appearance::default() }, + Card::Border => container::Appearance { + background: iced::Color::TRANSPARENT.into(), + border_radius: 10.0, + border_color: color::legacy::BORDER_GREY, + border_width: 1.0, + ..container::Appearance::default() + }, Card::Invalid => container::Appearance { background: color::legacy::FOREGROUND.into(), text_color: iced::Color::BLACK.into(), @@ -791,3 +814,58 @@ impl progress_bar::StyleSheet for Theme { } } } + +#[derive(Debug, Copy, Clone, Default)] +pub enum Slider { + #[default] + Simple, +} + +impl slider::StyleSheet for Theme { + type Style = Slider; + fn active(&self, _style: &Self::Style) -> slider::Appearance { + let handle = slider::Handle { + shape: slider::HandleShape::Rectangle { + width: 8, + border_radius: 4.0, + }, + color: color::legacy::FOREGROUND, + border_color: color::GREEN, + border_width: 1.0, + }; + slider::Appearance { + rail_colors: (color::GREEN, iced::Color::TRANSPARENT), + handle, + } + } + fn hovered(&self, _style: &Self::Style) -> slider::Appearance { + let handle = slider::Handle { + shape: slider::HandleShape::Rectangle { + width: 8, + border_radius: 4.0, + }, + color: color::GREEN, + border_color: color::GREEN, + border_width: 1.0, + }; + slider::Appearance { + rail_colors: (color::GREEN, iced::Color::TRANSPARENT), + handle, + } + } + fn dragging(&self, _style: &Self::Style) -> slider::Appearance { + let handle = slider::Handle { + shape: slider::HandleShape::Rectangle { + width: 8, + border_radius: 4.0, + }, + color: color::GREEN, + border_color: color::GREEN, + border_width: 1.0, + }; + slider::Appearance { + rail_colors: (color::GREEN, iced::Color::TRANSPARENT), + handle, + } + } +} From a42eb6d36a3501766dfdc981ea2346aa0c8394e8 Mon Sep 17 00:00:00 2001 From: edouard Date: Fri, 31 Mar 2023 11:52:24 +0200 Subject: [PATCH 3/4] gui: change wording coins view --- gui/src/app/view/coins.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/src/app/view/coins.rs b/gui/src/app/view/coins.rs index 5a62548b..2eee7199 100644 --- a/gui/src/app/view/coins.rs +++ b/gui/src/app/view/coins.rs @@ -140,14 +140,14 @@ fn coin_list_view( if let Some(b) = coin.block_height { if blockheight > b as u32 + timelock as u32 { Some(Container::new( - text("The recovery path is available") + text("One of the recovery path is available") .bold() .small() .style(color::legacy::ALERT), )) } else { Some(Container::new( - text(format!("The recovery path will be available in {} blocks", b as u32 + timelock as u32 - blockheight)) + text(format!("One of the recovery path will be available in {} blocks", b as u32 + timelock as u32 - blockheight)) .bold() .small(), )) From ce23bcf498d2284ed389e7b229e63aeaa0c96e91 Mon Sep 17 00:00:00 2001 From: edouard Date: Fri, 31 Mar 2023 15:01:25 +0200 Subject: [PATCH 4/4] gui: add path selection to recovery panel --- gui/src/app/mod.rs | 3 +- gui/src/app/state/recovery.rs | 120 ++++++++++++++++++++----------- gui/src/app/view/message.rs | 1 + gui/src/app/view/recovery.rs | 130 +++++++++++++++++++++++++++------- gui/src/daemon/client/mod.rs | 9 ++- gui/src/daemon/embedded.rs | 9 ++- gui/src/daemon/mod.rs | 7 +- 7 files changed, 207 insertions(+), 72 deletions(-) diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index c02a4c55..4e0be44f 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -77,8 +77,7 @@ impl App { menu::Menu::Recovery => RecoveryPanel::new( self.wallet.clone(), &self.cache.coins, - self.wallet.main_descriptor.first_timelock_value(), - self.cache.blockheight as u32, + self.cache.blockheight, ) .into(), menu::Menu::Receive => ReceivePanel::default().into(), diff --git a/gui/src/app/state/recovery.rs b/gui/src/app/state/recovery.rs index f2be2064..d22f4456 100644 --- a/gui/src/app/state/recovery.rs +++ b/gui/src/app/state/recovery.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use iced::Command; +use liana::miniscript::bitcoin::util::bip32::{DerivationPath, Fingerprint}; use liana_ui::{component::form, widget::Element}; use crate::{ @@ -26,41 +27,24 @@ use liana::miniscript::bitcoin::{Address, Amount}; pub struct RecoveryPanel { wallet: Arc, - locked_coins: (usize, Amount), - recoverable_coins: (usize, Amount), + recovery_paths: Vec, + selected_path: Option, warning: Option, feerate: form::Value, recipient: form::Value, generated: Option, - /// timelock value to pass for the heir to consume a coin. - timelock: u16, } impl RecoveryPanel { - pub fn new(wallet: Arc, coins: &[Coin], timelock: u16, blockheight: u32) -> Self { - let mut locked_coins = (0, Amount::from_sat(0)); - let mut recoverable_coins = (0, Amount::from_sat(0)); - for coin in coins { - if coin.spend_info.is_none() { - // recoverable coins are coins that can be recoverable next block. - if remaining_sequence(coin, blockheight, timelock) > 1 { - locked_coins.0 += 1; - locked_coins.1 += coin.amount; - } else { - recoverable_coins.0 += 1; - recoverable_coins.1 += coin.amount; - } - } - } + pub fn new(wallet: Arc, coins: &[Coin], blockheight: i32) -> Self { Self { + recovery_paths: recovery_paths(&wallet, coins, blockheight), wallet, - locked_coins, - recoverable_coins, + selected_path: None, warning: None, feerate: form::Value::default(), recipient: form::Value::default(), generated: None, - timelock, } } } @@ -74,8 +58,26 @@ impl State for RecoveryPanel { false, self.warning.as_ref(), view::recovery::recovery( - &self.locked_coins, - &self.recoverable_coins, + self.recovery_paths + .iter() + .enumerate() + .filter_map(|(i, path)| { + if path.number_of_coins > 0 { + Some(view::recovery::recovery_path_view( + i, + path.threshold, + &path.origins, + path.total_amount, + path.number_of_coins, + &self.wallet.keys_aliases, + self.selected_path == Some(i), + )) + } else { + None + } + }) + .collect(), + self.selected_path, &self.feerate, &self.recipient, ), @@ -95,22 +97,7 @@ impl State for RecoveryPanel { Err(e) => self.warning = Some(e), Ok(coins) => { self.warning = None; - self.locked_coins = (0, Amount::from_sat(0)); - self.recoverable_coins = (0, Amount::from_sat(0)); - for coin in coins { - if coin.spend_info.is_none() { - // recoverable coins are coins that can be recoverable next block. - if remaining_sequence(&coin, cache.blockheight as u32, self.timelock) - > 1 - { - self.locked_coins.0 += 1; - self.locked_coins.1 += coin.amount; - } else { - self.recoverable_coins.0 += 1; - self.recoverable_coins.1 += coin.amount; - } - } - } + self.recovery_paths = recovery_paths(&self.wallet, &coins, cache.blockheight); } }, Message::Recovery(res) => match res { @@ -134,6 +121,13 @@ impl State for RecoveryPanel { self.recipient.valid = false; } } + view::Message::CreateSpend(view::CreateSpendMessage::SelectPath(index)) => { + if Some(index) == self.selected_path { + self.selected_path = None; + } else { + self.selected_path = Some(index); + } + } view::Message::CreateSpend(view::CreateSpendMessage::FeerateEdited(feerate)) => { self.feerate.value = feerate; self.feerate.valid = @@ -144,9 +138,13 @@ impl State for RecoveryPanel { let feerate_vb = self.feerate.value.parse::().expect("Checked before"); self.warning = None; let desc = self.wallet.main_descriptor.clone(); + let sequence = self + .recovery_paths + .get(self.selected_path.expect("A path must be selected")) + .map(|p| p.sequence); return Command::perform( async move { - let psbt = daemon.create_recovery(address, feerate_vb)?; + let psbt = daemon.create_recovery(address, feerate_vb, sequence)?; let coins = daemon.list_coins().map(|res| res.coins)?; let coins = coins .iter() @@ -198,3 +196,43 @@ impl From for Box { Box::new(s) } } + +pub struct RecoveryPath { + threshold: usize, + sequence: u16, + origins: Vec<(Fingerprint, DerivationPath)>, + total_amount: Amount, + number_of_coins: usize, +} + +fn recovery_paths(wallet: &Wallet, coins: &[Coin], blockheight: i32) -> Vec { + wallet + .main_descriptor + .policy() + .recovery_paths() + .iter() + .map(|(&sequence, path)| { + let (number_of_coins, total_amount) = coins + .iter() + .filter(|coin| { + coin.spend_info.is_none() + && remaining_sequence(coin, blockheight as u32, sequence) <= 1 + }) + .fold( + (0, Amount::from_sat(0)), + |(number_of_coins, total_amount), coin| { + (number_of_coins + 1, total_amount + coin.amount) + }, + ); + + let (threshold, origins) = path.thresh_origins(); + RecoveryPath { + total_amount, + number_of_coins, + sequence, + threshold, + origins: origins.into_iter().collect(), + } + }) + .collect() +} diff --git a/gui/src/app/view/message.rs b/gui/src/app/view/message.rs index e636d723..0c589f58 100644 --- a/gui/src/app/view/message.rs +++ b/gui/src/app/view/message.rs @@ -24,6 +24,7 @@ pub enum CreateSpendMessage { SelectCoin(usize), RecipientEdited(usize, &'static str, String), FeerateEdited(String), + SelectPath(usize), Generate, } diff --git a/gui/src/app/view/recovery.rs b/gui/src/app/view/recovery.rs index b03e40e5..3129a70b 100644 --- a/gui/src/app/view/recovery.rs +++ b/gui/src/app/view/recovery.rs @@ -1,20 +1,30 @@ -use iced::{widget::Space, Alignment, Length}; +use std::collections::HashMap; -use liana::miniscript::bitcoin::Amount; +use iced::{ + widget::{tooltip, Space}, + Alignment, Length, +}; + +use liana::miniscript::bitcoin::{ + util::bip32::{DerivationPath, Fingerprint}, + Amount, +}; use liana_ui::{ component::{button, form, text::*}, - icon, - util::Collection, + icon, theme, widget::*, }; -use crate::app::view::message::{CreateSpendMessage, Message}; +use crate::app::view::{ + message::{CreateSpendMessage, Message}, + util::amount, +}; #[allow(clippy::too_many_arguments)] pub fn recovery<'a>( - locked_coins: &(usize, Amount), - recoverable_coins: &(usize, Amount), + recovery_paths: Vec>, + selected_path: Option, feerate: &form::Value, address: &'a form::Value, ) -> Element<'a, Message> { @@ -30,23 +40,17 @@ pub fn recovery<'a>( .spacing(1), ) .push( - Container::new(Row::new().push(text(format!( - "{} ({} coins) will be spendable through the recovery path in the next block", - recoverable_coins.1, recoverable_coins.0 - )))) - .center_x(), - ) - .push_maybe(if *locked_coins != (0, Amount::from_sat(0)) { - Some( - Container::new(Row::new().push(text(format!( - "{} ({} coins) are not yet spendable through the recovery path", - locked_coins.1, locked_coins.0 - )))) - .center_x(), + Container::new( + Column::new() + .spacing(10) + .push(text(format!( + "{} recovery paths are available or will be available next block, select one:", + recovery_paths.len() + ))) + .push(Column::with_children(recovery_paths).spacing(10)), ) - } else { - None - }) + .padding(20), + ) .push(Space::with_height(Length::Units(20))) .push( Column::new() @@ -80,7 +84,7 @@ pub fn recovery<'a>( && !feerate.value.is_empty() && address.valid && !address.value.is_empty() - && recoverable_coins.0 != 0 + && selected_path.is_some() { button::primary(None, "Next") .on_press(Message::Next) @@ -96,3 +100,81 @@ pub fn recovery<'a>( .spacing(20) .into() } + +pub fn recovery_path_view<'a>( + index: usize, + threshold: usize, + origins: &'a [(Fingerprint, DerivationPath)], + total_amount: Amount, + number_of_coins: usize, + key_aliases: &'a HashMap, + selected: bool, +) -> Element<'a, Message> { + Container::new( + Button::new( + Row::new() + .push(if selected { + icon::square_check_icon() + } else { + icon::square_icon() + }) + .push( + Column::new() + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push( + text(format!( + "{} signature{} from", + threshold, + if threshold > 1 { "s" } else { "" } + )) + .bold(), + ) + .push(origins.iter().fold( + Row::new().align_items(Alignment::Center).spacing(5), + |row, (fg, _)| { + row.push(if let Some(alias) = key_aliases.get(fg) { + Container::new( + tooltip::Tooltip::new( + Container::new(text(alias)).padding(3).style( + theme::Container::Pill(theme::Pill::Simple), + ), + fg.to_string(), + tooltip::Position::Bottom, + ) + .style(theme::Container::Card(theme::Card::Simple)), + ) + } else { + Container::new(text(fg.to_string())) + .padding(3) + .style(theme::Container::Pill(theme::Pill::Simple)) + }) + }, + )), + ) + .push( + Row::new() + .spacing(5) + .push(text("can recover")) + .push(text(format!( + "{} coin{} totalling", + number_of_coins, + if number_of_coins > 0 { "s" } else { "" } + ))) + .push(amount(&total_amount)), + ), + ) + .align_items(Alignment::Center) + .spacing(20), + ) + .padding(10) + .width(Length::Fill) + .on_press(Message::CreateSpend(CreateSpendMessage::SelectPath(index))) + .style(theme::Button::TransparentBorder), + ) + .style(theme::Container::Card(theme::Card::Simple)) + .width(Length::Fill) + .into() +} diff --git a/gui/src/daemon/client/mod.rs b/gui/src/daemon/client/mod.rs index 4f27777c..24342417 100644 --- a/gui/src/daemon/client/mod.rs +++ b/gui/src/daemon/client/mod.rs @@ -134,10 +134,15 @@ impl Daemon for Lianad { self.call("listtransactions", Some(vec![txids])) } - fn create_recovery(&self, address: Address, feerate_vb: u64) -> Result { + fn create_recovery( + &self, + address: Address, + feerate_vb: u64, + sequence: Option, + ) -> Result { let res: CreateSpendResult = self.call( "createrecovery", - Some(vec![json!(address), json!(feerate_vb)]), + Some(vec![json!(address), json!(feerate_vb), json!(sequence)]), )?; Ok(res.psbt) } diff --git a/gui/src/daemon/embedded.rs b/gui/src/daemon/embedded.rs index 973c71f7..c01f4ac0 100644 --- a/gui/src/daemon/embedded.rs +++ b/gui/src/daemon/embedded.rs @@ -194,14 +194,19 @@ impl Daemon for EmbeddedDaemon { .map_err(|e| DaemonError::Unexpected(e.to_string())) } - fn create_recovery(&self, address: Address, feerate_vb: u64) -> Result { + fn create_recovery( + &self, + address: Address, + feerate_vb: u64, + sequence: Option, + ) -> Result { self.handle .as_ref() .ok_or(DaemonError::NoAnswer)? .read() .unwrap() .control - .create_recovery(address, feerate_vb, None) + .create_recovery(address, feerate_vb, sequence) .map_err(|e| DaemonError::Unexpected(e.to_string())) .map(|res| res.psbt) } diff --git a/gui/src/daemon/mod.rs b/gui/src/daemon/mod.rs index d81716eb..aff5c012 100644 --- a/gui/src/daemon/mod.rs +++ b/gui/src/daemon/mod.rs @@ -68,7 +68,12 @@ pub trait Daemon: Debug { _end: u32, _limit: u64, ) -> Result; - fn create_recovery(&self, address: Address, feerate_vb: u64) -> Result; + fn create_recovery( + &self, + address: Address, + feerate_vb: u64, + sequence: Option, + ) -> Result; fn list_txs(&self, txid: &[Txid]) -> Result; fn list_spend_transactions(&self) -> Result, DaemonError> {