diff --git a/Cargo.lock b/Cargo.lock index 6fb0ee1..6d7bea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,85 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "age" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf640be7658959746f1f0f2faab798f6098a9436a8e18e148d18bc9875e13c4b" +dependencies = [ + "age-core", + "base64 0.21.7", + "bech32 0.9.1", + "chacha20poly1305", + "cookie-factory", + "hmac", + "i18n-embed", + "i18n-embed-fl", + "lazy_static", + "nom", + "pin-project", + "rand 0.8.5", + "rust-embed", + "scrypt", + "sha2", + "subtle", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "age-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99" +dependencies = [ + "base64 0.21.7", + "chacha20poly1305", + "cookie-factory", + "hkdf", + "io_tee", + "nom", + "rand 0.8.5", + "secrecy", + "sha2", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -82,12 +161,27 @@ dependencies = [ "object", ] +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -116,6 +210,27 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bech32" version = "0.11.1" @@ -129,8 +244,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ "bitcoin_hashes", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -143,7 +258,7 @@ checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ "base58ck", "base64 0.21.7", - "bech32", + "bech32 0.11.1", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -263,6 +378,12 @@ dependencies = [ "objc2", ] +[[package]] +name = "bmp-monochrome" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829a082bd3761fde7476dc2ed85ca56c11628948460ece621e4f56fef5046567" + [[package]] name = "bstr" version = "1.12.1" @@ -285,6 +406,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + [[package]] name = "cc" version = "1.2.56" @@ -307,6 +434,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "chumsky" version = "0.11.2" @@ -321,6 +472,17 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clap" version = "4.5.60" @@ -367,6 +529,31 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "cookie-factory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -408,9 +595,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "ctrlc" version = "3.5.2" @@ -422,6 +619,32 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "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", +] + [[package]] name = "digest" version = "0.10.7" @@ -430,6 +653,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -444,6 +668,17 @@ dependencies = [ "objc2", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -485,9 +720,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a0bd443023f9f5c4b7153053721939accc7113cbdf810a024434eed454b3db1" dependencies = [ "bitcoin", + "byteorder", + "libc", "log", + "rustls 0.23.38", "serde", "serde_json", + "webpki-roots 0.25.4", + "winapi", ] [[package]] @@ -496,13 +736,25 @@ version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81b2569d3495bfdfce36c504fd4d78752ff4a7699f8a33e6f3ee523bddf9f6ad" dependencies = [ - "bech32", + "bech32 0.11.1", "bitcoin", "secp256k1-zkp", "serde", "serde_json", ] +[[package]] +name = "elements" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d562b364c5d2aced40b01b3f73fc968311787e6813957593d4ffa94cd8733e3" +dependencies = [ + "bech32 0.11.1", + "bitcoin", + "secp256k1-zkp", + "serde_json", +] + [[package]] name = "elements-miniscript" version = "0.4.0" @@ -510,11 +762,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "571fa105690f83c7833df2109eb2e14ca0e62d633d2624ffcb166ff18a3da870" dependencies = [ "bitcoin", - "elements", + "elements 0.25.2", "miniscript", "serde", ] +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -528,7 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -537,18 +798,189 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fluent" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 1.1.0", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror 1.0.69", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -572,6 +1004,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + [[package]] name = "getrandom" version = "0.4.2" @@ -580,7 +1026,7 @@ checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "wasip2", "wasip3", ] @@ -621,6 +1067,25 @@ dependencies = [ "walkdir", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -666,7 +1131,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] -name = "home" +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" @@ -674,12 +1157,282 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2b52f86d1d4bc0d6b4e6826d960b1b333217e07d36b882dca570a5e1c48895b" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls 0.23.38", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.6", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "i18n-config" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e06b90c8a0d252e203c94344b21e35a30f3a3a85dc7db5af8f8df9f3e0c63ef" +dependencies = [ + "basic-toml", + "log", + "serde", + "serde_derive", + "thiserror 1.0.69", + "unic-langid", +] + +[[package]] +name = "i18n-embed" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669ffc2c93f97e6ddf06ddbe999fcd6782e3342978bb85f7d3c087c7978404c4" +dependencies = [ + "arc-swap", + "fluent", + "fluent-langneg", + "fluent-syntax", + "i18n-embed-impl", + "intl-memoizer", + "log", + "parking_lot", + "rust-embed", + "thiserror 1.0.69", + "unic-langid", + "walkdir", +] + +[[package]] +name = "i18n-embed-fl" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04b2969d0b3fc6143776c535184c19722032b43e6a642d710fa3f88faec53c2d" +dependencies = [ + "find-crate", + "fluent", + "fluent-syntax", + "i18n-config", + "i18n-embed", + "proc-macro-error2", + "proc-macro2", + "quote", + "strsim", + "syn", + "unic-langid", +] + +[[package]] +name = "i18n-embed-impl" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2" +dependencies = [ + "find-crate", + "i18n-config", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + [[package]] name = "id-arena" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "ignore" version = "0.4.25" @@ -708,6 +1461,56 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "intl-memoizer" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "io_tee" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b3f7cef34251886990511df1c61443aa928499d598a9473929ab5a90a527304" + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -751,6 +1554,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128fmt" version = "0.1.0" @@ -775,12 +1584,111 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lwk_common" +version = "0.16.0" +source = "git+https://github.com/Blockstream/lwk?rev=d384a20b8e2dde83ca0d733ba6c22dd3c5daac56#d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" +dependencies = [ + "aes-gcm-siv", + "base64 0.21.7", + "elements 0.25.2", + "elements-miniscript", + "getrandom 0.2.17", + "qr_code", + "rand 0.8.5", + "serde", + "serde_json", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "lwk_signer" +version = "0.16.0" +source = "git+https://github.com/Blockstream/lwk?rev=d384a20b8e2dde83ca0d733ba6c22dd3c5daac56#d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" +dependencies = [ + "base64 0.21.7", + "bip39", + "elements-miniscript", + "lwk_common", + "thiserror 1.0.69", +] + +[[package]] +name = "lwk_simplicity" +version = "0.16.0" +source = "git+https://github.com/Blockstream/lwk?rev=d384a20b8e2dde83ca0d733ba6c22dd3c5daac56#d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" +dependencies = [ + "log", + "lwk_common", + "lwk_signer", + "lwk_wollet", + "serde", + "serde_json", + "simplicityhl", + "thiserror 2.0.18", + "uuid", +] + +[[package]] +name = "lwk_wollet" +version = "0.16.0" +source = "git+https://github.com/Blockstream/lwk?rev=d384a20b8e2dde83ca0d733ba6c22dd3c5daac56#d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" +dependencies = [ + "aes-gcm-siv", + "age", + "base64 0.21.7", + "bip39", + "electrum-client", + "elements 0.25.2", + "elements 0.26.1", + "elements-miniscript", + "futures", + "fxhash", + "idna", + "js-sys", + "log", + "lwk_common", + "once_cell", + "rand 0.8.5", + "regex-lite", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "url", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "memchr" version = "2.8.0" @@ -796,13 +1704,25 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniscript" version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ - "bech32", + "bech32 0.11.1", "bitcoin", ] @@ -812,11 +1732,22 @@ version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" dependencies = [ - "rustls", - "rustls-webpki", + "rustls 0.21.12", + "rustls-webpki 0.101.7", "serde", "serde_json", - "webpki-roots", + "webpki-roots 0.25.4", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -845,6 +1776,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "objc2" version = "0.6.4" @@ -881,12 +1822,77 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -897,7 +1903,39 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] [[package]] name = "ppv-lite86" @@ -918,6 +1956,28 @@ dependencies = [ "syn", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -937,6 +1997,70 @@ dependencies = [ "cc", ] +[[package]] +name = "qr_code" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d2564aae5faaf3acb512b35b8bcb9a298d9d8c72d181c598691d800ee78a00" +dependencies = [ + "bmp-monochrome", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.2", + "rustls 0.23.38", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.3", + "ring", + "rustc-hash 2.1.2", + "rustls 0.23.38", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.45" @@ -946,6 +2070,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -959,8 +2089,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -970,7 +2110,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -982,6 +2132,24 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "regex" version = "1.12.3" @@ -1016,6 +2184,12 @@ dependencies = [ "regex-syntax 0.8.10", ] +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + [[package]] name = "regex-syntax" version = "0.7.5" @@ -1028,6 +2202,49 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.38", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.6", +] + [[package]] name = "ring" version = "0.17.14" @@ -1042,6 +2259,61 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rust-embed" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1065,7 +2337,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1076,10 +2348,35 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.11", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -1090,12 +2387,38 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.103.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a6af516fea4b20eccceaf166e8aa666ac996208e8a644ce3ef5aa783bc7cd4" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -1114,6 +2437,23 @@ dependencies = [ "regex", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2", +] + [[package]] name = "sct" version = "0.7.1" @@ -1131,7 +2471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes", - "rand", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -1152,7 +2492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" dependencies = [ "bitcoin-private", - "rand", + "rand 0.8.5", "secp256k1", "secp256k1-zkp-sys", "serde", @@ -1168,6 +2508,30 @@ dependencies = [ "secp256k1-sys", ] +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.2.2", +] + +[[package]] +name = "self_cell" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" + [[package]] name = "semver" version = "1.0.27" @@ -1226,6 +2590,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1252,7 +2628,7 @@ dependencies = [ "bitcoin", "bitcoin_hashes", "byteorder", - "elements", + "elements 0.25.2", "getrandom 0.2.17", "ghost-cell", "hex-conservative", @@ -1288,6 +2664,18 @@ dependencies = [ "simplicity-lang", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "smplx-build" version = "0.0.3" @@ -1301,7 +2689,7 @@ dependencies = [ "serde", "simplicityhl", "syn", - "thiserror", + "thiserror 2.0.18", "toml 0.9.12+spec-1.1.0", ] @@ -1320,7 +2708,7 @@ dependencies = [ "smplx-regtest", "smplx-sdk", "smplx-test", - "thiserror", + "thiserror 2.0.18", "tokio", "toml 0.9.12+spec-1.1.0", "toml_edit", @@ -1342,7 +2730,7 @@ dependencies = [ "electrsd", "serde", "smplx-sdk", - "thiserror", + "thiserror 2.0.18", "toml 0.9.12+spec-1.1.0", ] @@ -1361,7 +2749,7 @@ dependencies = [ "serde_json", "sha2", "simplicityhl", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -1382,17 +2770,40 @@ name = "smplx-test" version = "0.0.3" dependencies = [ "electrsd", + "futures", + "hex", + "lwk_common", + "lwk_signer", + "lwk_simplicity", + "lwk_wollet", "proc-macro2", "quote", "serde", + "serde_json", "simplicityhl", "smplx-regtest", "smplx-sdk", "syn", - "thiserror", + "thiserror 2.0.18", "toml 0.9.12+spec-1.1.0", ] +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "stacker" version = "0.1.23" @@ -1412,6 +2823,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.117" @@ -1423,6 +2840,47 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.11.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "target-triple" version = "1.0.0" @@ -1439,7 +2897,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1452,12 +2910,32 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "2.0.18" +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1471,6 +2949,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.10.0" @@ -1492,8 +2981,13 @@ version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ + "bytes", + "libc", + "mio", "pin-project-lite", + "socket2", "tokio-macros", + "windows-sys 0.61.2", ] [[package]] @@ -1507,6 +3001,38 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.38", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.9.12+spec-1.1.0" @@ -1583,6 +3109,76 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "trybuild" version = "1.0.116" @@ -1598,12 +3194,40 @@ dependencies = [ "toml 1.0.4+spec-1.1.0", ] +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.2", +] + [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "serde", + "tinystr", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -1631,18 +3255,58 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] + [[package]] name = "version_check" version = "0.9.5" @@ -1659,6 +3323,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1696,6 +3369,20 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.114" @@ -1762,12 +3449,41 @@ dependencies = [ "semver", ] +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -1780,21 +3496,72 @@ dependencies = [ "rustix 0.38.44", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1983,6 +3750,47 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.40" @@ -2003,6 +3811,81 @@ dependencies = [ "syn", ] +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index fc68e9b..687b207 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,3 +32,7 @@ simplicityhl = { version = "0.5.0-rc.0" } [patch.crates-io] simplicity-sys = { git = "https://github.com/BlockstreamResearch/rust-simplicity", tag = "simplicity-sys-0.6.1" } +lwk_common = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } +lwk_signer = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } +lwk_simplicity = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } +lwk_wollet = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } diff --git a/crates/simplex/src/lib.rs b/crates/simplex/src/lib.rs index 4e3525b..59a63b0 100644 --- a/crates/simplex/src/lib.rs +++ b/crates/simplex/src/lib.rs @@ -6,6 +6,7 @@ pub use smplx_sdk::*; pub use smplx_test::config::TestConfig; pub use smplx_test::context::TestContext; +pub use smplx_test::wallet_abi; pub use smplx_macros; pub use smplx_macros::{include_simf, test}; diff --git a/crates/simplex/tests/wallet_abi.rs b/crates/simplex/tests/wallet_abi.rs new file mode 100644 index 0000000..f9db770 --- /dev/null +++ b/crates/simplex/tests/wallet_abi.rs @@ -0,0 +1,150 @@ +use std::collections::HashMap; + +use simplex::wallet_abi::{FinalizerSpec, RuntimeFundingAsset, TxEvaluateRequest}; + +#[simplex::test] +fn wallet_abi_smoke(context: simplex::TestContext) -> Result<(), Box> { + let harness = context.wallet_abi()?; + + let lbtc_funding = harness.fund_signer_lbtc(200_000)?; + let issued_funding = harness.fund_signer_asset(5_000)?; + + let wallet_utxos = harness.wallet_utxos()?; + assert!(wallet_utxos.iter().any(|utxo| { + utxo.unblinded.asset == lbtc_funding.asset_id().expect("lbtc asset") + && utxo.unblinded.value == lbtc_funding.value().expect("lbtc value") + })); + assert!(wallet_utxos.iter().any(|utxo| { + utxo.unblinded.asset == issued_funding.asset_id().expect("issued asset") + && utxo.unblinded.value == issued_funding.value().expect("issued value") + })); + + let recipient_script = harness.signer_script(); + let policy_asset = harness.network().policy_asset(); + let request = harness + .tx() + .wallet_input_exact("wallet-input", policy_asset, lbtc_funding.value()?) + .explicit_output("recipient", recipient_script.clone(), policy_asset, 50_000) + .build_create()?; + let request_id = request.request_id.to_string(); + + let preview = harness.evaluate_request(TxEvaluateRequest::from_parts( + request_id.as_str(), + request.network, + request.params.clone(), + )?)?; + assert!(preview.error.is_none()); + assert!(preview.preview.is_some()); + + let tx = harness.process_request(request)?; + let recipient_output = harness.find_output(&tx, |tx_out| { + tx_out.script_pubkey == recipient_script + && tx_out.asset.explicit() == Some(policy_asset) + && tx_out.value.explicit() == Some(50_000) + })?; + + assert_eq!(recipient_output.value()?, 50_000); + assert_eq!(recipient_output.asset_id()?, policy_asset); + + Ok(()) +} + +#[simplex::test] +fn wallet_abi_current_height_matches_provider_tip( + context: simplex::TestContext, +) -> Result<(), Box> { + let harness = context.wallet_abi()?; + + assert_eq!( + harness.current_height()?, + context.get_default_provider().fetch_tip_height()?, + ); + + Ok(()) +} + +#[simplex::test] +fn wallet_abi_mine_to_height_reaches_target(context: simplex::TestContext) -> Result<(), Box> { + let harness = context.wallet_abi()?; + let current_height = harness.current_height()?; + let target_height = current_height + 2; + + harness.mine_to_height(target_height)?; + assert_eq!(harness.current_height()?, target_height); + + harness.mine_to_height(target_height)?; + assert_eq!(harness.current_height()?, target_height); + + Ok(()) +} + +#[simplex::test] +fn wallet_abi_fund_and_sync_returns_synced_utxo( + context: simplex::TestContext, +) -> Result<(), Box> { + let harness = context.wallet_abi()?; + let funding = harness.fund_and_sync(harness.signer_address(), RuntimeFundingAsset::Lbtc, 200_000, 1)?; + let wallet_utxos = harness.wallet_utxos()?; + + assert!(wallet_utxos.iter().any(|utxo| { + utxo.outpoint == funding.outpoint + && utxo.unblinded.asset == funding.asset_id().expect("funding asset") + && utxo.unblinded.value == funding.value().expect("funding value") + })); + + Ok(()) +} + +#[simplex::test] +fn wallet_abi_fund_signer_lbtc_returns_policy_asset( + context: simplex::TestContext, +) -> Result<(), Box> { + let harness = context.wallet_abi()?; + let funding = harness.fund_signer_lbtc(200_000)?; + + assert_eq!(funding.asset_id()?, harness.network().policy_asset()); + assert_eq!(funding.value()?, 200_000); + + Ok(()) +} + +#[simplex::test] +fn wallet_abi_fund_signer_asset_returns_issued_asset( + context: simplex::TestContext, +) -> Result<(), Box> { + let harness = context.wallet_abi()?; + let funding = harness.fund_signer_asset(5_000)?; + + assert_ne!(funding.asset_id()?, harness.network().policy_asset()); + assert_eq!(funding.value()?, 5_000); + + Ok(()) +} + +#[simplex::test] +fn simf_finalizer_uses_bip0341(context: simplex::TestContext) -> Result<(), Box> { + let harness = context.wallet_abi()?; + let arguments = simplex::wallet_abi::SimfArguments::new(simplex::simplicityhl::Arguments::from(HashMap::new())); + let witness = simplex::wallet_abi::SimfWitness::new(simplex::simplicityhl::WitnessValues::from(HashMap::new())); + let expected_arguments = simplex::wallet_abi::serialize_arguments(&arguments)?; + let expected_witness = simplex::wallet_abi::serialize_witness(&witness)?; + + let finalizer = harness.simf_finalizer("unit.simf", &arguments, &witness)?; + + match finalizer { + FinalizerSpec::Simf { + source_simf, + internal_key, + arguments, + witness, + } => { + assert_eq!(source_simf, "unit.simf"); + assert_eq!(internal_key, simplex::wallet_abi::InternalKeySource::Bip0341); + assert_eq!(arguments, expected_arguments); + assert_eq!(witness, expected_witness); + } + FinalizerSpec::Wallet => panic!("expected simf finalizer"), + } + + Ok(()) +} diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml index b676e7c..dd9e90a 100644 --- a/crates/test/Cargo.toml +++ b/crates/test/Cargo.toml @@ -19,6 +19,13 @@ simplicityhl = { workspace = true } electrsd = { workspace = true } serde = { workspace = true } toml = { workspace = true } +hex = { workspace = true } +serde_json = "1.0" +futures = "0.3" +lwk_common = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } +lwk_signer = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56", default-features = false } +lwk_simplicity = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56" } +lwk_wollet = { git = "https://github.com/Blockstream/lwk", rev = "d384a20b8e2dde83ca0d733ba6c22dd3c5daac56", default-features = false, features = ["esplora", "electrum"] } syn = { version = "2.0.114", default-features = false, features = ["proc-macro", "full", "parsing", "derive", "clone-impls", "extra-traits", "printing"] } proc-macro2 = { version = "1.0.106", features = ["span-locations"] } diff --git a/crates/test/src/context.rs b/crates/test/src/context.rs index 787ad6a..8d34fc3 100644 --- a/crates/test/src/context.rs +++ b/crates/test/src/context.rs @@ -10,6 +10,7 @@ use smplx_sdk::signer::Signer; use crate::config::TestConfig; use crate::error::TestError; +use crate::wallet_abi::WalletAbiHarness; #[allow(dead_code)] pub struct TestContext { @@ -70,6 +71,29 @@ impl TestContext { self.signer.get_provider().get_network() } + pub fn wallet_abi(&self) -> Result { + let network = match self.get_network() { + SimplicityNetwork::Liquid => lwk_wollet::ElementsNetwork::Liquid, + SimplicityNetwork::LiquidTestnet => lwk_wollet::ElementsNetwork::LiquidTestnet, + SimplicityNetwork::ElementsRegtest { policy_asset } => lwk_wollet::ElementsNetwork::ElementsRegtest { + policy_asset: policy_asset + .to_string() + .parse::() + .map_err(|error| TestError::WalletAbiInvariant(error.to_string()))?, + }, + }; + + WalletAbiHarness::new( + self.config.mnemonic.as_str(), + network, + self._provider_info.esplora_url.clone(), + self._provider_info + .elements_url + .clone() + .zip(self._provider_info.auth.clone()), + ) + } + fn setup(config: &TestConfig) -> Result<(Signer, ProviderInfo, Option), TestError> { let client: Option; let provider_info: ProviderInfo; diff --git a/crates/test/src/error.rs b/crates/test/src/error.rs index 23ea154..cedede5 100644 --- a/crates/test/src/error.rs +++ b/crates/test/src/error.rs @@ -1,9 +1,16 @@ use std::io; +use electrsd::bitcoind::bitcoincore_rpc::Error as RpcError; +use lwk_simplicity::error::WalletAbiError; use smplx_sdk::provider::ProviderError; +use lwk_signer::NewError; +use lwk_wollet::Error as LwkWalletError; +use lwk_wollet::elements::UnblindError; use smplx_regtest::error::RegtestError; +use crate::wallet_abi::WalletAbiAdapterError; + #[derive(thiserror::Error, Debug)] pub enum TestError { #[error(transparent)] @@ -20,4 +27,28 @@ pub enum TestError { #[error("Network name should either be `Liquid`, `LiquidTestnet` or `ElementsRegtest`, got: {0}")] BadNetworkName(String), + + #[error(transparent)] + LwkWallet(#[from] LwkWalletError), + + #[error(transparent)] + LwkSignerNew(#[from] NewError), + + #[error("wallet descriptor error: {0}")] + WalletDescriptor(String), + + #[error("wallet-abi invariant violation: {0}")] + WalletAbiInvariant(String), + + #[error(transparent)] + WalletAbi(#[from] WalletAbiError), + + #[error(transparent)] + WalletAbiAdapter(#[from] WalletAbiAdapterError), + + #[error(transparent)] + WalletAbiRpc(#[from] RpcError), + + #[error(transparent)] + WalletAbiUnblind(#[from] UnblindError), } diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index 055408e..7de35d6 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -2,5 +2,6 @@ pub mod config; pub mod context; pub mod error; pub mod macros; +pub mod wallet_abi; pub use config::{RpcConfig, TEST_ENV_NAME, TestConfig}; diff --git a/crates/test/src/wallet_abi.rs b/crates/test/src/wallet_abi.rs new file mode 100644 index 0000000..14f8b46 --- /dev/null +++ b/crates/test/src/wallet_abi.rs @@ -0,0 +1,1239 @@ +use std::future::Future; +use std::str::FromStr; +use std::sync::{Arc, Mutex, MutexGuard}; + +use electrsd::bitcoind::bitcoincore_rpc::{Auth, Client, RpcApi}; +use hex::FromHex; +use lwk_common::Signer as _; +use lwk_signer::SwSigner; +use lwk_simplicity::error::WalletAbiError; +pub use lwk_simplicity::wallet_abi::schema::OutputSchema; +pub use lwk_simplicity::wallet_abi::{ + AmountFilter, AssetFilter, AssetVariant, BlinderVariant, ErrorInfo, FinalizerSpec, InputIssuance, + InputIssuanceKind, InputSchema, InputUnblinding, InternalKeySource, LockFilter, LockVariant, PreviewAssetDelta, + PreviewOutput, PreviewOutputKind, RequestPreview, RuntimeParams, RuntimeSimfValue, RuntimeSimfWitness, + SimfArguments, SimfWitness, TX_CREATE_ABI_VERSION, TransactionInfo, TxCreateRequest, TxCreateResponse, + TxEvaluateRequest, TxEvaluateResponse, UTXOSource, WalletAbiProviderBuilder, WalletAbiRuntime, WalletCapabilities, + WalletSourceFilter, deserialize_arguments, deserialize_witness, generate_request_id, resolve_arguments, + resolve_witness, serialize_arguments, serialize_witness, +}; +use lwk_simplicity::wallet_abi::{ + GET_RAW_SIGNING_X_ONLY_PUBKEY_METHOD, GET_SIGNER_RECEIVE_ADDRESS_METHOD, KeyStoreMeta, + WALLET_ABI_EVALUATE_REQUEST_METHOD, WALLET_ABI_GET_CAPABILITIES_METHOD, WALLET_ABI_PROCESS_REQUEST_METHOD, + WalletAbiProvider, WalletBroadcaster, WalletOutputAllocator, WalletOutputRequest, WalletOutputTemplate, + WalletPrevoutResolver, WalletReceiveAddressProvider, WalletRequestSession, WalletRuntimeDeps, WalletSessionFactory, +}; +use lwk_wollet::bitcoin::PublicKey; +use lwk_wollet::bitcoin::bip32::{DerivationPath, KeySource}; +use lwk_wollet::blocking::BlockchainBackend; +use lwk_wollet::elements::confidential::{Asset as ConfidentialAsset, Nonce, Value}; +use lwk_wollet::elements::encode::deserialize; +use lwk_wollet::elements::pset::PartiallySignedTransaction; +pub use lwk_wollet::elements::{ + Address as ElementsAddress, AssetId as ElementsAssetId, OutPoint as ElementsOutPoint, Script as ElementsScript, + Sequence as ElementsSequence, Transaction as ElementsTransaction, TxOut as ElementsTxOut, Txid as ElementsTxid, +}; +use lwk_wollet::elements::{Address, AssetId, OutPoint, Script, Transaction, TxOut, TxOutSecrets, Txid}; +use lwk_wollet::secp256k1::schnorr::Signature; +use lwk_wollet::secp256k1::{Keypair, Message, XOnlyPublicKey}; +use lwk_wollet::{Chain, ElementsNetwork, ExternalUtxo, Wollet, WolletDescriptor}; + +use crate::error::TestError; + +const DEFAULT_ACCOUNT_INDEX: u32 = 0; + +pub type SimplexWalletAbiProvider = WalletAbiProvider< + WalletAbiSignerAdapter, + WalletAbiSessionFactoryAdapter, + WalletAbiPrevoutResolverAdapter, + WalletAbiOutputAllocatorAdapter, + WalletAbiBroadcasterAdapter, + WalletAbiReceiveAddressProviderAdapter, +>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RuntimeFundingAsset { + Lbtc, + IssuedAsset, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct KnownUtxo { + pub outpoint: OutPoint, + pub tx_out: TxOut, + pub unblinded: Option, +} + +impl KnownUtxo { + pub fn asset_id(&self) -> Result { + if let Some(unblinded) = &self.unblinded { + return Ok(unblinded.asset); + } + self.tx_out + .asset + .explicit() + .ok_or_else(|| TestError::WalletAbiInvariant("expected explicit asset".to_string())) + } + + pub fn value(&self) -> Result { + if let Some(unblinded) = &self.unblinded { + return Ok(unblinded.value); + } + self.tx_out + .value + .explicit() + .ok_or_else(|| TestError::WalletAbiInvariant("expected explicit value".to_string())) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum WalletAbiAdapterError { + #[error(transparent)] + Sign(#[from] lwk_signer::SignError), + + #[error(transparent)] + Wallet(#[from] lwk_wollet::Error), + + #[error(transparent)] + Rpc(#[from] electrsd::bitcoind::bitcoincore_rpc::Error), + + #[error(transparent)] + Unblind(#[from] lwk_wollet::elements::UnblindError), + + #[error("state lock poisoned: {0}")] + LockPoisoned(&'static str), + + #[error("wallet-owned output {0} not found")] + UnknownWalletOutpoint(OutPoint), + + #[error("missing tx output {vout} in transaction {txid}")] + MissingTxOutput { txid: Txid, vout: u32 }, + + #[error("failed to decode transaction hex: {0}")] + Decode(String), + + #[error("wallet signer x-only key mismatch")] + XOnlyKeyMismatch, + + #[error("elements rpc is not available for this test context")] + MissingRpc, + + #[error("wallet-abi invariant violation: {0}")] + Invariant(String), +} + +impl From for WalletAbiError { + fn from(error: WalletAbiAdapterError) -> Self { + WalletAbiError::InvalidRequest(error.to_string()) + } +} + +#[derive(Clone)] +pub struct WalletAbiRuntimeAdapters { + pub signer_meta: WalletAbiSignerAdapter, + pub session_factory: WalletAbiSessionFactoryAdapter, + pub prevout_resolver: WalletAbiPrevoutResolverAdapter, + pub output_allocator: WalletAbiOutputAllocatorAdapter, + pub broadcaster: WalletAbiBroadcasterAdapter, + pub receive_address_provider: WalletAbiReceiveAddressProviderAdapter, +} + +impl WalletAbiRuntimeAdapters { + pub fn provider(&self) -> SimplexWalletAbiProvider { + WalletAbiProviderBuilder::new( + self.signer_meta.clone(), + self.session_factory.clone(), + self.prevout_resolver.clone(), + self.output_allocator.clone(), + self.broadcaster.clone(), + self.receive_address_provider.clone(), + ) + .build() + } + + pub fn runtime_deps(&self) -> WalletRuntimeDeps { + WalletRuntimeDeps::new( + self.session_factory.clone(), + WalletAbiSplitProvider { + prevout_resolver: self.prevout_resolver.clone(), + output_allocator: self.output_allocator.clone(), + broadcaster: self.broadcaster.clone(), + }, + ) + } + + pub fn capabilities(&self) -> Result { + Ok(WalletCapabilities::new( + self.session_factory.open_wallet_request_session_sync()?.network, + [ + GET_SIGNER_RECEIVE_ADDRESS_METHOD, + GET_RAW_SIGNING_X_ONLY_PUBKEY_METHOD, + WALLET_ABI_EVALUATE_REQUEST_METHOD, + WALLET_ABI_GET_CAPABILITIES_METHOD, + WALLET_ABI_PROCESS_REQUEST_METHOD, + ], + )) + } +} + +pub struct WalletAbiHarness { + shared: Arc, + adapters: WalletAbiRuntimeAdapters, + signer_address: Address, +} + +#[derive(Debug, Clone)] +pub struct WalletAbiRequestBuilder { + network: ElementsNetwork, + inputs: Vec, + outputs: Vec, + lock_time: Option, +} + +impl WalletAbiRequestBuilder { + fn new(network: ElementsNetwork) -> Self { + Self { + network, + inputs: Vec::new(), + outputs: Vec::new(), + lock_time: None, + } + } + + pub fn build_create(self) -> Result { + let request_id = generate_request_id().to_string(); + Ok(TxCreateRequest::from_parts( + request_id.as_str(), + self.network, + RuntimeParams { + inputs: self.inputs, + outputs: self.outputs, + fee_rate_sat_kvb: Some(100.0), + lock_time: self.lock_time, + }, + true, + )?) + } + + pub fn wallet_input_exact(mut self, id: impl Into, asset_id: AssetId, amount_sat: u64) -> Self { + self.inputs.push(InputSchema { + id: id.into(), + utxo_source: UTXOSource::Wallet { + filter: WalletSourceFilter { + asset: AssetFilter::Exact { asset_id }, + amount: AmountFilter::Exact { amount_sat }, + lock: LockFilter::None, + }, + }, + unblinding: InputUnblinding::Wallet, + sequence: ElementsSequence::ENABLE_LOCKTIME_NO_RBF, + issuance: None, + finalizer: FinalizerSpec::Wallet, + }); + self + } + + pub fn provided_input( + mut self, + id: impl Into, + utxo: &KnownUtxo, + unblinding: InputUnblinding, + finalizer: FinalizerSpec, + ) -> Self { + self.inputs.push(InputSchema { + id: id.into(), + utxo_source: UTXOSource::Provided { + outpoint: utxo.outpoint, + }, + unblinding, + sequence: ElementsSequence::ENABLE_LOCKTIME_NO_RBF, + issuance: None, + finalizer, + }); + self + } + + pub fn new_issuance( + mut self, + input_id: &str, + asset_amount_sat: u64, + token_amount_sat: u64, + entropy: [u8; 32], + ) -> Result { + let mut matches = self.inputs.iter_mut().filter(|input| input.id == input_id); + let input = matches + .next() + .ok_or_else(|| TestError::WalletAbiInvariant(format!("missing input '{input_id}'")))?; + if matches.next().is_some() { + return Err(TestError::WalletAbiInvariant(format!( + "expected exactly one input named '{input_id}'", + ))); + } + input.issuance = Some(InputIssuance { + kind: InputIssuanceKind::New, + asset_amount_sat, + token_amount_sat, + entropy, + }); + Ok(self) + } + + pub fn explicit_output( + mut self, + id: impl Into, + script: Script, + asset_id: AssetId, + amount_sat: u64, + ) -> Self { + self.outputs.push(OutputSchema { + id: id.into(), + amount_sat, + lock: LockVariant::Script { script }, + asset: AssetVariant::AssetId { asset_id }, + blinder: BlinderVariant::Explicit, + }); + self + } + + pub fn new_issuance_asset_output( + mut self, + id: impl Into, + script: Script, + input_index: u32, + amount_sat: u64, + ) -> Self { + self.outputs.push(OutputSchema { + id: id.into(), + amount_sat, + lock: LockVariant::Script { script }, + asset: AssetVariant::NewIssuanceAsset { input_index }, + blinder: BlinderVariant::Explicit, + }); + self + } + + pub fn finalizer_output( + mut self, + id: impl Into, + finalizer: FinalizerSpec, + asset_id: AssetId, + amount_sat: u64, + ) -> Self { + self.outputs.push(OutputSchema { + id: id.into(), + amount_sat, + lock: LockVariant::Finalizer { + finalizer: Box::new(finalizer), + }, + asset: AssetVariant::AssetId { asset_id }, + blinder: BlinderVariant::Explicit, + }); + self + } + + pub fn lock_time_height(mut self, height: u32) -> Result { + self.lock_time = Some( + lwk_wollet::elements::LockTime::from_height(height) + .map_err(|error| TestError::WalletAbiInvariant(error.to_string()))?, + ); + Ok(self) + } +} + +impl WalletAbiHarness { + pub(crate) fn new( + mnemonic: &str, + network: ElementsNetwork, + esplora_url: String, + rpc: Option<(String, Auth)>, + ) -> Result { + let signer = SwSigner::new(mnemonic, matches!(network, ElementsNetwork::Liquid))?; + let descriptor: WolletDescriptor = signer + .wpkh_slip77_descriptor() + .map_err(TestError::WalletDescriptor)? + .parse()?; + let wallet = lwk_wollet::WolletBuilder::new(network, descriptor.clone()).build()?; + let signer_address = wallet.address(None)?.address().clone(); + let shared = Arc::new(WalletAbiSharedState { + account_index: DEFAULT_ACCOUNT_INDEX, + network, + signer, + descriptor, + wallet: Mutex::new(wallet), + esplora: Mutex::new(lwk_wollet::blocking::EsploraClient::new(esplora_url.as_str(), network)?), + rpc, + }); + let adapters = WalletAbiRuntimeAdapters { + signer_meta: WalletAbiSignerAdapter { + shared: Arc::clone(&shared), + }, + session_factory: WalletAbiSessionFactoryAdapter { + shared: Arc::clone(&shared), + }, + prevout_resolver: WalletAbiPrevoutResolverAdapter { + shared: Arc::clone(&shared), + }, + output_allocator: WalletAbiOutputAllocatorAdapter { + shared: Arc::clone(&shared), + }, + broadcaster: WalletAbiBroadcasterAdapter { + shared: Arc::clone(&shared), + }, + receive_address_provider: WalletAbiReceiveAddressProviderAdapter { + shared: Arc::clone(&shared), + }, + }; + + Ok(Self { + shared, + adapters, + signer_address, + }) + } + + pub fn signer_address(&self) -> &Address { + &self.signer_address + } + + pub fn signer_script(&self) -> Script { + self.signer_address.script_pubkey() + } + + pub fn network(&self) -> ElementsNetwork { + self.shared.network + } + + pub fn runtime_adapters(&self) -> &WalletAbiRuntimeAdapters { + &self.adapters + } + + pub fn provider(&self) -> SimplexWalletAbiProvider { + self.adapters.provider() + } + + pub fn tx(&self) -> WalletAbiRequestBuilder { + WalletAbiRequestBuilder::new(self.network()) + } + + pub fn wallet_utxos(&self) -> Result, TestError> { + Ok(self.shared.wallet_snapshot()?) + } + + pub fn sync_wallet(&self) -> Result<(), TestError> { + self.shared.sync_wallet()?; + Ok(()) + } + + pub fn current_height(&self) -> Result { + Ok(self.shared.current_height()?) + } + + pub fn mine_blocks(&self, blocks: u32) -> Result<(), TestError> { + self.shared.generate_blocks(blocks)?; + Ok(()) + } + + pub fn mine_to_height(&self, target_height: u32) -> Result<(), TestError> { + let current_height = self.current_height()?; + if target_height <= current_height { + return Ok(()); + } + self.mine_blocks(target_height - current_height)?; + for _ in 0..20 { + let synced_height = self.current_height()?; + if synced_height >= target_height { + return Ok(()); + } + std::thread::sleep(std::time::Duration::from_millis(100)); + } + Err(TestError::WalletAbiInvariant(format!( + "failed to sync wallet tip to height {target_height}", + ))) + } + + pub fn mine_and_sync(&self, blocks: u32) -> Result<(), TestError> { + self.mine_blocks(blocks)?; + self.sync_wallet() + } + + pub fn fund_address( + &self, + address: &Address, + asset: RuntimeFundingAsset, + amount_sat: u64, + ) -> Result { + self.shared.fund_address(address, asset, amount_sat) + } + + pub fn fund_and_sync( + &self, + address: &Address, + asset: RuntimeFundingAsset, + amount_sat: u64, + blocks: u32, + ) -> Result { + let utxo = self.fund_address(address, asset, amount_sat)?; + self.mine_and_sync(blocks)?; + Ok(utxo) + } + + pub fn fund_signer_lbtc(&self, amount_sat: u64) -> Result { + self.fund_and_sync(self.signer_address(), RuntimeFundingAsset::Lbtc, amount_sat, 1) + } + + pub fn fund_signer_asset(&self, amount_sat: u64) -> Result { + self.fund_and_sync(self.signer_address(), RuntimeFundingAsset::IssuedAsset, amount_sat, 1) + } + + pub fn simf_finalizer( + &self, + source_simf: impl Into, + arguments: &SimfArguments, + witness: &SimfWitness, + ) -> Result { + Ok(FinalizerSpec::Simf { + source_simf: source_simf.into(), + internal_key: InternalKeySource::Bip0341, + arguments: serialize_arguments(arguments)?, + witness: serialize_witness(witness)?, + }) + } + + pub fn evaluate_request(&self, request: TxEvaluateRequest) -> Result { + self.sync_wallet()?; + let provider = self.provider(); + self.run_async(move || async move { provider.evaluate_request(request).await }) + } + + pub fn process_request_response(&self, request: TxCreateRequest) -> Result { + self.sync_wallet()?; + let should_mine = request.broadcast; + let provider = self.provider(); + let response = self.run_async(move || async move { provider.process_request(request).await })?; + if should_mine { + self.mine_and_sync(1)?; + } + Ok(response) + } + + pub fn process_request(&self, request: TxCreateRequest) -> Result { + let response = self.process_request_response(request)?; + let tx = decode_transaction( + &response + .transaction + .ok_or_else(|| TestError::WalletAbiInvariant("missing transaction info".to_string()))?, + )?; + Ok(tx) + } + + pub fn find_output(&self, tx: &Transaction, predicate: impl Fn(&TxOut) -> bool) -> Result { + let mut matches = tx + .output + .iter() + .enumerate() + .filter_map(|(vout, tx_out)| predicate(tx_out).then_some((vout as u32, tx_out.clone()))) + .collect::>(); + + if matches.len() != 1 { + return Err(TestError::WalletAbiInvariant(format!( + "expected exactly one matching output, found {}", + matches.len() + ))); + } + + let (vout, tx_out) = matches.remove(0); + let unblinded = self.shared.unblind_known_txout(&tx_out).ok(); + Ok(KnownUtxo { + outpoint: OutPoint::new(tx.txid(), vout), + tx_out, + unblinded, + }) + } + + fn run_async(&self, make_future: F) -> Result + where + Fut: Future>, + F: FnOnce() -> Fut, + { + Ok(futures::executor::block_on(make_future())?) + } +} + +#[derive(Clone)] +pub struct WalletAbiSignerAdapter { + shared: Arc, +} + +impl KeyStoreMeta for WalletAbiSignerAdapter { + type Error = WalletAbiAdapterError; + + fn get_raw_signing_x_only_pubkey(&self) -> Result { + self.shared.signer_xonly() + } + + fn sign_pst(&self, pst: &mut PartiallySignedTransaction) -> Result<(), Self::Error> { + self.shared.signer.sign(pst)?; + Ok(()) + } + + fn sign_schnorr(&self, message: Message, xonly_public_key: XOnlyPublicKey) -> Result { + let (keypair, expected_xonly) = self.shared.signing_keypair()?; + if xonly_public_key != expected_xonly { + return Err(WalletAbiAdapterError::XOnlyKeyMismatch); + } + Ok(keypair.sign_schnorr(message)) + } +} + +#[derive(Clone)] +pub struct WalletAbiSessionFactoryAdapter { + shared: Arc, +} + +impl WalletAbiSessionFactoryAdapter { + pub fn open_wallet_request_session_sync(&self) -> Result { + self.shared.open_wallet_request_session() + } +} + +impl WalletSessionFactory for WalletAbiSessionFactoryAdapter { + type Error = WalletAbiAdapterError; + + async fn open_wallet_request_session(&self) -> Result { + self.open_wallet_request_session_sync() + } +} + +#[derive(Clone)] +pub struct WalletAbiPrevoutResolverAdapter { + shared: Arc, +} + +impl WalletPrevoutResolver for WalletAbiPrevoutResolverAdapter { + type Error = WalletAbiAdapterError; + + fn get_bip32_derivation_pair(&self, out_point: &OutPoint) -> Result, Self::Error> { + self.shared.wallet_bip32_pair(out_point) + } + + fn unblind(&self, tx_out: &TxOut) -> Result { + self.shared.unblind_txout(tx_out) + } + + async fn get_tx_out(&self, outpoint: OutPoint) -> Result { + self.shared.fetch_tx_out(outpoint) + } +} + +#[derive(Clone)] +pub struct WalletAbiOutputAllocatorAdapter { + shared: Arc, +} + +impl WalletOutputAllocator for WalletAbiOutputAllocatorAdapter { + type Error = WalletAbiAdapterError; + + fn get_wallet_output_template( + &self, + _session: &WalletRequestSession, + request: &WalletOutputRequest, + ) -> Result { + self.shared.output_template(request) + } +} + +#[derive(Clone)] +pub struct WalletAbiBroadcasterAdapter { + shared: Arc, +} + +impl WalletBroadcaster for WalletAbiBroadcasterAdapter { + type Error = WalletAbiAdapterError; + + fn broadcast_transaction(&self, tx: &Transaction) -> impl Future> + Send + '_ { + let tx = tx.clone(); + async move { self.shared.broadcast(&tx) } + } +} + +#[derive(Clone)] +pub struct WalletAbiReceiveAddressProviderAdapter { + shared: Arc, +} + +impl WalletReceiveAddressProvider for WalletAbiReceiveAddressProviderAdapter { + type Error = WalletAbiAdapterError; + + fn get_signer_receive_address(&self) -> Result { + self.shared.receive_address() + } +} + +#[derive(Clone)] +pub struct WalletAbiSplitProvider { + pub prevout_resolver: WalletAbiPrevoutResolverAdapter, + pub output_allocator: WalletAbiOutputAllocatorAdapter, + pub broadcaster: WalletAbiBroadcasterAdapter, +} + +impl lwk_simplicity::wallet_abi::WalletProviderMeta for WalletAbiSplitProvider { + type Error = WalletAbiAdapterError; + + fn get_bip32_derivation_pair(&self, out_point: &OutPoint) -> Result, Self::Error> { + self.prevout_resolver.get_bip32_derivation_pair(out_point) + } + + fn unblind(&self, tx_out: &TxOut) -> Result { + self.prevout_resolver.unblind(tx_out) + } + + async fn get_tx_out(&self, outpoint: OutPoint) -> Result { + self.prevout_resolver.get_tx_out(outpoint).await + } + + fn get_wallet_output_template( + &self, + session: &WalletRequestSession, + request: &WalletOutputRequest, + ) -> Result { + self.output_allocator.get_wallet_output_template(session, request) + } + + fn broadcast_transaction(&self, tx: &Transaction) -> impl Future> + Send + '_ { + let tx = tx.clone(); + async move { self.broadcaster.broadcast_transaction(&tx).await } + } +} + +struct WalletAbiSharedState { + account_index: u32, + network: ElementsNetwork, + signer: SwSigner, + descriptor: WolletDescriptor, + wallet: Mutex, + esplora: Mutex, + rpc: Option<(String, Auth)>, +} + +impl WalletAbiSharedState { + fn lock_wallet(&self) -> Result, WalletAbiAdapterError> { + self.wallet + .lock() + .map_err(|_| WalletAbiAdapterError::LockPoisoned("wallet")) + } + + fn lock_esplora(&self) -> Result, WalletAbiAdapterError> { + self.esplora + .lock() + .map_err(|_| WalletAbiAdapterError::LockPoisoned("esplora")) + } + + fn rpc_client(&self) -> Result { + let (url, auth) = self.rpc.as_ref().ok_or(WalletAbiAdapterError::MissingRpc)?; + Ok(Client::new(url, auth.clone())?) + } + + fn sync_wallet(&self) -> Result<(), WalletAbiAdapterError> { + let state = { + let wallet = self.lock_wallet()?; + wallet.state() + }; + let update = { + let mut esplora = self.lock_esplora()?; + esplora.full_scan(&state)? + }; + if let Some(update) = update { + let mut wallet = self.lock_wallet()?; + wallet.apply_update(update)?; + } + Ok(()) + } + + fn current_height(&self) -> Result { + self.sync_wallet()?; + let wallet = self.lock_wallet()?; + Ok(wallet.tip().height()) + } + + fn receive_address(&self) -> Result { + let wallet = self.lock_wallet()?; + Ok(wallet.address(None)?.address().clone()) + } + + fn generate_blocks(&self, blocks: u32) -> Result<(), WalletAbiAdapterError> { + let rpc = self.rpc_client()?; + let address = rpc + .call::("getnewaddress", &["".into(), "bech32".into()])? + .as_str() + .ok_or_else(|| WalletAbiAdapterError::Invariant("missing getnewaddress result".to_string()))? + .to_string(); + rpc.call::("generatetoaddress", &[blocks.into(), address.into()])?; + Ok(()) + } + + fn broadcast(&self, tx: &Transaction) -> Result { + let esplora = self.lock_esplora()?; + Ok(esplora.broadcast(tx)?) + } + + fn fetch_transaction(&self, txid: &Txid) -> Result { + let esplora = self.lock_esplora()?; + let txs = esplora.get_transactions(&[*txid])?; + txs.into_iter() + .next() + .ok_or_else(|| WalletAbiAdapterError::Invariant(format!("transaction {txid} not found"))) + } + + fn fetch_tx_out(&self, outpoint: OutPoint) -> Result { + let tx = self.fetch_transaction(&outpoint.txid)?; + tx.output + .get(outpoint.vout as usize) + .cloned() + .ok_or(WalletAbiAdapterError::MissingTxOutput { + txid: outpoint.txid, + vout: outpoint.vout, + }) + } + + fn wallet_snapshot(&self) -> Result, WalletAbiAdapterError> { + self.sync_wallet()?; + let (utxos, is_segwit, max_weight) = { + let wallet = self.lock_wallet()?; + (wallet.utxos()?, wallet.is_segwit(), wallet.max_weight_to_satisfy()) + }; + utxos + .into_iter() + .map(|utxo| { + let tx = self.fetch_transaction(&utxo.outpoint.txid)?; + let txout = tx.output.get(utxo.outpoint.vout as usize).cloned().ok_or( + WalletAbiAdapterError::MissingTxOutput { + txid: utxo.outpoint.txid, + vout: utxo.outpoint.vout, + }, + )?; + Ok(ExternalUtxo { + outpoint: utxo.outpoint, + txout, + tx: (!is_segwit).then_some(tx), + unblinded: utxo.unblinded, + max_weight_to_satisfy: max_weight, + }) + }) + .collect() + } + + fn open_wallet_request_session(&self) -> Result { + Ok(WalletRequestSession { + session_id: lwk_simplicity::wallet_abi::generate_request_id().to_string(), + network: self.network, + spendable_utxos: Arc::from(self.wallet_snapshot()?), + }) + } + + fn wallet_bip32_pair(&self, out_point: &OutPoint) -> Result, WalletAbiAdapterError> { + let txos = { + let wallet = self.lock_wallet()?; + wallet.txos()? + }; + + let txo = match txos.into_iter().find(|txo| &txo.outpoint == out_point) { + Some(txo) => txo, + None => return Ok(None), + }; + + let coin_type = if matches!(self.network, ElementsNetwork::Liquid) { + 1776 + } else { + 1 + }; + let branch = match txo.ext_int { + Chain::External => 0, + Chain::Internal => 1, + }; + let path = DerivationPath::from_str(&format!( + "m/84h/{coin_type}h/{}h/{branch}/{}", + self.account_index, txo.wildcard_index + )) + .map_err(|error: lwk_wollet::bitcoin::bip32::Error| WalletAbiAdapterError::Invariant(error.to_string()))?; + let xpub = self.signer.derive_xpub(&path)?; + let fingerprint = self.signer.fingerprint(); + + Ok(Some((PublicKey::new(xpub.public_key), (fingerprint, path)))) + } + + fn signer_xonly(&self) -> Result { + Ok(self.signing_keypair()?.1) + } + + fn signing_keypair(&self) -> Result<(Keypair, XOnlyPublicKey), WalletAbiAdapterError> { + let coin_type = if matches!(self.network, ElementsNetwork::Liquid) { + 1776 + } else { + 1 + }; + let path = DerivationPath::from_str(&format!("m/86h/{coin_type}h/{}h/0/0", self.account_index)) + .map_err(|error: lwk_wollet::bitcoin::bip32::Error| WalletAbiAdapterError::Invariant(error.to_string()))?; + let xprv = self.signer.derive_xprv(&path)?; + let keypair = Keypair::from_secret_key(&lwk_wollet::EC, &xprv.private_key); + let xonly = keypair.x_only_public_key().0; + Ok((keypair, xonly)) + } + + fn unblind_txout(&self, tx_out: &TxOut) -> Result { + match (tx_out.asset, tx_out.value, tx_out.nonce) { + (ConfidentialAsset::Explicit(asset), Value::Explicit(value), _) => Ok(TxOutSecrets::new( + asset, + lwk_wollet::elements::confidential::AssetBlindingFactor::zero(), + value, + lwk_wollet::elements::confidential::ValueBlindingFactor::zero(), + )), + (ConfidentialAsset::Confidential(_), Value::Confidential(_), Nonce::Confidential(_)) => { + let secret_key = + lwk_common::derive_blinding_key(self.descriptor.ct_descriptor()?, &tx_out.script_pubkey) + .ok_or_else(|| WalletAbiAdapterError::Invariant("missing blinding key".to_string()))?; + Ok(tx_out.unblind(&lwk_wollet::EC, secret_key)?) + } + _ => Err(WalletAbiAdapterError::Invariant( + "received unconfidential or null asset/value/nonce".to_string(), + )), + } + } + + fn unblind_known_txout(&self, tx_out: &TxOut) -> Result { + match (tx_out.asset, tx_out.value) { + (ConfidentialAsset::Explicit(asset), Value::Explicit(value)) => Ok(TxOutSecrets::new( + asset, + lwk_wollet::elements::confidential::AssetBlindingFactor::zero(), + value, + lwk_wollet::elements::confidential::ValueBlindingFactor::zero(), + )), + _ => self.unblind_txout(tx_out), + } + } + + fn output_template(&self, request: &WalletOutputRequest) -> Result { + let wallet = self.lock_wallet()?; + let address = match request { + WalletOutputRequest::Receive { index } => wallet.address(Some(*index))?.address().clone(), + WalletOutputRequest::Change { index, .. } => wallet.change(Some(*index))?.address().clone(), + }; + Ok(WalletOutputTemplate { + script_pubkey: address.script_pubkey(), + blinding_pubkey: address.blinding_pubkey, + }) + } + + fn fund_address( + &self, + address: &Address, + asset: RuntimeFundingAsset, + amount_sat: u64, + ) -> Result { + let rpc = self.rpc_client()?; + let (funded_asset, txid) = match asset { + RuntimeFundingAsset::Lbtc => ( + self.network.policy_asset(), + send_to_address(&rpc, address, amount_sat, None)?, + ), + RuntimeFundingAsset::IssuedAsset => { + let issued = issue_asset(&rpc, amount_sat)?; + let txid = send_to_address(&rpc, address, amount_sat, Some(issued))?; + (issued, txid) + } + }; + let tx = get_raw_transaction(&rpc, &txid)?; + self.find_funded_output(&tx, address, funded_asset, amount_sat) + .map_err(TestError::from) + } + + fn find_funded_output( + &self, + tx: &Transaction, + address: &Address, + asset_id: AssetId, + amount_sat: u64, + ) -> Result { + let script_pubkey = address.script_pubkey(); + let mut matches = Vec::new(); + + for (vout, tx_out) in tx.output.iter().enumerate() { + if tx_out.script_pubkey != script_pubkey { + continue; + } + + let secrets = self.unblind_txout(tx_out)?; + if secrets.asset == asset_id && secrets.value == amount_sat { + matches.push((vout as u32, tx_out.clone())); + } + } + + if matches.len() != 1 { + return Err(WalletAbiAdapterError::Invariant(format!( + "expected exactly one funded output, found {}", + matches.len() + ))); + } + let (vout, tx_out) = matches.remove(0); + let unblinded = self.unblind_known_txout(&tx_out)?; + Ok(KnownUtxo { + outpoint: OutPoint::new(tx.txid(), vout), + tx_out, + unblinded: Some(unblinded), + }) + } +} + +fn send_to_address( + rpc: &Client, + address: &Address, + amount_sat: u64, + asset: Option, +) -> Result { + let btc = (amount_sat as f64) / 100_000_000.0; + let value = match asset { + Some(asset) => rpc.call::( + "sendtoaddress", + &[ + address.to_string().into(), + btc.into(), + "".into(), + "".into(), + false.into(), + false.into(), + 1.into(), + "UNSET".into(), + false.into(), + asset.to_string().into(), + ], + )?, + None => rpc.call::("sendtoaddress", &[address.to_string().into(), btc.into()])?, + }; + let txid = value + .as_str() + .ok_or_else(|| WalletAbiAdapterError::Invariant("missing sendtoaddress txid".to_string()))?; + txid.parse::() + .map_err(|error| WalletAbiAdapterError::Invariant(error.to_string())) +} + +fn issue_asset(rpc: &Client, amount_sat: u64) -> Result { + let btc = (amount_sat as f64) / 100_000_000.0; + let value = rpc.call::("issueasset", &[btc.into(), 0.into()])?; + let asset = value + .get("asset") + .and_then(serde_json::Value::as_str) + .ok_or_else(|| WalletAbiAdapterError::Invariant("missing issueasset asset id".to_string()))?; + asset + .parse::() + .map_err(|error| WalletAbiAdapterError::Invariant(error.to_string())) +} + +fn get_raw_transaction(rpc: &Client, txid: &Txid) -> Result { + let value = rpc.call::("getrawtransaction", &[txid.to_string().into(), false.into()])?; + let tx_hex = value + .as_str() + .ok_or_else(|| WalletAbiAdapterError::Invariant("missing getrawtransaction hex".to_string()))?; + let bytes = Vec::::from_hex(tx_hex).map_err(|error| WalletAbiAdapterError::Decode(error.to_string()))?; + deserialize(&bytes).map_err(|error| WalletAbiAdapterError::Decode(error.to_string())) +} + +fn decode_transaction(info: &TransactionInfo) -> Result { + let bytes = + Vec::::from_hex(info.tx_hex.as_str()).map_err(|error| TestError::WalletAbiInvariant(error.to_string()))?; + deserialize(&bytes).map_err(|error| TestError::WalletAbiInvariant(error.to_string())) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tx_builder_build_create_uses_wallet_abi_defaults() { + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .build_create() + .expect("request"); + + assert_eq!(request.network, ElementsNetwork::Liquid); + assert!(request.params.inputs.is_empty()); + assert!(request.params.outputs.is_empty()); + assert_eq!(request.params.fee_rate_sat_kvb, Some(100.0)); + assert_eq!(request.params.lock_time, None); + assert!(request.broadcast); + assert_eq!(request.abi_version, TX_CREATE_ABI_VERSION); + } + + #[test] + fn tx_builder_adds_wallet_input_exact() { + let network = ElementsNetwork::Liquid; + let request = WalletAbiRequestBuilder::new(network) + .wallet_input_exact("wallet-input", network.policy_asset(), 50_000) + .build_create() + .expect("request"); + + assert_eq!(request.params.inputs.len(), 1); + let input = &request.params.inputs[0]; + assert_eq!(input.id, "wallet-input"); + assert_eq!(input.unblinding, InputUnblinding::Wallet); + assert_eq!(input.sequence, ElementsSequence::ENABLE_LOCKTIME_NO_RBF); + assert_eq!(input.issuance, None); + assert_eq!(input.finalizer, FinalizerSpec::Wallet); + assert_eq!( + input.utxo_source, + UTXOSource::Wallet { + filter: WalletSourceFilter { + asset: AssetFilter::Exact { + asset_id: network.policy_asset(), + }, + amount: AmountFilter::Exact { amount_sat: 50_000 }, + lock: LockFilter::None, + }, + } + ); + } + + #[test] + fn tx_builder_adds_provided_input() { + let known_utxo = KnownUtxo { + outpoint: OutPoint::default(), + tx_out: TxOut::default(), + unblinded: None, + }; + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .provided_input( + "provided-input", + &known_utxo, + InputUnblinding::Explicit, + FinalizerSpec::Wallet, + ) + .build_create() + .expect("request"); + + assert_eq!(request.params.inputs.len(), 1); + let input = &request.params.inputs[0]; + assert_eq!(input.id, "provided-input"); + assert_eq!( + input.utxo_source, + UTXOSource::Provided { + outpoint: OutPoint::default(), + } + ); + assert_eq!(input.unblinding, InputUnblinding::Explicit); + assert_eq!(input.sequence, ElementsSequence::ENABLE_LOCKTIME_NO_RBF); + assert_eq!(input.issuance, None); + assert_eq!(input.finalizer, FinalizerSpec::Wallet); + } + + #[test] + fn tx_builder_sets_new_issuance_on_named_input() { + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .wallet_input_exact("issuance-input", ElementsNetwork::Liquid.policy_asset(), 100_000) + .new_issuance("issuance-input", 50_000, 0, [7; 32]) + .expect("builder") + .build_create() + .expect("request"); + + assert_eq!( + request.params.inputs[0].issuance, + Some(InputIssuance { + kind: InputIssuanceKind::New, + asset_amount_sat: 50_000, + token_amount_sat: 0, + entropy: [7; 32], + }) + ); + } + + #[test] + fn tx_builder_adds_explicit_output() { + let script = Script::new(); + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .explicit_output( + "recipient", + script.clone(), + ElementsNetwork::Liquid.policy_asset(), + 50_000, + ) + .build_create() + .expect("request"); + + assert_eq!( + request.params.outputs, + vec![OutputSchema { + id: "recipient".to_string(), + amount_sat: 50_000, + lock: LockVariant::Script { script }, + asset: AssetVariant::AssetId { + asset_id: ElementsNetwork::Liquid.policy_asset(), + }, + blinder: BlinderVariant::Explicit, + }] + ); + } + + #[test] + fn tx_builder_adds_new_issuance_asset_output() { + let script = Script::new(); + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .new_issuance_asset_output("issued", script.clone(), 2, 25_000) + .build_create() + .expect("request"); + + assert_eq!( + request.params.outputs, + vec![OutputSchema { + id: "issued".to_string(), + amount_sat: 25_000, + lock: LockVariant::Script { script }, + asset: AssetVariant::NewIssuanceAsset { input_index: 2 }, + blinder: BlinderVariant::Explicit, + }] + ); + } + + #[test] + fn tx_builder_adds_finalizer_output() { + let finalizer = FinalizerSpec::Simf { + source_simf: "unit.simf".to_string(), + internal_key: InternalKeySource::Bip0341, + arguments: vec![1], + witness: vec![2], + }; + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .finalizer_output( + "locked", + finalizer.clone(), + ElementsNetwork::Liquid.policy_asset(), + 10_000, + ) + .build_create() + .expect("request"); + + assert_eq!( + request.params.outputs, + vec![OutputSchema { + id: "locked".to_string(), + amount_sat: 10_000, + lock: LockVariant::Finalizer { + finalizer: Box::new(finalizer), + }, + asset: AssetVariant::AssetId { + asset_id: ElementsNetwork::Liquid.policy_asset(), + }, + blinder: BlinderVariant::Explicit, + }] + ); + } + + #[test] + fn tx_builder_sets_lock_time_from_height() { + let request = WalletAbiRequestBuilder::new(ElementsNetwork::Liquid) + .lock_time_height(42) + .expect("builder") + .build_create() + .expect("request"); + + assert_eq!( + request.params.lock_time, + Some(lwk_wollet::elements::LockTime::from_height(42).expect("height lock")), + ); + } +}