diff --git a/gui/Cargo.lock b/gui/Cargo.lock index 40fad6b49..b2e91f49d 100644 --- a/gui/Cargo.lock +++ b/gui/Cargo.lock @@ -62,30 +62,30 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common", "generic-array", ] [[package]] name = "aes" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] name = "aes-gcm" -version = "0.9.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", @@ -101,7 +101,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.8", + "getrandom", "once_cell", "version_check", ] @@ -159,9 +159,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ash" @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "async-hwi" -version = "0.0.12" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca4546c8774683d7c15e692be53751f59fcac3b83465332013b3ca673248e15" +checksum = "2a1d739fac959bf5e332425995a1892f99d94f39acd8acf36fe6c212f9583e0c" dependencies = [ "async-trait", "base64 0.13.1", @@ -297,21 +297,21 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitbox-api" -version = "0.1.8" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f42283322b091f6650ed7cfa17febd100c245bf068fc1a28708e6b3763f2f43" +checksum = "bb3e44c693da4b4db46e2e3f2beb28479cb6a0bd4ebda12f1f22b39a48188f88" dependencies = [ "async-trait", "base32", "bitcoin", "byteorder", - "getrandom 0.2.8", + "getrandom", "hex", "hidapi", "noise-protocol", "noise-rust-crypto", "num-bigint", - "prost", + "prost 0.12.2", "prost-build", "semver", "serde", @@ -372,7 +372,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -485,21 +485,20 @@ dependencies = [ [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", @@ -531,11 +530,13 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", + "zeroize", ] [[package]] @@ -657,7 +658,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ - "getrandom 0.2.8", + "getrandom", "once_cell", "proc-macro-hack", "tiny-keccak", @@ -833,9 +834,9 @@ dependencies = [ [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] @@ -848,17 +849,31 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "cxx" version = "1.0.94" @@ -955,15 +970,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" @@ -1214,6 +1220,12 @@ dependencies = [ "log", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "filetime" version = "0.2.22" @@ -1498,17 +1510,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.8" @@ -1524,9 +1525,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug", "polyval", @@ -2221,6 +2222,15 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -2354,7 +2364,7 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d676038719d1c892f91e6e85121550143c75880b42f7feff6d413a078cf91fb3" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", ] [[package]] @@ -2420,14 +2430,14 @@ dependencies = [ [[package]] name = "liana" version = "2.0.0" -source = "git+https://github.com/wizardsardine/liana?branch=master#2d303b139d4eeafc6b6505433e18b24cd561ab6b" +source = "git+https://github.com/wizardsardine/liana?branch=master#514535d8d6fec705c7271241f68276c42b918150" dependencies = [ "backtrace", "bdk_coin_select", "bip39", "dirs 5.0.0", "fern", - "getrandom 0.2.8", + "getrandom", "jsonrpc 0.16.0", "log", "miniscript", @@ -2599,7 +2609,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "euclid", "num-traits", ] @@ -2815,7 +2825,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom 0.2.8", + "getrandom", ] [[package]] @@ -2936,23 +2946,22 @@ checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "noise-protocol" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb474d36dfe51bb4d7e733fee2b0dfd92ee1b95c716030a70e92737dea1a52b" +checksum = "2473d39689a839f5a363aaef7d99f76d5611bf352286682b25a6644fec18b1d3" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", ] [[package]] name = "noise-rust-crypto" -version = "0.5.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e7cfeb8e6a63b4a5ccef34ed7a22d084a129b1e53a000c080bbc54c0da6f8c" +checksum = "b4c6159f60beb3bbbcdc266bc789bfc6c37fdad7d7ca7152d3e049ef5af633f0" dependencies = [ "aes-gcm", "blake2", "chacha20poly1305", - "getrandom 0.2.8", "noise-protocol", "sha2", "x25519-dalek", @@ -3353,6 +3362,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "png" version = "0.17.7" @@ -3367,9 +3382,9 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", @@ -3378,9 +3393,9 @@ dependencies = [ [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", "cpufeatures", @@ -3446,9 +3461,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -3466,7 +3481,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5a410fc7882af66deb8d01d01737353cf3ad6204c408177ba494291a626312" +dependencies = [ + "bytes", + "prost-derive 0.12.2", ] [[package]] @@ -3483,7 +3508,7 @@ dependencies = [ "multimap", "petgraph", "prettyplease", - "prost", + "prost 0.11.9", "prost-types", "regex", "syn 1.0.109", @@ -3504,13 +3529,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065717a5dfaca4a83d2fe57db3487b311365200000551d7a364e715dbf4346bc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost", + "prost 0.11.9", ] [[package]] @@ -3533,9 +3571,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -3548,7 +3586,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -3558,16 +3596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -3576,7 +3605,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom", ] [[package]] @@ -3644,7 +3673,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e233b642160555c1aa1ff7a78443c6139342f411b6fa6602af2ebbfee9e166bb" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -3671,7 +3700,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.8", + "getrandom", "redox_syscall 0.2.16", "thiserror", ] @@ -3840,6 +3869,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.13" @@ -4065,13 +4103,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -4446,7 +4484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" dependencies = [ "arrayref", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bytemuck", "cfg-if", "png", @@ -4745,11 +4783,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] @@ -4836,12 +4874,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -5046,7 +5078,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d745a1b6d91d85c33defbb29f0eee0450e1d2614d987e14bf6baf26009d132d7" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "cfg-if", "js-sys", "log", @@ -5070,7 +5102,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7131408d940e335792645a98f03639573b0480e9e2e7cddbbab74f7c6d9f3fff" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bit-vec", "bitflags", "codespan-reporting", @@ -5094,7 +5126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdcf61a283adc744bb5453dd88ea91f3f86d5ca6b027661c6c73c7734ae0288b" dependencies = [ "android_system_properties", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "ash", "bit-set", "bitflags", @@ -5502,12 +5534,12 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek", - "rand_core 0.5.1", + "rand_core", "zeroize", ] @@ -5540,9 +5572,9 @@ checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" [[package]] name = "zeroize" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 89b2c4fb2..20e55ce43 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -14,7 +14,7 @@ name = "liana-gui" path = "src/main.rs" [dependencies] -async-hwi = "0.0.12" +async-hwi = "0.0.13" liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false, features = ["nonblocking_shutdown"] } liana_ui = { path = "ui" } backtrace = "0.3" diff --git a/gui/src/app/message.rs b/gui/src/app/message.rs index f8256ecb4..bc7b62b5b 100644 --- a/gui/src/app/message.rs +++ b/gui/src/app/message.rs @@ -3,7 +3,11 @@ use std::sync::Arc; use liana::{ config::Config as DaemonConfig, - miniscript::bitcoin::{bip32::Fingerprint, psbt::Psbt, Address}, + miniscript::bitcoin::{ + bip32::{ChildNumber, Fingerprint}, + psbt::Psbt, + Address, + }, }; use crate::{ @@ -21,7 +25,7 @@ pub enum Message { LoadWallet, WalletLoaded(Result, Error>), Info(Result), - ReceiveAddress(Result), + ReceiveAddress(Result<(Address, ChildNumber), Error>), Coins(Result, Error>), Labels(Result, Error>), SpendTxs(Result, Error>), @@ -31,6 +35,7 @@ pub enum Message { WalletRegistered(Result), Updated(Result<(), Error>), Saved(Result<(), Error>), + Verified(Fingerprint, Result<(), Error>), StartRescan(Result<(), Error>), HardwareWallets(HardwareWalletMessage), HistoryTransactions(Result, Error>), diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index 78f9a62df..605220308 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -90,7 +90,9 @@ impl App { self.cache.blockheight, ) .into(), - menu::Menu::Receive => ReceivePanel::default().into(), + menu::Menu::Receive => { + ReceivePanel::new(self.data_dir.clone(), self.wallet.clone()).into() + } menu::Menu::Transactions => TransactionsPanel::new().into(), menu::Menu::PSBTs => PsbtsPanel::new(self.wallet.clone(), &self.cache.spend_txs).into(), menu::Menu::CreateSpendTx => CreateSpendPanel::new( diff --git a/gui/src/app/state/mod.rs b/gui/src/app/state/mod.rs index b6292e066..1126f62f6 100644 --- a/gui/src/app/state/mod.rs +++ b/gui/src/app/state/mod.rs @@ -2,29 +2,30 @@ mod coins; mod label; mod psbt; mod psbts; +mod receive; mod recovery; mod settings; mod spend; mod transactions; -use std::collections::HashMap; use std::convert::TryInto; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; -use iced::{widget::qr_code, Command, Subscription}; -use liana::miniscript::bitcoin::{Address, Amount, OutPoint}; +use iced::{Command, Subscription}; +use liana::miniscript::bitcoin::{Amount, OutPoint}; use liana_ui::widget::*; use super::{cache::Cache, error::Error, menu::Menu, message::Message, view, wallet::Wallet}; use crate::daemon::{ - model::{remaining_sequence, Coin, HistoryTransaction, LabelItem, Labelled}, + model::{remaining_sequence, Coin, HistoryTransaction, Labelled}, Daemon, }; pub use coins::CoinsPanel; use label::LabelsEdited; pub use psbts::PsbtsPanel; +pub use receive::ReceivePanel; pub use recovery::RecoveryPanel; pub use settings::SettingsState; pub use spend::CreateSpendPanel; @@ -48,6 +49,13 @@ pub trait State { } } +/// redirect to another state with a message menu +pub fn redirect(menu: Menu) -> Command { + Command::perform(async { menu }, |menu| { + Message::View(view::Message::Menu(menu)) + }) +} + pub struct Home { wallet: Arc, balance: Amount, @@ -292,142 +300,3 @@ impl From for Box { Box::new(s) } } - -#[derive(Debug, Default)] -pub struct Addresses { - list: Vec
, - labels: HashMap, -} - -impl Labelled for Addresses { - fn labelled(&self) -> Vec { - self.list - .iter() - .map(|a| LabelItem::Address(a.clone())) - .collect() - } - fn labels(&mut self) -> &mut HashMap { - &mut self.labels - } -} - -#[derive(Default)] -pub struct ReceivePanel { - addresses: Addresses, - labels_edited: LabelsEdited, - qr_code: Option, - warning: Option, -} - -impl State for ReceivePanel { - fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> { - view::dashboard( - &Menu::Receive, - cache, - self.warning.as_ref(), - view::receive::receive( - &self.addresses.list, - self.qr_code.as_ref(), - &self.addresses.labels, - self.labels_edited.cache(), - ), - ) - } - fn update( - &mut self, - daemon: Arc, - _cache: &Cache, - message: Message, - ) -> Command { - match message { - Message::View(view::Message::Label(_, _)) | Message::LabelsUpdated(_) => { - match self.labels_edited.update( - daemon, - message, - std::iter::once(&mut self.addresses).map(|a| a as &mut dyn Labelled), - ) { - Ok(cmd) => cmd, - Err(e) => { - self.warning = Some(e); - Command::none() - } - } - } - Message::ReceiveAddress(res) => { - match res { - Ok(address) => { - self.warning = None; - self.qr_code = Some(qr_code::State::new(address.to_qr_uri()).unwrap()); - self.addresses.list.push(address); - } - Err(e) => self.warning = Some(e), - } - Command::none() - } - Message::View(view::Message::Next) => self.load(daemon), - _ => Command::none(), - } - } - - fn load(&self, daemon: Arc) -> Command { - let daemon = daemon.clone(); - Command::perform( - async move { - daemon - .get_new_address() - .map(|res| res.address().clone()) - .map_err(|e| e.into()) - }, - Message::ReceiveAddress, - ) - } -} - -impl From for Box { - fn from(s: ReceivePanel) -> Box { - Box::new(s) - } -} - -/// redirect to another state with a message menu -pub fn redirect(menu: Menu) -> Command { - Command::perform(async { menu }, |menu| { - Message::View(view::Message::Menu(menu)) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - app::cache::Cache, - daemon::{ - client::{Lianad, Request}, - model::*, - }, - utils::{mock::Daemon, sandbox::Sandbox}, - }; - - use liana::miniscript::bitcoin::Address; - use serde_json::json; - use std::str::FromStr; - - #[tokio::test] - async fn test_receive_panel() { - let addr = - Address::from_str("tb1qkldgvljmjpxrjq2ev5qxe8dvhn0dph9q85pwtfkjeanmwdue2akqj4twxj") - .unwrap() - .assume_checked(); - let daemon = Daemon::new(vec![( - Some(json!({"method": "getnewaddress", "params": Option::::None})), - Ok(json!(GetAddressResult::new(addr.clone()))), - )]); - - let sandbox: Sandbox = Sandbox::new(ReceivePanel::default()); - let client = Arc::new(Lianad::new(daemon.run())); - let sandbox = sandbox.load(client, &Cache::default()).await; - - let panel = sandbox.state(); - assert_eq!(panel.addresses.list, vec![addr]); - } -} diff --git a/gui/src/app/state/receive.rs b/gui/src/app/state/receive.rs new file mode 100644 index 000000000..8a7f85a7b --- /dev/null +++ b/gui/src/app/state/receive.rs @@ -0,0 +1,321 @@ +use std::collections::{HashMap, HashSet}; +use std::path::PathBuf; +use std::sync::Arc; + +use iced::{widget::qr_code, Command, Subscription}; +use liana::miniscript::bitcoin::{ + bip32::{ChildNumber, Fingerprint}, + Address, Network, +}; +use liana_ui::{component::modal, widget::*}; + +use crate::{ + app::{ + cache::Cache, + error::Error, + menu::Menu, + message::Message, + state::{label::LabelsEdited, State}, + view, + wallet::Wallet, + }, + hw::{HardwareWallet, HardwareWallets}, +}; + +use crate::daemon::{ + model::{LabelItem, Labelled}, + Daemon, +}; + +#[derive(Debug, Default)] +pub struct Addresses { + list: Vec
, + derivation_indexes: Vec, + labels: HashMap, +} + +impl Labelled for Addresses { + fn labelled(&self) -> Vec { + self.list + .iter() + .map(|a| LabelItem::Address(a.clone())) + .collect() + } + fn labels(&mut self) -> &mut HashMap { + &mut self.labels + } +} + +pub struct ReceivePanel { + data_dir: PathBuf, + wallet: Arc, + addresses: Addresses, + labels_edited: LabelsEdited, + qr_code: Option, + modal: Option, + warning: Option, +} + +impl ReceivePanel { + pub fn new(data_dir: PathBuf, wallet: Arc) -> Self { + Self { + data_dir, + wallet, + addresses: Addresses::default(), + labels_edited: LabelsEdited::default(), + qr_code: None, + modal: None, + warning: None, + } + } +} + +impl State for ReceivePanel { + fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> { + let content = view::dashboard( + &Menu::Receive, + cache, + self.warning.as_ref(), + view::receive::receive( + &self.addresses.list, + self.qr_code.as_ref(), + &self.addresses.labels, + self.labels_edited.cache(), + ), + ); + if let Some(m) = &self.modal { + modal::Modal::new(content, m.view()) + .on_blur(Some(view::Message::Close)) + .into() + } else { + content + } + } + + fn subscription(&self) -> Subscription { + if let Some(modal) = &self.modal { + modal.subscription() + } else { + Subscription::none() + } + } + + fn update( + &mut self, + daemon: Arc, + cache: &Cache, + message: Message, + ) -> Command { + match message { + Message::View(view::Message::Label(_, _)) | Message::LabelsUpdated(_) => { + match self.labels_edited.update( + daemon, + message, + std::iter::once(&mut self.addresses).map(|a| a as &mut dyn Labelled), + ) { + Ok(cmd) => cmd, + Err(e) => { + self.warning = Some(e); + Command::none() + } + } + } + Message::ReceiveAddress(res) => { + match res { + Ok((address, derivation_index)) => { + self.warning = None; + self.qr_code = Some(qr_code::State::new(address.to_qr_uri()).unwrap()); + self.addresses.list.push(address); + self.addresses.derivation_indexes.push(derivation_index); + } + Err(e) => self.warning = Some(e), + } + Command::none() + } + Message::View(view::Message::Close) => { + self.modal = None; + Command::none() + } + Message::View(view::Message::Select(i)) => { + self.modal = Some(VerifyAddressModal::new( + self.data_dir.clone(), + self.wallet.clone(), + cache.network, + self.addresses.list.get(i).expect("Must be present").clone(), + *self + .addresses + .derivation_indexes + .get(i) + .expect("Must be present"), + )); + Command::none() + } + Message::View(view::Message::Next) => self.load(daemon), + _ => self + .modal + .as_mut() + .map(|m| m.update(daemon, cache, message)) + .unwrap_or_else(Command::none), + } + } + + fn load(&self, daemon: Arc) -> Command { + let daemon = daemon.clone(); + Command::perform( + async move { + daemon + .get_new_address() + .map(|res| (res.address, res.derivation_index)) + .map_err(|e| e.into()) + }, + Message::ReceiveAddress, + ) + } +} + +impl From for Box { + fn from(s: ReceivePanel) -> Box { + Box::new(s) + } +} + +pub struct VerifyAddressModal { + warning: Option, + chosen_hws: HashSet, + hws: HardwareWallets, + address: Address, + derivation_index: ChildNumber, +} + +impl VerifyAddressModal { + pub fn new( + data_dir: PathBuf, + wallet: Arc, + network: Network, + address: Address, + derivation_index: ChildNumber, + ) -> Self { + Self { + warning: None, + chosen_hws: HashSet::new(), + hws: HardwareWallets::new(data_dir, network).with_wallet(wallet), + address, + derivation_index, + } + } +} + +impl VerifyAddressModal { + fn view(&self) -> Element { + view::receive::verify_address_modal( + self.warning.as_ref(), + &self.hws.list, + &self.chosen_hws, + &self.address, + &self.derivation_index, + ) + } + + fn subscription(&self) -> Subscription { + self.hws.refresh().map(Message::HardwareWallets) + } + + fn update( + &mut self, + _daemon: Arc, + _cache: &Cache, + message: Message, + ) -> Command { + match message { + Message::HardwareWallets(msg) => match self.hws.update(msg) { + Ok(cmd) => cmd.map(Message::HardwareWallets), + Err(e) => { + self.warning = Some(e.into()); + Command::none() + } + }, + Message::Verified(fg, res) => { + self.chosen_hws.remove(&fg); + if let Err(e) = res { + self.warning = Some(e); + } + Command::none() + } + Message::View(view::Message::SelectHardwareWallet(i)) => { + if let Some(HardwareWallet::Supported { + device, + fingerprint, + .. + }) = self.hws.list.get(i) + { + self.warning = None; + self.chosen_hws.insert(*fingerprint); + let fg = *fingerprint; + Command::perform( + verify_address(device.clone(), self.derivation_index), + move |res| Message::Verified(fg, res), + ) + } else { + Command::none() + } + } + _ => Command::none(), + } + } +} + +async fn verify_address( + hw: std::sync::Arc, + index: ChildNumber, +) -> Result<(), Error> { + hw.display_address(&async_hwi::AddressScript::Miniscript { + change: false, + index: index.into(), + }) + .await?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + app::cache::Cache, + daemon::{ + client::{Lianad, Request}, + model::*, + }, + utils::{mock::Daemon, sandbox::Sandbox}, + }; + + use liana::{descriptors::LianaDescriptor, miniscript::bitcoin::Address}; + use serde_json::json; + use std::str::FromStr; + + const DESC: &str = "wsh(or_d(multi(2,[ffd63c8d/48'/1'/0'/2']tpubDExA3EC3iAsPxPhFn4j6gMiVup6V2eH3qKyk69RcTc9TTNRfFYVPad8bJD5FCHVQxyBT4izKsvr7Btd2R4xmQ1hZkvsqGBaeE82J71uTK4N/<0;1>/*,[de6eb005/48'/1'/0'/2']tpubDFGuYfS2JwiUSEXiQuNGdT3R7WTDhbaE6jbUhgYSSdhmfQcSx7ZntMPPv7nrkvAqjpj3jX9wbhSGMeKVao4qAzhbNyBi7iQmv5xxQk6H6jz/<0;1>/*),and_v(v:pkh([ffd63c8d/48'/1'/0'/2']tpubDExA3EC3iAsPxPhFn4j6gMiVup6V2eH3qKyk69RcTc9TTNRfFYVPad8bJD5FCHVQxyBT4izKsvr7Btd2R4xmQ1hZkvsqGBaeE82J71uTK4N/<2;3>/*),older(3))))#p9ax3xxp"; + + #[tokio::test] + async fn test_receive_panel() { + let addr = + Address::from_str("tb1qkldgvljmjpxrjq2ev5qxe8dvhn0dph9q85pwtfkjeanmwdue2akqj4twxj") + .unwrap() + .assume_checked(); + let daemon = Daemon::new(vec![( + Some(json!({"method": "getnewaddress", "params": Option::::None})), + Ok(json!(GetAddressResult::new( + addr.clone(), + ChildNumber::from_normal_idx(0).unwrap() + ))), + )]); + + let sandbox: Sandbox = Sandbox::new(ReceivePanel::new( + PathBuf::new(), + Arc::new(Wallet::new(LianaDescriptor::from_str(DESC).unwrap())), + )); + let client = Arc::new(Lianad::new(daemon.run())); + let sandbox = sandbox.load(client, &Cache::default()).await; + + let panel = sandbox.state(); + assert_eq!(panel.addresses.list, vec![addr]); + } +} diff --git a/gui/src/app/view/hw.rs b/gui/src/app/view/hw.rs index e6dbba985..de1eafd39 100644 --- a/gui/src/app/view/hw.rs +++ b/gui/src/app/view/hw.rs @@ -107,3 +107,40 @@ pub fn hw_list_view_for_registration( .style(theme::Container::Card(theme::Card::Simple)) .into() } + +pub fn hw_list_view_verify_address( + i: usize, + hw: &HardwareWallet, + chosen: bool, +) -> Element { + let mut bttn = Button::new(match hw { + HardwareWallet::Supported { + kind, + version, + fingerprint, + alias, + .. + } => { + if chosen { + hw::processing_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref()) + } else { + hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref()) + } + } + HardwareWallet::Unsupported { version, kind, .. } => { + hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref()) + } + HardwareWallet::Locked { + kind, pairing_code, .. + } => hw::locked_hardware_wallet(kind, pairing_code.as_ref()), + }) + .style(theme::Button::Border) + .width(Length::Fill); + if !chosen && hw.is_supported() { + bttn = bttn.on_press(Message::SelectHardwareWallet(i)); + } + Container::new(bttn) + .width(Length::Fill) + .style(theme::Container::Card(theme::Card::Simple)) + .into() +} diff --git a/gui/src/app/view/receive.rs b/gui/src/app/view/receive.rs index 7b7a2c976..508b145c9 100644 --- a/gui/src/app/view/receive.rs +++ b/gui/src/app/view/receive.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use iced::{ widget::{ @@ -8,7 +8,11 @@ use iced::{ Alignment, Length, }; -use liana::miniscript::bitcoin; +use liana::miniscript::bitcoin::{ + self, + bip32::{ChildNumber, Fingerprint}, + Address, +}; use liana_ui::{ color, @@ -17,10 +21,17 @@ use liana_ui::{ text::{self, *}, }, icon, theme, + util::Collection, widget::*, }; -use crate::app::view::label; +use crate::{ + app::{ + error::Error, + view::{hw, label, warning::warn}, + }, + hw::HardwareWallet, +}; use super::message::Message; @@ -44,9 +55,9 @@ pub fn receive<'a>( .push( Row::new() .spacing(10) - .push(addresses.iter().rev().fold( + .push(addresses.iter().enumerate().rev().fold( Column::new().spacing(10).width(Length::Fill), - |col, address| { + |col, (i, address)| { let addr = address.to_string(); col.push( card::simple( @@ -98,7 +109,12 @@ pub fn receive<'a>( .style(theme::Button::TransparentBorder), ) .align_items(Alignment::Center), - ), + ) + .push( + button::primary(None, "Verify on hardware device") + .on_press(Message::Select(i)), + ) + .spacing(10), ) .padding(20), ) @@ -115,3 +131,86 @@ pub fn receive<'a>( .spacing(20) .into() } + +pub fn verify_address_modal<'a>( + warning: Option<&Error>, + hws: &'a [HardwareWallet], + chosen_hws: &HashSet, + address: &Address, + derivation_index: &ChildNumber, +) -> Element<'a, Message> { + Column::new() + .push_maybe(warning.map(|w| warn(Some(w)))) + .push(card::simple( + Column::new() + .push( + Column::new() + .push( + Column::new() + .push( + Row::new() + .width(Length::Fill) + .align_items(Alignment::Center) + .push( + Container::new(text("Address:").bold()) + .width(Length::Fill), + ) + .push( + Row::new() + .align_items(Alignment::Center) + .push(Container::new( + text(address.to_string()).small(), + )) + .push( + Button::new(icon::clipboard_icon()) + .on_press(Message::Clipboard( + address.to_string(), + )) + .style(theme::Button::TransparentBorder), + ) + .width(Length::Shrink), + ), + ) + .push( + Row::new() + .width(Length::Fill) + .align_items(Alignment::Center) + .push( + Container::new(text("Derivation index:").bold()) + .width(Length::Fill), + ) + .push( + Container::new( + text(derivation_index.to_string()).small(), + ) + .width(Length::Shrink), + ), + ) + .spacing(5), + ) + .push(text("Select device to verify address on:").width(Length::Fill)) + .spacing(10) + .push(hws.iter().enumerate().fold( + Column::new().spacing(10), + |col, (i, hw)| { + col.push(hw::hw_list_view_verify_address( + i, + hw, + if let HardwareWallet::Supported { fingerprint, .. } = hw { + chosen_hws.contains(fingerprint) + } else { + false + }, + )) + }, + )) + .width(Length::Fill), + ) + .spacing(20) + .width(Length::Fill) + .align_items(Alignment::Center), + )) + .width(Length::Fill) + .max_width(750) + .into() +} diff --git a/gui/src/hw.rs b/gui/src/hw.rs index de2a21005..90d753a0e 100644 --- a/gui/src/hw.rs +++ b/gui/src/hw.rs @@ -355,7 +355,13 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) { still.push(id); } else { let device = specter::Specter::::new(port.clone()); - if device.is_connected().await.is_ok() { + if tokio::time::timeout( + std::time::Duration::from_millis(500), + device.fingerprint(), + ) + .await + .is_ok() + { match HardwareWallet::new(id, Arc::new(device), Some(&state.keys_aliases)) .await {