diff --git a/Cargo.lock b/Cargo.lock index 121d9bc..4b5dc53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,7 +49,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "version_check", ] @@ -109,9 +109,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "argon2" @@ -164,7 +164,7 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -200,7 +200,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -242,8 +242,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", + "bitcoin-internals", + "bitcoin_hashes 0.14.1", ] [[package]] @@ -290,7 +290,7 @@ dependencies = [ "bip39", "bitcoin 0.30.2", "electrum-client", - "getrandom 0.2.16", + "getrandom 0.2.17", "js-sys", "log", "miniscript", @@ -320,9 +320,9 @@ checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] name = "bech32" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bip32" @@ -345,11 +345,11 @@ dependencies = [ [[package]] name = "bip39" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" +checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes 0.14.1", "rand 0.8.5", "rand_core 0.6.4", "serde", @@ -373,17 +373,17 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.32.7" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ "base58ck", - "bech32 0.11.0", - "bitcoin-internals 0.3.0", + "bech32 0.11.1", + "bitcoin-internals", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", + "bitcoin_hashes 0.14.1", + "hex-conservative", "hex_lit", "secp256k1 0.29.1", "serde", @@ -397,7 +397,7 @@ checksum = "1d59480a0145d7695f784675d7414830e12e95f0f71010ca41ec93617c5d3171" dependencies = [ "bip32", "bip39", - "bitcoin 0.32.7", + "bitcoin 0.32.8", "hex", "secp256k1 0.30.0", "serde", @@ -406,12 +406,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "bitcoin-internals" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" - [[package]] name = "bitcoin-internals" version = "0.3.0" @@ -423,9 +417,9 @@ dependencies = [ [[package]] name = "bitcoin-io" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] name = "bitcoin-private" @@ -439,7 +433,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" dependencies = [ - "bitcoin-internals 0.3.0", + "bitcoin-internals", "serde", ] @@ -455,22 +449,12 @@ dependencies = [ [[package]] name = "bitcoin_hashes" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" -dependencies = [ - "bitcoin-internals 0.2.0", - "hex-conservative 0.1.2", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ "bitcoin-io", - "hex-conservative 0.2.1", + "hex-conservative", "serde", ] @@ -482,23 +466,23 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ "serde_core", ] [[package]] name = "bitkitcore" -version = "0.1.42" +version = "0.1.44" dependencies = [ "android_logger", "async-trait", "base64 0.22.1", "bdk", "bip39", - "bitcoin 0.32.7", + "bitcoin 0.32.8", "bitcoin-address-generator", "btleplug", "chrono", @@ -524,7 +508,7 @@ dependencies = [ "serial_test", "tempfile", "test-case", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "trezor-connect-rs", "uniffi", @@ -600,7 +584,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84ae4213cc2a8dc663acecac67bbdad05142be4d8ef372b6903abf878b0c690a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bluez-generated", "dbus", "dbus-tokio", @@ -609,7 +593,7 @@ dependencies = [ "log", "serde", "serde-xml-rs", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "uuid", ] @@ -625,9 +609,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", "cfg_aliases", @@ -635,15 +619,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -662,7 +646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9a11621cb2c8c024e444734292482b1ad86fb50ded066cf46252e46643c8748" dependencies = [ "async-trait", - "bitflags 2.10.0", + "bitflags 2.11.0", "bluez-async", "dashmap 6.1.0", "dbus", @@ -675,7 +659,7 @@ dependencies = [ "objc2-foundation", "once_cell", "static_assertions", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "uuid", @@ -685,9 +669,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytecheck" @@ -719,15 +703,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "camino" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ "serde_core", ] @@ -752,7 +736,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -766,9 +750,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -794,9 +778,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", @@ -819,9 +803,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.51" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -829,9 +813,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.51" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstyle", "clap_lex", @@ -840,21 +824,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cobs" @@ -862,7 +846,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -900,9 +884,9 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.21.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" dependencies = [ "cookie", "document-features", @@ -926,16 +910,6 @@ dependencies = [ "tracing", ] -[[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" version = "0.10.1" @@ -1029,9 +1003,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1086,7 +1060,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -1185,7 +1159,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -1376,9 +1350,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixedbitset" @@ -1388,9 +1362,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1408,10 +1382,10 @@ dependencies = [ ] [[package]] -name = "fnv" -version = "1.0.7" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "foreign-types" @@ -1464,9 +1438,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1492,9 +1466,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1502,15 +1476,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1519,9 +1493,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -1538,32 +1512,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1573,7 +1547,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1619,9 +1592,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1630,9 +1603,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1650,11 +1623,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "ghash" version = "0.5.1" @@ -1722,9 +1708,18 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hashlink" @@ -1761,7 +1756,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd54745cfacb7b97dee45e8fdb91814b62bccddb481debb7de0f9ee6b7bf5b43" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "byteorder", "heed-traits", "heed-types", @@ -1797,15 +1792,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" - -[[package]] -name = "hex-conservative" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" dependencies = [ "arrayvec", ] @@ -1836,12 +1825,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1882,9 +1870,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", @@ -1910,13 +1898,13 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] @@ -1937,14 +1925,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -1961,9 +1948,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2031,9 +2018,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -2045,9 +2032,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -2064,6 +2051,12 @@ dependencies = [ "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" @@ -2087,12 +2080,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -2116,15 +2111,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -2141,9 +2136,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jni" @@ -2182,9 +2177,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -2204,9 +2199,9 @@ dependencies = [ [[package]] name = "lazy-regex" -version = "3.4.2" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" +checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -2215,14 +2210,14 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.4.2" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" +checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -2231,11 +2226,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.177" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libdbus-sys" @@ -2276,7 +2277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ab9f6ea77e20e3129235e62a2e6bd64ed932363df104e864ee65ccffb54a8f" dependencies = [ "bech32 0.9.1", - "bitcoin 0.32.7", + "bitcoin 0.32.8", "lightning-types", ] @@ -2287,15 +2288,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1083b8d9137000edf3bfcb1ff011c0d25e0cdd2feb98cc21d6765e64a494148f" dependencies = [ "bech32 0.9.1", - "bitcoin 0.32.7", - "hex-conservative 0.2.1", + "bitcoin 0.32.8", + "hex-conservative", ] [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -2329,8 +2330,8 @@ dependencies = [ "aes", "anyhow", "base64 0.22.1", - "bech32 0.11.0", - "bitcoin 0.32.7", + "bech32 0.11.1", + "bitcoin 0.32.8", "cbc", "email_address", "reqwest", @@ -2351,9 +2352,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "loom" @@ -2392,13 +2393,13 @@ dependencies = [ "ed25519-dalek", "flume", "futures-lite", - "getrandom 0.2.16", + "getrandom 0.2.17", "lru", "serde", "serde_bencode", "serde_bytes", "sha1_smol", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] @@ -2413,9 +2414,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "minimal-lexical" @@ -2446,9 +2447,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -2463,9 +2464,9 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -2473,7 +2474,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] @@ -2496,7 +2497,7 @@ checksum = "c50f94c405726d3e0095e89e72f75ce7f6587b94a8bd8dc8054b73f65c0fd68c" dependencies = [ "base32", "document-features", - "getrandom 0.2.16", + "getrandom 0.2.17", "httpdate", "js-sys", "once_cell", @@ -2568,7 +2569,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a644b62ffb826a5277f536cf0f701493de420b13d40e700c452c36567771111" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "objc2", "objc2-foundation", ] @@ -2585,7 +2586,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "libc", "objc2", @@ -2605,11 +2606,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.74" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "foreign-types", "libc", @@ -2626,29 +2627,29 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.5.4+3.5.4" +version = "300.5.5+3.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" +checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -2788,7 +2789,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -2802,9 +2803,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -2829,7 +2830,7 @@ dependencies = [ "futures-buffered", "futures-lite", "genawaiter", - "getrandom 0.2.16", + "getrandom 0.2.17", "heed", "log", "lru", @@ -2837,13 +2838,13 @@ dependencies = [ "ntimestamp", "page_size", "reqwest", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-webpki 0.102.8", "self_cell", "serde", "sha1_smol", "simple-dns", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -2939,23 +2940,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2986,7 +2987,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.109", + "syn 2.0.117", "tempfile", ] @@ -3000,7 +3001,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -3054,7 +3055,7 @@ dependencies = [ "pkarr", "pubky-common", "reqwest", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -3080,7 +3081,7 @@ dependencies = [ "pubky-timestamp", "rand 0.9.2", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", ] @@ -3092,7 +3093,7 @@ checksum = "44aafc63c1eab1905e8a8378d2b085500540c9935b6d028908c8a50a5a246a3d" dependencies = [ "base32", "document-features", - "getrandom 0.2.16", + "getrandom 0.2.17", "httpdate", "js-sys", "once_cell", @@ -3121,9 +3122,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.37", "socket2", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -3141,10 +3142,10 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -3166,9 +3167,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -3179,6 +3180,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "r2d2" version = "0.8.10" @@ -3225,7 +3232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3245,7 +3252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3254,14 +3261,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -3281,14 +3288,14 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3298,9 +3305,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3309,9 +3316,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rend" @@ -3324,9 +3331,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", @@ -3346,7 +3353,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-pki-types", "serde", @@ -3363,7 +3370,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] @@ -3384,7 +3391,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3401,9 +3408,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -3419,9 +3426,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -3444,7 +3451,7 @@ version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -3462,16 +3469,16 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "url", ] [[package]] name = "rust_decimal" -version = "1.39.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ "arrayvec", "borsh", @@ -3500,11 +3507,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", @@ -3525,35 +3532,35 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -3582,9 +3589,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -3599,9 +3606,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "salsa20" @@ -3677,7 +3684,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -3733,7 +3740,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes 0.14.1", "rand 0.8.5", "secp256k1-sys 0.10.1", "serde", @@ -3745,7 +3752,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes 0.14.1", "rand 0.8.5", "secp256k1-sys 0.10.1", ] @@ -3770,25 +3777,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.1", + "bitflags 2.11.0", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", @@ -3796,9 +3790,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -3838,7 +3832,7 @@ checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" dependencies = [ "log", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "xml", ] @@ -3879,20 +3873,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -3909,11 +3903,12 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f" dependencies = [ - "futures", + "futures-executor", + "futures-util", "log", "once_cell", "parking_lot 0.12.5", @@ -3923,13 +3918,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -3966,10 +3961,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3985,9 +3981,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "simdutf8" @@ -4001,7 +3997,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -4018,9 +4014,9 @@ checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "sled" @@ -4052,9 +4048,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -4133,9 +4129,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.109" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4168,7 +4164,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -4179,12 +4175,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4208,7 +4204,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -4219,7 +4215,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", "test-case-core", ] @@ -4243,11 +4239,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -4258,18 +4254,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -4339,9 +4335,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -4356,13 +4352,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -4381,7 +4377,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.37", "tokio", ] @@ -4421,18 +4417,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "1.0.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.7" +version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ "indexmap", "toml_datetime", @@ -4442,18 +4438,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -4466,11 +4462,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "futures-util", "http", @@ -4496,9 +4492,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -4513,14 +4509,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -4539,9 +4535,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -4557,14 +4553,14 @@ dependencies = [ [[package]] name = "trezor-connect-rs" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d1fb22b5b5d47cdf083ce5a02e3b50c625fdc81333278999e75f8ef5ad6320" +checksum = "3537d53e297065072664de30fe55607fe8e9cebc09ec3d7469d2490c3d9d29ba" dependencies = [ "aes-gcm", "async-trait", "base64 0.22.1", - "bitcoin 0.32.7", + "bitcoin 0.32.8", "btleplug", "bytes", "futures", @@ -4603,9 +4599,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -4616,11 +4612,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "uniffi" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6d968cb62160c11f2573e6be724ef8b1b18a277aededd17033f8a912d73e2b4" +checksum = "3291800a6b06569f7d3e15bdb6dc235e0f0c8bd3eb07177f430057feb076415f" dependencies = [ "anyhow", "camino", @@ -4634,9 +4636,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b39ef1acbe1467d5d210f274fae344cb6f8766339330cb4c9688752899bf6b" +checksum = "a04b99fa7796eaaa7b87976a0dbdd1178dc1ee702ea00aca2642003aef9b669e" dependencies = [ "anyhow", "askama", @@ -4660,9 +4662,9 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d990b553d6b9a7ee9c3ae71134674739913d52350b56152b0e613595bb5a6f" +checksum = "f38a9a27529ccff732f8efddb831b65b1e07f7dea3fd4cacd4a35a8c4b253b98" dependencies = [ "anyhow", "bytes", @@ -4672,22 +4674,22 @@ dependencies = [ [[package]] name = "uniffi_internal_macros" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f4f224becf14885c10e6e400b95cc4d1985738140cb194ccc2044563f8a56b" +checksum = "09acd2ce09c777dd65ee97c251d33c8a972afc04873f1e3b21eb3492ade16933" dependencies = [ "anyhow", "indexmap", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] name = "uniffi_macros" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b481d385af334871d70904e6a5f129be7cd38c18fcf8dd8fd1f646b426a56d58" +checksum = "5596f178c4f7aafa1a501c4e0b96236a96bc2ef92bdb453d83e609dad0040152" dependencies = [ "camino", "fs-err", @@ -4695,16 +4697,16 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.109", + "syn 2.0.117", "toml", "uniffi_meta", ] [[package]] name = "uniffi_meta" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f817868a3b171bb7bf259e882138d104deafde65684689b4694c846d322491" +checksum = "beadc1f460eb2e209263c49c4f5b19e9a02e00a3b2b393f78ad10d766346ecff" dependencies = [ "anyhow", "siphasher 0.3.11", @@ -4714,9 +4716,9 @@ dependencies = [ [[package]] name = "uniffi_pipeline" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b147e133ad7824e32426b90bc41fda584363563f2ba747f590eca1fd6fd14e6" +checksum = "dd76b3ac8a2d964ca9fce7df21c755afb4c77b054a85ad7a029ad179cc5abb8a" dependencies = [ "anyhow", "heck", @@ -4727,9 +4729,9 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.29.4" +version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caed654fb73da5abbc7a7e9c741532284532ba4762d6fe5071372df22a41730a" +checksum = "4319cf905911d70d5b97ce0f46f101619a22e9a189c8c46d797a9955e9233716" dependencies = [ "anyhow", "textwrap", @@ -4774,14 +4776,15 @@ dependencies = [ [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -4792,11 +4795,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", "rand 0.9.2", "wasm-bindgen", @@ -4847,18 +4850,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -4869,11 +4881,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.55" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -4882,9 +4895,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4892,31 +4905,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -4959,9 +5006,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -5073,7 +5120,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -5084,7 +5131,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -5321,18 +5368,100 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -5386,28 +5515,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -5427,7 +5556,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", "synstructure", ] @@ -5448,7 +5577,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] [[package]] @@ -5481,5 +5610,11 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.117", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 9b9cbe3..7a5848e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitkitcore" -version = "0.1.42" +version = "0.1.44" edition = "2021" [lib] @@ -45,11 +45,11 @@ btleplug = "0.11" # Trezor connect library - non-iOS platforms get USB + Bluetooth [target.'cfg(not(target_os = "ios"))'.dependencies] -trezor-connect-rs = { version = "0.2.2", features = ["psbt"] } +trezor-connect-rs = { version = "0.2.3", features = ["psbt"] } # iOS: Bluetooth only (libusb has no iOS backend, so no USB support) [target.'cfg(target_os = "ios")'.dependencies] -trezor-connect-rs = { version = "0.2.2", default-features = false, features = ["bluetooth", "psbt"] } +trezor-connect-rs = { version = "0.2.3", default-features = false, features = ["bluetooth", "psbt"] } # JNI for Android (must match btleplug's jni version) [target.'cfg(target_os = "android")'.dependencies] diff --git a/Package.swift b/Package.swift index 417a194..d0fccdf 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.1.42" -let checksum = "2c7c01511b5c08efe97ce3fa5b417f5d0c8afc1ae2a40b4a099ae1e834b189a0" +let tag = "v0.1.44" +let checksum = "f1436a0df7f08f00d73087eb1991f96489cfbfc2dc859bba010b3417acb24aca" let url = "https://github.com/synonymdev/bitkit-core/releases/download/\(tag)/BitkitCore.xcframework.zip" let package = Package( diff --git a/README.md b/README.md index 5a9c2df..c5ac9eb 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ - Derive addresses for specified paths - Retrieve account information - Handle responses from Trezor devices + - Query account info from extended public keys (xpub/ypub/zpub) via Electrum + - Query single address balance and UTXOs via Electrum + - Compose and sign transactions ## Available Modules: Methods - Scanner @@ -436,6 +439,23 @@ common: Option, ) -> Result ``` + - [get_account_info_from_xpub](src/modules/trezor/README.md): Query account info from an extended public key via Electrum (no device required) + ```rust + async fn get_account_info_from_xpub( + extended_key: String, + electrum_url: String, + network: Option, + gap_limit: Option, + ) -> Result + ``` + - [get_address_info_from_address](src/modules/trezor/README.md): Query balance and UTXOs for a single Bitcoin address via Electrum (no device required) + ```rust + async fn get_address_info_from_address( + address: String, + electrum_url: String, + network: Option, + ) -> Result + ``` ## Building the Bindings diff --git a/bindings/android/gradle.properties b/bindings/android/gradle.properties index 8582c45..b0d068e 100644 --- a/bindings/android/gradle.properties +++ b/bindings/android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.1.42 +version=0.1.44 diff --git a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so index f9a2231..5cff0a6 100755 Binary files a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so index 14bf42b..ac3b78e 100755 Binary files a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so index 42c2258..b3e0f93 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so index be63c0a..e8bbae7 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt index ce2bb24..cf06af0 100644 --- a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt +++ b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt @@ -1374,6 +1374,20 @@ internal typealias UniffiVTableCallbackInterfaceTrezorUiCallbackUniffiByValue = + + + + + + + + + + + + + + @@ -1662,6 +1676,12 @@ internal object IntegrityCheckingUniffiLib : Library { if (uniffi_bitkitcore_checksum_func_test_notification() != 32857.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type() != 48918.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx() != 15100.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_trezor_clear_credentials() != 41940.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1671,9 +1691,18 @@ internal object IntegrityCheckingUniffiLib : Library { if (uniffi_bitkitcore_checksum_func_trezor_disconnect() != 48780.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs() != 46921.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (uniffi_bitkitcore_checksum_func_trezor_get_account_info() != 1783.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_trezor_get_address() != 12910.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_trezor_get_address_info() != 1337.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_trezor_get_connected_device() != 48383.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1701,6 +1730,12 @@ internal object IntegrityCheckingUniffiLib : Library { if (uniffi_bitkitcore_checksum_func_trezor_list_devices() != 32859.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_trezor_precompose_transaction() != 56637.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params() != 30193.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_trezor_scan() != 54763.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2056,6 +2091,12 @@ internal object IntegrityCheckingUniffiLib : Library { external fun uniffi_bitkitcore_checksum_func_test_notification( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type( + ): Short + @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_trezor_clear_credentials( ): Short @JvmStatic @@ -2065,9 +2106,18 @@ internal object IntegrityCheckingUniffiLib : Library { external fun uniffi_bitkitcore_checksum_func_trezor_disconnect( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs( + ): Short + @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_get_account_info( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_trezor_get_address( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_get_address_info( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_trezor_get_connected_device( ): Short @JvmStatic @@ -2095,6 +2145,12 @@ internal object IntegrityCheckingUniffiLib : Library { external fun uniffi_bitkitcore_checksum_func_trezor_list_devices( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_precompose_transaction( + ): Short + @JvmStatic + external fun uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_trezor_scan( ): Short @JvmStatic @@ -2767,6 +2823,16 @@ internal object UniffiLib : Library { `customUrl`: RustBufferByValue, ): Long @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type( + `accountType`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx( + `serializedTx`: RustBufferByValue, + `electrumUrl`: RustBufferByValue, + ): Long + @JvmStatic external fun uniffi_bitkitcore_fn_func_trezor_clear_credentials( `deviceId`: RustBufferByValue, ): Long @@ -2778,10 +2844,28 @@ internal object UniffiLib : Library { external fun uniffi_bitkitcore_fn_func_trezor_disconnect( ): Long @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs( + `txids`: RustBufferByValue, + `electrumUrl`: RustBufferByValue, + ): Long + @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_get_account_info( + `extendedKey`: RustBufferByValue, + `electrumUrl`: RustBufferByValue, + `network`: RustBufferByValue, + `gapLimit`: RustBufferByValue, + ): Long + @JvmStatic external fun uniffi_bitkitcore_fn_func_trezor_get_address( `params`: RustBufferByValue, ): Long @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_get_address_info( + `address`: RustBufferByValue, + `electrumUrl`: RustBufferByValue, + `network`: RustBufferByValue, + ): Long + @JvmStatic external fun uniffi_bitkitcore_fn_func_trezor_get_connected_device( ): Long @JvmStatic @@ -2812,6 +2896,18 @@ internal object UniffiLib : Library { external fun uniffi_bitkitcore_fn_func_trezor_list_devices( ): Long @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_precompose_transaction( + `params`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + @JvmStatic + external fun uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params( + `inputs`: RustBufferByValue, + `outputs`: RustBufferByValue, + `coin`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + @JvmStatic external fun uniffi_bitkitcore_fn_func_trezor_scan( ): Long @JvmStatic @@ -4368,6 +4464,83 @@ public object FfiConverterTypeAccountAddresses: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AccountInfoResult { + return AccountInfoResult( + FfiConverterTypeComposeAccount.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterTypeAccountType.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: AccountInfoResult): ULong = ( + FfiConverterTypeComposeAccount.allocationSize(value.`account`) + + FfiConverterULong.allocationSize(value.`balance`) + + FfiConverterUInt.allocationSize(value.`utxoCount`) + + FfiConverterTypeAccountType.allocationSize(value.`accountType`) + + FfiConverterUInt.allocationSize(value.`blockHeight`) + ) + + override fun write(value: AccountInfoResult, buf: ByteBuffer) { + FfiConverterTypeComposeAccount.write(value.`account`, buf) + FfiConverterULong.write(value.`balance`, buf) + FfiConverterUInt.write(value.`utxoCount`, buf) + FfiConverterTypeAccountType.write(value.`accountType`, buf) + FfiConverterUInt.write(value.`blockHeight`, buf) + } +} + + + + +public object FfiConverterTypeAccountUtxo: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AccountUtxo { + return AccountUtxo( + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + FfiConverterULong.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalBoolean.read(buf), + ) + } + + override fun allocationSize(value: AccountUtxo): ULong = ( + FfiConverterString.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + + FfiConverterULong.allocationSize(value.`amount`) + + FfiConverterUInt.allocationSize(value.`blockHeight`) + + FfiConverterString.allocationSize(value.`address`) + + FfiConverterString.allocationSize(value.`path`) + + FfiConverterUInt.allocationSize(value.`confirmations`) + + FfiConverterBoolean.allocationSize(value.`coinbase`) + + FfiConverterBoolean.allocationSize(value.`own`) + + FfiConverterOptionalBoolean.allocationSize(value.`required`) + ) + + override fun write(value: AccountUtxo, buf: ByteBuffer) { + FfiConverterString.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + FfiConverterULong.write(value.`amount`, buf) + FfiConverterUInt.write(value.`blockHeight`, buf) + FfiConverterString.write(value.`address`, buf) + FfiConverterString.write(value.`path`, buf) + FfiConverterUInt.write(value.`confirmations`, buf) + FfiConverterBoolean.write(value.`coinbase`, buf) + FfiConverterBoolean.write(value.`own`, buf) + FfiConverterOptionalBoolean.write(value.`required`, buf) + } +} + + + + public object FfiConverterTypeActivityTags: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): ActivityTags { return ActivityTags( @@ -4532,6 +4705,31 @@ public object FfiConverterTypeClosedChannelDetails: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ComposeAccount { + return ComposeAccount( + FfiConverterString.read(buf), + FfiConverterTypeAccountAddresses.read(buf), + FfiConverterSequenceTypeAccountUtxo.read(buf), + ) + } + + override fun allocationSize(value: ComposeAccount): ULong = ( + FfiConverterString.allocationSize(value.`path`) + + FfiConverterTypeAccountAddresses.allocationSize(value.`addresses`) + + FfiConverterSequenceTypeAccountUtxo.allocationSize(value.`utxo`) + ) + + override fun write(value: ComposeAccount, buf: ByteBuffer) { + FfiConverterString.write(value.`path`, buf) + FfiConverterTypeAccountAddresses.write(value.`addresses`, buf) + FfiConverterSequenceTypeAccountUtxo.write(value.`utxo`, buf) + } +} + + + + public object FfiConverterTypeCreateCjitOptions: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): CreateCjitOptions { return CreateCjitOptions( @@ -6197,6 +6395,37 @@ public object FfiConverterTypePubkyAuth: FfiConverterRustBuffer { +public object FfiConverterTypeSingleAddressInfoResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SingleAddressInfoResult { + return SingleAddressInfoResult( + FfiConverterString.read(buf), + FfiConverterULong.read(buf), + FfiConverterSequenceTypeAccountUtxo.read(buf), + FfiConverterUInt.read(buf), + FfiConverterUInt.read(buf), + ) + } + + override fun allocationSize(value: SingleAddressInfoResult): ULong = ( + FfiConverterString.allocationSize(value.`address`) + + FfiConverterULong.allocationSize(value.`balance`) + + FfiConverterSequenceTypeAccountUtxo.allocationSize(value.`utxos`) + + FfiConverterUInt.allocationSize(value.`transfers`) + + FfiConverterUInt.allocationSize(value.`blockHeight`) + ) + + override fun write(value: SingleAddressInfoResult, buf: ByteBuffer) { + FfiConverterString.write(value.`address`, buf) + FfiConverterULong.write(value.`balance`, buf) + FfiConverterSequenceTypeAccountUtxo.write(value.`utxos`, buf) + FfiConverterUInt.write(value.`transfers`, buf) + FfiConverterUInt.write(value.`blockHeight`, buf) + } +} + + + + public object FfiConverterTypeSweepResult: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): SweepResult { return SweepResult( @@ -6466,6 +6695,31 @@ public object FfiConverterTypeTrezorFeatures: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TrezorFeeLevel { + return TrezorFeeLevel( + FfiConverterString.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalBoolean.read(buf), + ) + } + + override fun allocationSize(value: TrezorFeeLevel): ULong = ( + FfiConverterString.allocationSize(value.`feePerUnit`) + + FfiConverterOptionalULong.allocationSize(value.`baseFee`) + + FfiConverterOptionalBoolean.allocationSize(value.`floorBaseFee`) + ) + + override fun write(value: TrezorFeeLevel, buf: ByteBuffer) { + FfiConverterString.write(value.`feePerUnit`, buf) + FfiConverterOptionalULong.write(value.`baseFee`, buf) + FfiConverterOptionalBoolean.write(value.`floorBaseFee`, buf) + } +} + + + + public object FfiConverterTypeTrezorGetAddressParams: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): TrezorGetAddressParams { return TrezorGetAddressParams( @@ -6519,6 +6773,74 @@ public object FfiConverterTypeTrezorGetPublicKeyParams: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TrezorPrecomposeParams { + return TrezorPrecomposeParams( + FfiConverterSequenceTypeTrezorPrecomposeOutput.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeComposeAccount.read(buf), + FfiConverterSequenceTypeTrezorFeeLevel.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalTypeTrezorSortingStrategy.read(buf), + ) + } + + override fun allocationSize(value: TrezorPrecomposeParams): ULong = ( + FfiConverterSequenceTypeTrezorPrecomposeOutput.allocationSize(value.`outputs`) + + FfiConverterString.allocationSize(value.`coin`) + + FfiConverterTypeComposeAccount.allocationSize(value.`account`) + + FfiConverterSequenceTypeTrezorFeeLevel.allocationSize(value.`feeLevels`) + + FfiConverterOptionalUInt.allocationSize(value.`sequence`) + + FfiConverterOptionalTypeTrezorSortingStrategy.allocationSize(value.`sortingStrategy`) + ) + + override fun write(value: TrezorPrecomposeParams, buf: ByteBuffer) { + FfiConverterSequenceTypeTrezorPrecomposeOutput.write(value.`outputs`, buf) + FfiConverterString.write(value.`coin`, buf) + FfiConverterTypeComposeAccount.write(value.`account`, buf) + FfiConverterSequenceTypeTrezorFeeLevel.write(value.`feeLevels`, buf) + FfiConverterOptionalUInt.write(value.`sequence`, buf) + FfiConverterOptionalTypeTrezorSortingStrategy.write(value.`sortingStrategy`, buf) + } +} + + + + +public object FfiConverterTypeTrezorPrecomposedInput: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TrezorPrecomposedInput { + return TrezorPrecomposedInput( + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeTrezorScriptType.read(buf), + ) + } + + override fun allocationSize(value: TrezorPrecomposedInput): ULong = ( + FfiConverterString.allocationSize(value.`txid`) + + FfiConverterUInt.allocationSize(value.`vout`) + + FfiConverterString.allocationSize(value.`amount`) + + FfiConverterString.allocationSize(value.`address`) + + FfiConverterString.allocationSize(value.`path`) + + FfiConverterTypeTrezorScriptType.allocationSize(value.`scriptType`) + ) + + override fun write(value: TrezorPrecomposedInput, buf: ByteBuffer) { + FfiConverterString.write(value.`txid`, buf) + FfiConverterUInt.write(value.`vout`, buf) + FfiConverterString.write(value.`amount`, buf) + FfiConverterString.write(value.`address`, buf) + FfiConverterString.write(value.`path`, buf) + FfiConverterTypeTrezorScriptType.write(value.`scriptType`, buf) + } +} + + + + public object FfiConverterTypeTrezorPrevTx: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): TrezorPrevTx { return TrezorPrevTx( @@ -6723,17 +7045,20 @@ public object FfiConverterTypeTrezorSignedTx: FfiConverterRustBuffer { + override fun lift(errorBuf: RustBufferByValue): AccountInfoException = FfiConverterTypeAccountInfoError.lift(errorBuf) +} -public object FfiConverterTypeActivity : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): Activity { - return when(buf.getInt()) { - 1 -> Activity.Onchain( - FfiConverterTypeOnchainActivity.read(buf), +public object FfiConverterTypeAccountInfoError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AccountInfoException { + return when (buf.getInt()) { + 1 -> AccountInfoException.InvalidExtendedKey( + FfiConverterString.read(buf), ) - 2 -> Activity.Lightning( - FfiConverterTypeLightningActivity.read(buf), + 2 -> AccountInfoException.InvalidAddress( + FfiConverterString.read(buf), ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") + 3 -> AccountInfoException.ElectrumException( + FfiConverterString.read(buf), + ) + 4 -> AccountInfoException.WalletException( + FfiConverterString.read(buf), + ) + 5 -> AccountInfoException.SyncException( + FfiConverterString.read(buf), + ) + 6 -> AccountInfoException.UnsupportedKeyType( + FfiConverterString.read(buf), + ) + 7 -> AccountInfoException.NetworkMismatch( + FfiConverterString.read(buf), + ) + 8 -> AccountInfoException.InvalidTxid( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") } } - override fun allocationSize(value: Activity): ULong = when(value) { - is Activity.Onchain -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( + override fun allocationSize(value: AccountInfoException): ULong { + return when (value) { + is AccountInfoException.InvalidExtendedKey -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL - + FfiConverterTypeOnchainActivity.allocationSize(value.v1) + + FfiConverterString.allocationSize(value.`errorDetails`) ) - } - is Activity.Lightning -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( + is AccountInfoException.InvalidAddress -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields 4UL - + FfiConverterTypeLightningActivity.allocationSize(value.v1) + + FfiConverterString.allocationSize(value.`errorDetails`) ) - } - } - - override fun write(value: Activity, buf: ByteBuffer) { - when(value) { - is Activity.Onchain -> { - buf.putInt(1) - FfiConverterTypeOnchainActivity.write(value.v1, buf) - Unit - } - is Activity.Lightning -> { - buf.putInt(2) - FfiConverterTypeLightningActivity.write(value.v1, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + is AccountInfoException.ElectrumException -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + is AccountInfoException.WalletException -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + is AccountInfoException.SyncException -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + is AccountInfoException.UnsupportedKeyType -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + is AccountInfoException.NetworkMismatch -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + is AccountInfoException.InvalidTxid -> ( + // Add the size for the Int that specifies the variant plus the size needed for all fields + 4UL + + FfiConverterString.allocationSize(value.`errorDetails`) + ) + } + } + + override fun write(value: AccountInfoException, buf: ByteBuffer) { + when (value) { + is AccountInfoException.InvalidExtendedKey -> { + buf.putInt(1) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.InvalidAddress -> { + buf.putInt(2) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.ElectrumException -> { + buf.putInt(3) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.WalletException -> { + buf.putInt(4) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.SyncException -> { + buf.putInt(5) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.UnsupportedKeyType -> { + buf.putInt(6) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.NetworkMismatch -> { + buf.putInt(7) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is AccountInfoException.InvalidTxid -> { + buf.putInt(8) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +public object FfiConverterTypeAccountType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AccountType = try { + AccountType.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: AccountType): ULong = 4UL + + override fun write(value: AccountType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + +public object FfiConverterTypeActivity : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Activity { + return when(buf.getInt()) { + 1 -> Activity.Onchain( + FfiConverterTypeOnchainActivity.read(buf), + ) + 2 -> Activity.Lightning( + FfiConverterTypeLightningActivity.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: Activity): ULong = when(value) { + is Activity.Onchain -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeOnchainActivity.allocationSize(value.v1) + ) + } + is Activity.Lightning -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeLightningActivity.allocationSize(value.v1) + ) + } + } + + override fun write(value: Activity, buf: ByteBuffer) { + when(value) { + is Activity.Onchain -> { + buf.putInt(1) + FfiConverterTypeOnchainActivity.write(value.v1, buf) + Unit + } + is Activity.Lightning -> { + buf.putInt(2) + FfiConverterTypeLightningActivity.write(value.v1, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } @@ -8592,14 +9064,280 @@ public object FfiConverterTypeTrezorError : FfiConverterRustBuffer { - buf.putInt(18) - FfiConverterString.write(value.`errorDetails`, buf) + is TrezorException.SessionException -> { + buf.putInt(18) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + is TrezorException.IoException -> { + buf.putInt(19) + FfiConverterString.write(value.`errorDetails`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +public object FfiConverterTypeTrezorPrecomposeOutput : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): TrezorPrecomposeOutput { + return when(buf.getInt()) { + 1 -> TrezorPrecomposeOutput.Payment( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + 2 -> TrezorPrecomposeOutput.PaymentNoAddress( + FfiConverterString.read(buf), + ) + 3 -> TrezorPrecomposeOutput.SendMax( + FfiConverterString.read(buf), + ) + 4 -> TrezorPrecomposeOutput.SendMaxNoAddress + 5 -> TrezorPrecomposeOutput.OpReturn( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: TrezorPrecomposeOutput): ULong = when(value) { + is TrezorPrecomposeOutput.Payment -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`address`) + + FfiConverterString.allocationSize(value.`amount`) + ) + } + is TrezorPrecomposeOutput.PaymentNoAddress -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`amount`) + ) + } + is TrezorPrecomposeOutput.SendMax -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`address`) + ) + } + is TrezorPrecomposeOutput.SendMaxNoAddress -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is TrezorPrecomposeOutput.OpReturn -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`dataHex`) + ) + } + } + + override fun write(value: TrezorPrecomposeOutput, buf: ByteBuffer) { + when(value) { + is TrezorPrecomposeOutput.Payment -> { + buf.putInt(1) + FfiConverterString.write(value.`address`, buf) + FfiConverterString.write(value.`amount`, buf) + Unit + } + is TrezorPrecomposeOutput.PaymentNoAddress -> { + buf.putInt(2) + FfiConverterString.write(value.`amount`, buf) + Unit + } + is TrezorPrecomposeOutput.SendMax -> { + buf.putInt(3) + FfiConverterString.write(value.`address`, buf) + Unit + } + is TrezorPrecomposeOutput.SendMaxNoAddress -> { + buf.putInt(4) + Unit + } + is TrezorPrecomposeOutput.OpReturn -> { + buf.putInt(5) + FfiConverterString.write(value.`dataHex`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +public object FfiConverterTypeTrezorPrecomposedOutput : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): TrezorPrecomposedOutput { + return when(buf.getInt()) { + 1 -> TrezorPrecomposedOutput.Payment( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + 2 -> TrezorPrecomposedOutput.Change( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeTrezorScriptType.read(buf), + ) + 3 -> TrezorPrecomposedOutput.OpReturn( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: TrezorPrecomposedOutput): ULong = when(value) { + is TrezorPrecomposedOutput.Payment -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`address`) + + FfiConverterString.allocationSize(value.`amount`) + ) + } + is TrezorPrecomposedOutput.Change -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`address`) + + FfiConverterString.allocationSize(value.`path`) + + FfiConverterString.allocationSize(value.`amount`) + + FfiConverterTypeTrezorScriptType.allocationSize(value.`scriptType`) + ) + } + is TrezorPrecomposedOutput.OpReturn -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`dataHex`) + ) + } + } + + override fun write(value: TrezorPrecomposedOutput, buf: ByteBuffer) { + when(value) { + is TrezorPrecomposedOutput.Payment -> { + buf.putInt(1) + FfiConverterString.write(value.`address`, buf) + FfiConverterString.write(value.`amount`, buf) + Unit + } + is TrezorPrecomposedOutput.Change -> { + buf.putInt(2) + FfiConverterString.write(value.`address`, buf) + FfiConverterString.write(value.`path`, buf) + FfiConverterString.write(value.`amount`, buf) + FfiConverterTypeTrezorScriptType.write(value.`scriptType`, buf) + Unit + } + is TrezorPrecomposedOutput.OpReturn -> { + buf.putInt(3) + FfiConverterString.write(value.`dataHex`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + + + + + +public object FfiConverterTypeTrezorPrecomposedResult : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): TrezorPrecomposedResult { + return when(buf.getInt()) { + 1 -> TrezorPrecomposedResult.Final( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + FfiConverterSequenceTypeTrezorPrecomposedInput.read(buf), + FfiConverterSequenceTypeTrezorPrecomposedOutput.read(buf), + FfiConverterSequenceUInt.read(buf), + ) + 2 -> TrezorPrecomposedResult.NonFinal( + FfiConverterOptionalString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUInt.read(buf), + ) + 3 -> TrezorPrecomposedResult.Error( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } + } + + override fun allocationSize(value: TrezorPrecomposedResult): ULong = when(value) { + is TrezorPrecomposedResult.Final -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`totalSpent`) + + FfiConverterString.allocationSize(value.`fee`) + + FfiConverterString.allocationSize(value.`feePerByte`) + + FfiConverterUInt.allocationSize(value.`bytes`) + + FfiConverterSequenceTypeTrezorPrecomposedInput.allocationSize(value.`inputs`) + + FfiConverterSequenceTypeTrezorPrecomposedOutput.allocationSize(value.`outputs`) + + FfiConverterSequenceUInt.allocationSize(value.`outputsPermutation`) + ) + } + is TrezorPrecomposedResult.NonFinal -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalString.allocationSize(value.`max`) + + FfiConverterString.allocationSize(value.`totalSpent`) + + FfiConverterString.allocationSize(value.`fee`) + + FfiConverterString.allocationSize(value.`feePerByte`) + + FfiConverterUInt.allocationSize(value.`bytes`) + ) + } + is TrezorPrecomposedResult.Error -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`error`) + ) + } + } + + override fun write(value: TrezorPrecomposedResult, buf: ByteBuffer) { + when(value) { + is TrezorPrecomposedResult.Final -> { + buf.putInt(1) + FfiConverterString.write(value.`totalSpent`, buf) + FfiConverterString.write(value.`fee`, buf) + FfiConverterString.write(value.`feePerByte`, buf) + FfiConverterUInt.write(value.`bytes`, buf) + FfiConverterSequenceTypeTrezorPrecomposedInput.write(value.`inputs`, buf) + FfiConverterSequenceTypeTrezorPrecomposedOutput.write(value.`outputs`, buf) + FfiConverterSequenceUInt.write(value.`outputsPermutation`, buf) + Unit + } + is TrezorPrecomposedResult.NonFinal -> { + buf.putInt(2) + FfiConverterOptionalString.write(value.`max`, buf) + FfiConverterString.write(value.`totalSpent`, buf) + FfiConverterString.write(value.`fee`, buf) + FfiConverterString.write(value.`feePerByte`, buf) + FfiConverterUInt.write(value.`bytes`, buf) Unit } - is TrezorException.IoException -> { - buf.putInt(19) - FfiConverterString.write(value.`errorDetails`, buf) + is TrezorPrecomposedResult.Error -> { + buf.putInt(3) + FfiConverterString.write(value.`error`, buf) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } @@ -8628,6 +9366,24 @@ public object FfiConverterTypeTrezorScriptType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TrezorSortingStrategy = try { + TrezorSortingStrategy.entries[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: TrezorSortingStrategy): ULong = 4UL + + override fun write(value: TrezorSortingStrategy, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + public object FfiConverterTypeTrezorTransportType: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): TrezorTransportType = try { TrezorTransportType.entries[buf.getInt() - 1] @@ -9794,6 +10550,35 @@ public object FfiConverterOptionalTypeTrezorScriptType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): TrezorSortingStrategy? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeTrezorSortingStrategy.read(buf) + } + + override fun allocationSize(value: TrezorSortingStrategy?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeTrezorSortingStrategy.allocationSize(value) + } + } + + override fun write(value: TrezorSortingStrategy?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeTrezorSortingStrategy.write(value, buf) + } + } +} + + + + public object FfiConverterOptionalTypeWordCount: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): WordCount? { if (buf.get().toInt() == 0) { @@ -9910,6 +10695,31 @@ public object FfiConverterOptionalMapStringString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterUInt.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterUInt.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterUInt.write(it, buf) + } + } +} + + + + public object FfiConverterSequenceString: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() @@ -9935,6 +10745,31 @@ public object FfiConverterSequenceString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeAccountUtxo.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeAccountUtxo.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeAccountUtxo.write(it, buf) + } + } +} + + + + public object FfiConverterSequenceTypeActivityTags: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() @@ -10310,6 +11145,56 @@ public object FfiConverterSequenceTypeTrezorDeviceInfo: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTrezorFeeLevel.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTrezorFeeLevel.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTrezorFeeLevel.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeTrezorPrecomposedInput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTrezorPrecomposedInput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTrezorPrecomposedInput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTrezorPrecomposedInput.write(it, buf) + } + } +} + + + + public object FfiConverterSequenceTypeTrezorPrevTx: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() @@ -10509,6 +11394,81 @@ public object FfiConverterSequenceTypeActivity: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTrezorPrecomposeOutput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTrezorPrecomposeOutput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTrezorPrecomposeOutput.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeTrezorPrecomposedOutput: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTrezorPrecomposedOutput.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTrezorPrecomposedOutput.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTrezorPrecomposedOutput.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeTrezorPrecomposedResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeTrezorPrecomposedResult.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeTrezorPrecomposedResult.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeTrezorPrecomposedResult.write(it, buf) + } + } +} + + + public object FfiConverterMapStringString: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): Map { val len = buf.getInt() @@ -11655,6 +12615,42 @@ public suspend fun `testNotification`(`deviceToken`: kotlin.String, `secretMessa ) } +/** + * Convert an account type to its corresponding script type. + */ +public fun `trezorAccountTypeToScriptType`(`accountType`: AccountType): TrezorScriptType { + return FfiConverterTypeTrezorScriptType.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type( + FfiConverterTypeAccountType.lower(`accountType`), + uniffiRustCallStatus, + ) + }) +} + +/** + * Broadcast a signed raw transaction via Electrum. + * + * Takes a hex-encoded serialized transaction and an Electrum server URL. + * Returns the transaction ID on success. + */ +@Throws(AccountInfoException::class, kotlin.coroutines.cancellation.CancellationException::class) +public suspend fun `trezorBroadcastRawTx`(`serializedTx`: kotlin.String, `electrumUrl`: kotlin.String): kotlin.String { + return uniffiRustCallAsync( + UniffiLib.uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx( + FfiConverterString.lower(`serializedTx`), + FfiConverterString.lower(`electrumUrl`), + ), + { future, callback, continuation -> UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterString.lift(it) }, + // Error FFI converter + AccountInfoExceptionErrorHandler, + ) +} + /** * Clear stored Bluetooth pairing credentials for a specific Trezor device. * @@ -11722,6 +12718,56 @@ public suspend fun `trezorDisconnect`() { ) } +/** + * Fetch previous transactions from Electrum for Trezor signing. + * + * Takes transaction IDs (from TrezorSignTxParams inputs' prev_hash fields), + * fetches the full transactions from Electrum, and returns them as + * TrezorPrevTx structures ready to merge into TrezorSignTxParams.prev_txs. + * + * Duplicate txids are automatically deduplicated. + */ +@Throws(AccountInfoException::class, kotlin.coroutines.cancellation.CancellationException::class) +public suspend fun `trezorFetchPrevTxs`(`txids`: List, `electrumUrl`: kotlin.String): List { + return uniffiRustCallAsync( + UniffiLib.uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs( + FfiConverterSequenceString.lower(`txids`), + FfiConverterString.lower(`electrumUrl`), + ), + { future, callback, continuation -> UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeTrezorPrevTx.lift(it) }, + // Error FFI converter + AccountInfoExceptionErrorHandler, + ) +} + +/** + * Query account information for an extended public key via Electrum. + */ +@Throws(AccountInfoException::class, kotlin.coroutines.cancellation.CancellationException::class) +public suspend fun `trezorGetAccountInfo`(`extendedKey`: kotlin.String, `electrumUrl`: kotlin.String, `network`: TrezorCoinType?, `gapLimit`: kotlin.UInt?): AccountInfoResult { + return uniffiRustCallAsync( + UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_account_info( + FfiConverterString.lower(`extendedKey`), + FfiConverterString.lower(`electrumUrl`), + FfiConverterOptionalTypeTrezorCoinType.lower(`network`), + FfiConverterOptionalUInt.lower(`gapLimit`), + ), + { future, callback, continuation -> UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterTypeAccountInfoResult.lift(it) }, + // Error FFI converter + AccountInfoExceptionErrorHandler, + ) +} + /** * Get a Bitcoin address from the connected Trezor device. */ @@ -11742,6 +12788,28 @@ public suspend fun `trezorGetAddress`(`params`: TrezorGetAddressParams): TrezorA ) } +/** + * Query balance and UTXOs for a single Bitcoin address via Electrum. + */ +@Throws(AccountInfoException::class, kotlin.coroutines.cancellation.CancellationException::class) +public suspend fun `trezorGetAddressInfo`(`address`: kotlin.String, `electrumUrl`: kotlin.String, `network`: TrezorCoinType?): SingleAddressInfoResult { + return uniffiRustCallAsync( + UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address_info( + FfiConverterString.lower(`address`), + FfiConverterString.lower(`electrumUrl`), + FfiConverterOptionalTypeTrezorCoinType.lower(`network`), + ), + { future, callback, continuation -> UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer(future) }, + { future -> UniffiLib.ffi_bitkitcore_rust_future_cancel_rust_buffer(future) }, + // lift function + { FfiConverterTypeSingleAddressInfoResult.lift(it) }, + // Error FFI converter + AccountInfoExceptionErrorHandler, + ) +} + /** * Get information about the currently connected Trezor device. */ @@ -11918,6 +12986,36 @@ public suspend fun `trezorListDevices`(): List { ) } +/** + * Compose a transaction offline for multiple fee levels. + * + * No device interaction needed — pure coin selection and fee calculation. + */ +public fun `trezorPrecomposeTransaction`(`params`: TrezorPrecomposeParams): List { + return FfiConverterSequenceTypeTrezorPrecomposedResult.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.uniffi_bitkitcore_fn_func_trezor_precompose_transaction( + FfiConverterTypeTrezorPrecomposeParams.lower(`params`), + uniffiRustCallStatus, + ) + }) +} + +/** + * Convert precomposed results into signing parameters for trezor_sign_tx. + * + * The returned params have empty prev_txs — add them before signing. + */ +public fun `trezorPrecomposedToSignParams`(`inputs`: List, `outputs`: List, `coin`: TrezorCoinType?): TrezorSignTxParams { + return FfiConverterTypeTrezorSignTxParams.lift(uniffiRustCall { uniffiRustCallStatus -> + UniffiLib.uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params( + FfiConverterSequenceTypeTrezorPrecomposedInput.lower(`inputs`), + FfiConverterSequenceTypeTrezorPrecomposedOutput.lower(`outputs`), + FfiConverterOptionalTypeTrezorCoinType.lower(`coin`), + uniffiRustCallStatus, + ) + }) +} + /** * Scan for available Trezor devices (USB + Bluetooth). * diff --git a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt index 64d03f8..ccaadc5 100644 --- a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt +++ b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.common.kt @@ -281,16 +281,16 @@ public interface TrezorUiCallback { /** - * Account addresses + * Grouped address lists for an account. */ @kotlinx.serialization.Serializable public data class AccountAddresses ( /** - * Used addresses + * Used receive addresses (have at least one transaction) */ val `used`: List, /** - * Unused addresses + * Unused receive addresses (no transactions yet) */ val `unused`: List, /** @@ -303,6 +303,88 @@ public data class AccountAddresses ( +/** + * Result from querying an extended public key — ready for Trezor compose. + */ +@kotlinx.serialization.Serializable +public data class AccountInfoResult ( + /** + * The compose-compatible account structure + */ + val `account`: ComposeAccount, + /** + * Total confirmed balance in satoshis + */ + val `balance`: kotlin.ULong, + /** + * Number of UTXOs + */ + val `utxoCount`: kotlin.UInt, + /** + * The detected or specified account type + */ + val `accountType`: AccountType, + /** + * The current blockchain tip height + */ + val `blockHeight`: kotlin.UInt +) { + public companion object +} + + + +/** + * A UTXO in the format expected by Trezor compose. + */ +@kotlinx.serialization.Serializable +public data class AccountUtxo ( + /** + * Transaction ID (hex) + */ + val `txid`: kotlin.String, + /** + * Output index + */ + val `vout`: kotlin.UInt, + /** + * Amount in satoshis + */ + val `amount`: kotlin.ULong, + /** + * Block height where the UTXO was confirmed (0 if unconfirmed) + */ + val `blockHeight`: kotlin.UInt, + /** + * Address holding this UTXO + */ + val `address`: kotlin.String, + /** + * BIP32 derivation path (e.g., "m/84'/0'/0'/0/0") + */ + val `path`: kotlin.String, + /** + * Number of confirmations (0 if unconfirmed) + */ + val `confirmations`: kotlin.UInt, + /** + * Whether this is a coinbase output + */ + val `coinbase`: kotlin.Boolean, + /** + * Whether this UTXO is owned by the account + */ + val `own`: kotlin.Boolean, + /** + * Whether this UTXO must be included in the transaction + */ + val `required`: kotlin.Boolean? +) { + public companion object +} + + + @kotlinx.serialization.Serializable public data class ActivityTags ( val `activityId`: kotlin.String, @@ -314,20 +396,20 @@ public data class ActivityTags ( /** - * Address information + * Information about a single address in an account. */ @kotlinx.serialization.Serializable public data class AddressInfo ( /** - * Address string + * The Bitcoin address */ val `address`: kotlin.String, /** - * Derivation path + * BIP32 derivation path */ val `path`: kotlin.String, /** - * Number of transfers + * Number of transactions involving this address */ val `transfers`: kotlin.UInt ) { @@ -383,6 +465,32 @@ public data class ClosedChannelDetails ( +/** + * Full account structure for Trezor compose. + * + * This is the `account` object expected by `composeTransaction` in + * precompose mode. + */ +@kotlinx.serialization.Serializable +public data class ComposeAccount ( + /** + * Account derivation path (e.g., "m/84'/0'/0'") + */ + val `path`: kotlin.String, + /** + * Categorized addresses + */ + val `addresses`: AccountAddresses, + /** + * Unspent transaction outputs + */ + val `utxo`: List +) { + public companion object +} + + + @kotlinx.serialization.Serializable public data class CreateCjitOptions ( val `source`: kotlin.String?, @@ -1150,6 +1258,37 @@ public data class PubkyAuth ( +/** + * Result from querying a single Bitcoin address. + */ +@kotlinx.serialization.Serializable +public data class SingleAddressInfoResult ( + /** + * The queried address + */ + val `address`: kotlin.String, + /** + * Total confirmed balance in satoshis + */ + val `balance`: kotlin.ULong, + /** + * UTXOs for this address + */ + val `utxos`: List, + /** + * Number of transactions involving this address + */ + val `transfers`: kotlin.UInt, + /** + * Current blockchain tip height + */ + val `blockHeight`: kotlin.UInt +) { + public companion object +} + + + @kotlinx.serialization.Serializable public data class SweepResult ( /** @@ -1441,6 +1580,29 @@ public data class TrezorFeatures ( +/** + * Fee level for transaction composition. + */ +@kotlinx.serialization.Serializable +public data class TrezorFeeLevel ( + /** + * Fee rate in sat/vB + */ + val `feePerUnit`: kotlin.String, + /** + * Base fee in satoshis (optional, added to calculated fee) + */ + val `baseFee`: kotlin.ULong?, + /** + * Whether to use floor for base fee calculation + */ + val `floorBaseFee`: kotlin.Boolean? +) { + public companion object +} + + + /** * Parameters for getting an address from the device. */ @@ -1491,6 +1653,76 @@ public data class TrezorGetPublicKeyParams ( +/** + * Parameters for precompose transaction. + */ +@kotlinx.serialization.Serializable +public data class TrezorPrecomposeParams ( + /** + * Desired outputs + */ + val `outputs`: List, + /** + * Coin name (e.g., "Bitcoin", "Regtest") + */ + val `coin`: kotlin.String, + /** + * Account with UTXOs and addresses + */ + val `account`: ComposeAccount, + /** + * Fee levels to evaluate + */ + val `feeLevels`: List, + /** + * Default sequence number + */ + val `sequence`: kotlin.UInt?, + /** + * Sorting strategy for inputs/outputs + */ + val `sortingStrategy`: TrezorSortingStrategy? +) { + public companion object +} + + + +/** + * Input in a precomposed result. + */ +@kotlinx.serialization.Serializable +public data class TrezorPrecomposedInput ( + /** + * Transaction ID (hex) + */ + val `txid`: kotlin.String, + /** + * Output index + */ + val `vout`: kotlin.UInt, + /** + * Amount in satoshis (as string) + */ + val `amount`: kotlin.String, + /** + * Address + */ + val `address`: kotlin.String, + /** + * BIP32 derivation path + */ + val `path`: kotlin.String, + /** + * Script type + */ + val `scriptType`: TrezorScriptType +) { + public companion object +} + + + /** * Previous transaction data (for non-SegWit input verification). */ @@ -1696,7 +1928,11 @@ public data class TrezorSignedTx ( /** * Serialized transaction (hex) */ - val `serializedTx`: kotlin.String + val `serializedTx`: kotlin.String, + /** + * Broadcast transaction ID (populated when push=true) + */ + val `txid`: kotlin.String? ) { public companion object } @@ -1945,6 +2181,133 @@ public data class ValidationResult ( + +/** + * Errors specific to account info operations (BDK/Electrum-based). + * + * These are separate from `TrezorError` because account info operations + * do not interact with a Trezor device — they only query the blockchain. + */ +public sealed class AccountInfoException: kotlin.Exception() { + + /** + * The provided extended public key is invalid or cannot be parsed + */ + public class InvalidExtendedKey( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * The provided address is invalid + */ + public class InvalidAddress( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * Electrum connection or query failed + */ + public class ElectrumException( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * BDK wallet creation or operation error + */ + public class WalletException( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * Wallet sync with Electrum failed + */ + public class SyncException( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * The key type/prefix is not recognized + */ + public class UnsupportedKeyType( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * Network mismatch between key prefix and specified network + */ + public class NetworkMismatch( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + + /** + * Invalid transaction ID provided + */ + public class InvalidTxid( + public val `errorDetails`: kotlin.String, + ) : AccountInfoException() { + override val message: String + get() = "errorDetails=${ `errorDetails` }" + } + +} + + + + +/** + * Account type classification for extended public keys. + * + * Determines the BIP standard, derivation path purpose, and script type. + */ + +@kotlinx.serialization.Serializable +public enum class AccountType { + + /** + * BIP44 legacy (P2PKH) — xpub/tpub prefix + */ + LEGACY, + /** + * BIP49 wrapped segwit (P2SH-P2WPKH) — ypub/upub prefix + */ + WRAPPED_SEGWIT, + /** + * BIP84 native segwit (P2WPKH) — zpub/vpub prefix + */ + NATIVE_SEGWIT, + /** + * BIP86 taproot (P2TR) + */ + TAPROOT; + public companion object +} + + + + + + @kotlinx.serialization.Serializable public sealed class Activity { @kotlinx.serialization.Serializable @@ -2978,6 +3341,147 @@ public sealed class TrezorException: kotlin.Exception() { +/** + * Output specification for precompose. + */ +@kotlinx.serialization.Serializable +public sealed class TrezorPrecomposeOutput { + + /** + * Payment to a specific address + */@kotlinx.serialization.Serializable + public data class Payment( + val `address`: kotlin.String, + val `amount`: kotlin.String, + ) : TrezorPrecomposeOutput() { + } + + /** + * Payment without address (estimation only) + */@kotlinx.serialization.Serializable + public data class PaymentNoAddress( + val `amount`: kotlin.String, + ) : TrezorPrecomposeOutput() { + } + + /** + * Send all remaining funds to an address + */@kotlinx.serialization.Serializable + public data class SendMax( + val `address`: kotlin.String, + ) : TrezorPrecomposeOutput() { + } + + /** + * Send all remaining funds (no address) + */ + @kotlinx.serialization.Serializable + public data object SendMaxNoAddress : TrezorPrecomposeOutput() + + + /** + * OP_RETURN data output + */@kotlinx.serialization.Serializable + public data class OpReturn( + val `dataHex`: kotlin.String, + ) : TrezorPrecomposeOutput() { + } + +} + + + + + + +/** + * Output in a precomposed result. + */ +@kotlinx.serialization.Serializable +public sealed class TrezorPrecomposedOutput { + + /** + * Payment to an address + */@kotlinx.serialization.Serializable + public data class Payment( + val `address`: kotlin.String, + val `amount`: kotlin.String, + ) : TrezorPrecomposedOutput() { + } + + /** + * Change output + */@kotlinx.serialization.Serializable + public data class Change( + val `address`: kotlin.String, + val `path`: kotlin.String, + val `amount`: kotlin.String, + val `scriptType`: TrezorScriptType, + ) : TrezorPrecomposedOutput() { + } + + /** + * OP_RETURN data output + */@kotlinx.serialization.Serializable + public data class OpReturn( + val `dataHex`: kotlin.String, + ) : TrezorPrecomposedOutput() { + } + +} + + + + + + +/** + * Precomposed transaction result (one per fee level). + */ +@kotlinx.serialization.Serializable +public sealed class TrezorPrecomposedResult { + + /** + * Successfully composed a sendable transaction + */@kotlinx.serialization.Serializable + public data class Final( + val `totalSpent`: kotlin.String, + val `fee`: kotlin.String, + val `feePerByte`: kotlin.String, + val `bytes`: kotlin.UInt, + val `inputs`: List, + val `outputs`: List, + val `outputsPermutation`: List, + ) : TrezorPrecomposedResult() { + } + + /** + * Non-final result (e.g., send-max estimation) + */@kotlinx.serialization.Serializable + public data class NonFinal( + val `max`: kotlin.String?, + val `totalSpent`: kotlin.String, + val `fee`: kotlin.String, + val `feePerByte`: kotlin.String, + val `bytes`: kotlin.UInt, + ) : TrezorPrecomposedResult() { + } + + /** + * Composition failed + */@kotlinx.serialization.Serializable + public data class Error( + val `error`: kotlin.String, + ) : TrezorPrecomposedResult() { + } + +} + + + + + + /** * Script types for address derivation. */ @@ -3017,6 +3521,33 @@ public enum class TrezorScriptType { +/** + * Sorting strategy for transaction inputs and outputs. + */ + +@kotlinx.serialization.Serializable +public enum class TrezorSortingStrategy { + + /** + * BIP-69: deterministic lexicographic sorting + */ + BIP69, + /** + * Random shuffle (better privacy) + */ + RANDOM, + /** + * Keep original order + */ + NONE; + public companion object +} + + + + + + /** * Transport type for Trezor devices. */ @@ -3188,6 +3719,22 @@ public enum class WordCount { + + + + + + + + + + + + + + + + diff --git a/bindings/ios/BitkitCore.xcframework.zip b/bindings/ios/BitkitCore.xcframework.zip index 2f8e45b..3470628 100644 Binary files a/bindings/ios/BitkitCore.xcframework.zip and b/bindings/ios/BitkitCore.xcframework.zip differ diff --git a/bindings/ios/BitkitCore.xcframework/Info.plist b/bindings/ios/BitkitCore.xcframework/Info.plist index 478a88f..b7357e0 100644 --- a/bindings/ios/BitkitCore.xcframework/Info.plist +++ b/bindings/ios/BitkitCore.xcframework/Info.plist @@ -10,7 +10,7 @@ HeadersPath Headers LibraryIdentifier - ios-arm64 + ios-arm64-simulator LibraryPath libbitkitcore.a SupportedArchitectures @@ -19,6 +19,8 @@ SupportedPlatform ios + SupportedPlatformVariant + simulator BinaryPath @@ -26,7 +28,7 @@ HeadersPath Headers LibraryIdentifier - ios-arm64-simulator + ios-arm64 LibraryPath libbitkitcore.a SupportedArchitectures @@ -35,8 +37,6 @@ SupportedPlatform ios - SupportedPlatformVariant - simulator CFBundlePackageType diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h index e2134e2..0f360b1 100644 --- a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h +++ b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h @@ -867,6 +867,16 @@ uint64_t uniffi_bitkitcore_fn_func_start_pubky_auth(RustBuffer caps uint64_t uniffi_bitkitcore_fn_func_test_notification(RustBuffer device_token, RustBuffer secret_message, RustBuffer notification_type, RustBuffer custom_url ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +RustBuffer uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type(RustBuffer account_type, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +uint64_t uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx(RustBuffer serialized_tx, RustBuffer electrum_url +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS uint64_t uniffi_bitkitcore_fn_func_trezor_clear_credentials(RustBuffer device_id @@ -881,6 +891,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_connect(RustBuffer device_id #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_DISCONNECT uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +uint64_t uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs(RustBuffer txids, RustBuffer electrum_url +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_account_info(RustBuffer extended_key, RustBuffer electrum_url, RustBuffer network, RustBuffer gap_limit ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS @@ -888,6 +908,11 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void uint64_t uniffi_bitkitcore_fn_func_trezor_get_address(RustBuffer params ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_address_info(RustBuffer address, RustBuffer electrum_url, RustBuffer network +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE uint64_t uniffi_bitkitcore_fn_func_trezor_get_connected_device(void @@ -938,6 +963,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_LIST_DEVICES uint64_t uniffi_bitkitcore_fn_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +RustBuffer uniffi_bitkitcore_fn_func_trezor_precompose_transaction(RustBuffer params, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +RustBuffer uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params(RustBuffer inputs, RustBuffer outputs, RustBuffer coin, RustCallStatus *_Nonnull out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_SCAN @@ -1820,6 +1855,18 @@ uint16_t uniffi_bitkitcore_checksum_func_start_pubky_auth(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TEST_NOTIFICATION uint16_t uniffi_bitkitcore_checksum_func_test_notification(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +uint16_t uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +uint16_t uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_CLEAR_CREDENTIALS @@ -1838,12 +1885,30 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_connect(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_DISCONNECT uint16_t uniffi_bitkitcore_checksum_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +uint16_t uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_account_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_CONNECTED_DEVICE @@ -1898,6 +1963,18 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_LIST_DEVICES uint16_t uniffi_bitkitcore_checksum_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +uint16_t uniffi_bitkitcore_checksum_func_trezor_precompose_transaction(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +uint16_t uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_SCAN diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a index 180ba37..c5acb28 100644 Binary files a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a and b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a differ diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h b/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h index e2134e2..0f360b1 100644 --- a/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h +++ b/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h @@ -867,6 +867,16 @@ uint64_t uniffi_bitkitcore_fn_func_start_pubky_auth(RustBuffer caps uint64_t uniffi_bitkitcore_fn_func_test_notification(RustBuffer device_token, RustBuffer secret_message, RustBuffer notification_type, RustBuffer custom_url ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +RustBuffer uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type(RustBuffer account_type, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +uint64_t uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx(RustBuffer serialized_tx, RustBuffer electrum_url +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS uint64_t uniffi_bitkitcore_fn_func_trezor_clear_credentials(RustBuffer device_id @@ -881,6 +891,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_connect(RustBuffer device_id #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_DISCONNECT uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +uint64_t uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs(RustBuffer txids, RustBuffer electrum_url +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_account_info(RustBuffer extended_key, RustBuffer electrum_url, RustBuffer network, RustBuffer gap_limit ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS @@ -888,6 +908,11 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void uint64_t uniffi_bitkitcore_fn_func_trezor_get_address(RustBuffer params ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_address_info(RustBuffer address, RustBuffer electrum_url, RustBuffer network +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE uint64_t uniffi_bitkitcore_fn_func_trezor_get_connected_device(void @@ -938,6 +963,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_LIST_DEVICES uint64_t uniffi_bitkitcore_fn_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +RustBuffer uniffi_bitkitcore_fn_func_trezor_precompose_transaction(RustBuffer params, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +RustBuffer uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params(RustBuffer inputs, RustBuffer outputs, RustBuffer coin, RustCallStatus *_Nonnull out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_SCAN @@ -1820,6 +1855,18 @@ uint16_t uniffi_bitkitcore_checksum_func_start_pubky_auth(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TEST_NOTIFICATION uint16_t uniffi_bitkitcore_checksum_func_test_notification(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +uint16_t uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +uint16_t uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_CLEAR_CREDENTIALS @@ -1838,12 +1885,30 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_connect(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_DISCONNECT uint16_t uniffi_bitkitcore_checksum_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +uint16_t uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_account_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_CONNECTED_DEVICE @@ -1898,6 +1963,18 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_LIST_DEVICES uint16_t uniffi_bitkitcore_checksum_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +uint16_t uniffi_bitkitcore_checksum_func_trezor_precompose_transaction(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +uint16_t uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_SCAN diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a b/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a index 7e1c4c2..8d72e03 100644 Binary files a/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a and b/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a differ diff --git a/bindings/ios/bitkitcore.swift b/bindings/ios/bitkitcore.swift index ce6871b..d1b935e 100644 --- a/bindings/ios/bitkitcore.swift +++ b/bindings/ios/bitkitcore.swift @@ -1549,15 +1549,15 @@ public func FfiConverterTypeTrezorUiCallback_lower(_ value: TrezorUiCallback) -> /** - * Account addresses + * Grouped address lists for an account. */ public struct AccountAddresses { /** - * Used addresses + * Used receive addresses (have at least one transaction) */ public var used: [AddressInfo] /** - * Unused addresses + * Unused receive addresses (no transactions yet) */ public var unused: [AddressInfo] /** @@ -1569,10 +1569,10 @@ public struct AccountAddresses { // declare one manually. public init( /** - * Used addresses + * Used receive addresses (have at least one transaction) */used: [AddressInfo], /** - * Unused addresses + * Unused receive addresses (no transactions yet) */unused: [AddressInfo], /** * Change addresses @@ -1649,6 +1649,334 @@ public func FfiConverterTypeAccountAddresses_lower(_ value: AccountAddresses) -> } +/** + * Result from querying an extended public key — ready for Trezor compose. + */ +public struct AccountInfoResult { + /** + * The compose-compatible account structure + */ + public var account: ComposeAccount + /** + * Total confirmed balance in satoshis + */ + public var balance: UInt64 + /** + * Number of UTXOs + */ + public var utxoCount: UInt32 + /** + * The detected or specified account type + */ + public var accountType: AccountType + /** + * The current blockchain tip height + */ + public var blockHeight: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * The compose-compatible account structure + */account: ComposeAccount, + /** + * Total confirmed balance in satoshis + */balance: UInt64, + /** + * Number of UTXOs + */utxoCount: UInt32, + /** + * The detected or specified account type + */accountType: AccountType, + /** + * The current blockchain tip height + */blockHeight: UInt32) { + self.account = account + self.balance = balance + self.utxoCount = utxoCount + self.accountType = accountType + self.blockHeight = blockHeight + } +} + +#if compiler(>=6) +extension AccountInfoResult: Sendable {} +#endif + + +extension AccountInfoResult: Equatable, Hashable { + public static func ==(lhs: AccountInfoResult, rhs: AccountInfoResult) -> Bool { + if lhs.account != rhs.account { + return false + } + if lhs.balance != rhs.balance { + return false + } + if lhs.utxoCount != rhs.utxoCount { + return false + } + if lhs.accountType != rhs.accountType { + return false + } + if lhs.blockHeight != rhs.blockHeight { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(account) + hasher.combine(balance) + hasher.combine(utxoCount) + hasher.combine(accountType) + hasher.combine(blockHeight) + } +} + +extension AccountInfoResult: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeAccountInfoResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountInfoResult { + return + try AccountInfoResult( + account: FfiConverterTypeComposeAccount.read(from: &buf), + balance: FfiConverterUInt64.read(from: &buf), + utxoCount: FfiConverterUInt32.read(from: &buf), + accountType: FfiConverterTypeAccountType.read(from: &buf), + blockHeight: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: AccountInfoResult, into buf: inout [UInt8]) { + FfiConverterTypeComposeAccount.write(value.account, into: &buf) + FfiConverterUInt64.write(value.balance, into: &buf) + FfiConverterUInt32.write(value.utxoCount, into: &buf) + FfiConverterTypeAccountType.write(value.accountType, into: &buf) + FfiConverterUInt32.write(value.blockHeight, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountInfoResult_lift(_ buf: RustBuffer) throws -> AccountInfoResult { + return try FfiConverterTypeAccountInfoResult.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountInfoResult_lower(_ value: AccountInfoResult) -> RustBuffer { + return FfiConverterTypeAccountInfoResult.lower(value) +} + + +/** + * A UTXO in the format expected by Trezor compose. + */ +public struct AccountUtxo { + /** + * Transaction ID (hex) + */ + public var txid: String + /** + * Output index + */ + public var vout: UInt32 + /** + * Amount in satoshis + */ + public var amount: UInt64 + /** + * Block height where the UTXO was confirmed (0 if unconfirmed) + */ + public var blockHeight: UInt32 + /** + * Address holding this UTXO + */ + public var address: String + /** + * BIP32 derivation path (e.g., "m/84'/0'/0'/0/0") + */ + public var path: String + /** + * Number of confirmations (0 if unconfirmed) + */ + public var confirmations: UInt32 + /** + * Whether this is a coinbase output + */ + public var coinbase: Bool + /** + * Whether this UTXO is owned by the account + */ + public var own: Bool + /** + * Whether this UTXO must be included in the transaction + */ + public var required: Bool? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Transaction ID (hex) + */txid: String, + /** + * Output index + */vout: UInt32, + /** + * Amount in satoshis + */amount: UInt64, + /** + * Block height where the UTXO was confirmed (0 if unconfirmed) + */blockHeight: UInt32, + /** + * Address holding this UTXO + */address: String, + /** + * BIP32 derivation path (e.g., "m/84'/0'/0'/0/0") + */path: String, + /** + * Number of confirmations (0 if unconfirmed) + */confirmations: UInt32, + /** + * Whether this is a coinbase output + */coinbase: Bool, + /** + * Whether this UTXO is owned by the account + */own: Bool, + /** + * Whether this UTXO must be included in the transaction + */required: Bool?) { + self.txid = txid + self.vout = vout + self.amount = amount + self.blockHeight = blockHeight + self.address = address + self.path = path + self.confirmations = confirmations + self.coinbase = coinbase + self.own = own + self.required = required + } +} + +#if compiler(>=6) +extension AccountUtxo: Sendable {} +#endif + + +extension AccountUtxo: Equatable, Hashable { + public static func ==(lhs: AccountUtxo, rhs: AccountUtxo) -> Bool { + if lhs.txid != rhs.txid { + return false + } + if lhs.vout != rhs.vout { + return false + } + if lhs.amount != rhs.amount { + return false + } + if lhs.blockHeight != rhs.blockHeight { + return false + } + if lhs.address != rhs.address { + return false + } + if lhs.path != rhs.path { + return false + } + if lhs.confirmations != rhs.confirmations { + return false + } + if lhs.coinbase != rhs.coinbase { + return false + } + if lhs.own != rhs.own { + return false + } + if lhs.required != rhs.required { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(txid) + hasher.combine(vout) + hasher.combine(amount) + hasher.combine(blockHeight) + hasher.combine(address) + hasher.combine(path) + hasher.combine(confirmations) + hasher.combine(coinbase) + hasher.combine(own) + hasher.combine(required) + } +} + +extension AccountUtxo: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeAccountUtxo: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountUtxo { + return + try AccountUtxo( + txid: FfiConverterString.read(from: &buf), + vout: FfiConverterUInt32.read(from: &buf), + amount: FfiConverterUInt64.read(from: &buf), + blockHeight: FfiConverterUInt32.read(from: &buf), + address: FfiConverterString.read(from: &buf), + path: FfiConverterString.read(from: &buf), + confirmations: FfiConverterUInt32.read(from: &buf), + coinbase: FfiConverterBool.read(from: &buf), + own: FfiConverterBool.read(from: &buf), + required: FfiConverterOptionBool.read(from: &buf) + ) + } + + public static func write(_ value: AccountUtxo, into buf: inout [UInt8]) { + FfiConverterString.write(value.txid, into: &buf) + FfiConverterUInt32.write(value.vout, into: &buf) + FfiConverterUInt64.write(value.amount, into: &buf) + FfiConverterUInt32.write(value.blockHeight, into: &buf) + FfiConverterString.write(value.address, into: &buf) + FfiConverterString.write(value.path, into: &buf) + FfiConverterUInt32.write(value.confirmations, into: &buf) + FfiConverterBool.write(value.coinbase, into: &buf) + FfiConverterBool.write(value.own, into: &buf) + FfiConverterOptionBool.write(value.required, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountUtxo_lift(_ buf: RustBuffer) throws -> AccountUtxo { + return try FfiConverterTypeAccountUtxo.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountUtxo_lower(_ value: AccountUtxo) -> RustBuffer { + return FfiConverterTypeAccountUtxo.lower(value) +} + + public struct ActivityTags { public var activityId: String public var tags: [String] @@ -1722,19 +2050,19 @@ public func FfiConverterTypeActivityTags_lower(_ value: ActivityTags) -> RustBuf /** - * Address information + * Information about a single address in an account. */ public struct AddressInfo { /** - * Address string + * The Bitcoin address */ public var address: String /** - * Derivation path + * BIP32 derivation path */ public var path: String /** - * Number of transfers + * Number of transactions involving this address */ public var transfers: UInt32 @@ -1742,13 +2070,13 @@ public struct AddressInfo { // declare one manually. public init( /** - * Address string + * The Bitcoin address */address: String, /** - * Derivation path + * BIP32 derivation path */path: String, /** - * Number of transfers + * Number of transactions involving this address */transfers: UInt32) { self.address = address self.path = path @@ -2174,57 +2502,161 @@ public func FfiConverterTypeClosedChannelDetails_lower(_ value: ClosedChannelDet } -public struct CreateCjitOptions { - public var source: String? - public var discountCode: String? +/** + * Full account structure for Trezor compose. + * + * This is the `account` object expected by `composeTransaction` in + * precompose mode. + */ +public struct ComposeAccount { + /** + * Account derivation path (e.g., "m/84'/0'/0'") + */ + public var path: String + /** + * Categorized addresses + */ + public var addresses: AccountAddresses + /** + * Unspent transaction outputs + */ + public var utxo: [AccountUtxo] // Default memberwise initializers are never public by default, so we // declare one manually. - public init(source: String?, discountCode: String?) { - self.source = source - self.discountCode = discountCode + public init( + /** + * Account derivation path (e.g., "m/84'/0'/0'") + */path: String, + /** + * Categorized addresses + */addresses: AccountAddresses, + /** + * Unspent transaction outputs + */utxo: [AccountUtxo]) { + self.path = path + self.addresses = addresses + self.utxo = utxo } } #if compiler(>=6) -extension CreateCjitOptions: Sendable {} +extension ComposeAccount: Sendable {} #endif -extension CreateCjitOptions: Equatable, Hashable { - public static func ==(lhs: CreateCjitOptions, rhs: CreateCjitOptions) -> Bool { - if lhs.source != rhs.source { +extension ComposeAccount: Equatable, Hashable { + public static func ==(lhs: ComposeAccount, rhs: ComposeAccount) -> Bool { + if lhs.path != rhs.path { return false } - if lhs.discountCode != rhs.discountCode { + if lhs.addresses != rhs.addresses { + return false + } + if lhs.utxo != rhs.utxo { return false } return true } public func hash(into hasher: inout Hasher) { - hasher.combine(source) - hasher.combine(discountCode) + hasher.combine(path) + hasher.combine(addresses) + hasher.combine(utxo) } } -extension CreateCjitOptions: Codable {} +extension ComposeAccount: Codable {} #if swift(>=5.8) @_documentation(visibility: private) #endif -public struct FfiConverterTypeCreateCjitOptions: FfiConverterRustBuffer { - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CreateCjitOptions { +public struct FfiConverterTypeComposeAccount: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ComposeAccount { return - try CreateCjitOptions( - source: FfiConverterOptionString.read(from: &buf), - discountCode: FfiConverterOptionString.read(from: &buf) + try ComposeAccount( + path: FfiConverterString.read(from: &buf), + addresses: FfiConverterTypeAccountAddresses.read(from: &buf), + utxo: FfiConverterSequenceTypeAccountUtxo.read(from: &buf) ) } - public static func write(_ value: CreateCjitOptions, into buf: inout [UInt8]) { + public static func write(_ value: ComposeAccount, into buf: inout [UInt8]) { + FfiConverterString.write(value.path, into: &buf) + FfiConverterTypeAccountAddresses.write(value.addresses, into: &buf) + FfiConverterSequenceTypeAccountUtxo.write(value.utxo, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeComposeAccount_lift(_ buf: RustBuffer) throws -> ComposeAccount { + return try FfiConverterTypeComposeAccount.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeComposeAccount_lower(_ value: ComposeAccount) -> RustBuffer { + return FfiConverterTypeComposeAccount.lower(value) +} + + +public struct CreateCjitOptions { + public var source: String? + public var discountCode: String? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init(source: String?, discountCode: String?) { + self.source = source + self.discountCode = discountCode + } +} + +#if compiler(>=6) +extension CreateCjitOptions: Sendable {} +#endif + + +extension CreateCjitOptions: Equatable, Hashable { + public static func ==(lhs: CreateCjitOptions, rhs: CreateCjitOptions) -> Bool { + if lhs.source != rhs.source { + return false + } + if lhs.discountCode != rhs.discountCode { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(source) + hasher.combine(discountCode) + } +} + +extension CreateCjitOptions: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeCreateCjitOptions: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CreateCjitOptions { + return + try CreateCjitOptions( + source: FfiConverterOptionString.read(from: &buf), + discountCode: FfiConverterOptionString.read(from: &buf) + ) + } + + public static func write(_ value: CreateCjitOptions, into buf: inout [UInt8]) { FfiConverterOptionString.write(value.source, into: &buf) FfiConverterOptionString.write(value.discountCode, into: &buf) } @@ -7271,6 +7703,135 @@ public func FfiConverterTypePubkyAuth_lower(_ value: PubkyAuth) -> RustBuffer { } +/** + * Result from querying a single Bitcoin address. + */ +public struct SingleAddressInfoResult { + /** + * The queried address + */ + public var address: String + /** + * Total confirmed balance in satoshis + */ + public var balance: UInt64 + /** + * UTXOs for this address + */ + public var utxos: [AccountUtxo] + /** + * Number of transactions involving this address + */ + public var transfers: UInt32 + /** + * Current blockchain tip height + */ + public var blockHeight: UInt32 + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * The queried address + */address: String, + /** + * Total confirmed balance in satoshis + */balance: UInt64, + /** + * UTXOs for this address + */utxos: [AccountUtxo], + /** + * Number of transactions involving this address + */transfers: UInt32, + /** + * Current blockchain tip height + */blockHeight: UInt32) { + self.address = address + self.balance = balance + self.utxos = utxos + self.transfers = transfers + self.blockHeight = blockHeight + } +} + +#if compiler(>=6) +extension SingleAddressInfoResult: Sendable {} +#endif + + +extension SingleAddressInfoResult: Equatable, Hashable { + public static func ==(lhs: SingleAddressInfoResult, rhs: SingleAddressInfoResult) -> Bool { + if lhs.address != rhs.address { + return false + } + if lhs.balance != rhs.balance { + return false + } + if lhs.utxos != rhs.utxos { + return false + } + if lhs.transfers != rhs.transfers { + return false + } + if lhs.blockHeight != rhs.blockHeight { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(address) + hasher.combine(balance) + hasher.combine(utxos) + hasher.combine(transfers) + hasher.combine(blockHeight) + } +} + +extension SingleAddressInfoResult: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeSingleAddressInfoResult: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SingleAddressInfoResult { + return + try SingleAddressInfoResult( + address: FfiConverterString.read(from: &buf), + balance: FfiConverterUInt64.read(from: &buf), + utxos: FfiConverterSequenceTypeAccountUtxo.read(from: &buf), + transfers: FfiConverterUInt32.read(from: &buf), + blockHeight: FfiConverterUInt32.read(from: &buf) + ) + } + + public static func write(_ value: SingleAddressInfoResult, into buf: inout [UInt8]) { + FfiConverterString.write(value.address, into: &buf) + FfiConverterUInt64.write(value.balance, into: &buf) + FfiConverterSequenceTypeAccountUtxo.write(value.utxos, into: &buf) + FfiConverterUInt32.write(value.transfers, into: &buf) + FfiConverterUInt32.write(value.blockHeight, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeSingleAddressInfoResult_lift(_ buf: RustBuffer) throws -> SingleAddressInfoResult { + return try FfiConverterTypeSingleAddressInfoResult.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeSingleAddressInfoResult_lower(_ value: SingleAddressInfoResult) -> RustBuffer { + return FfiConverterTypeSingleAddressInfoResult.lower(value) +} + + public struct SweepResult { /** * The transaction ID of the sweep transaction @@ -8402,6 +8963,107 @@ public func FfiConverterTypeTrezorFeatures_lower(_ value: TrezorFeatures) -> Rus } +/** + * Fee level for transaction composition. + */ +public struct TrezorFeeLevel { + /** + * Fee rate in sat/vB + */ + public var feePerUnit: String + /** + * Base fee in satoshis (optional, added to calculated fee) + */ + public var baseFee: UInt64? + /** + * Whether to use floor for base fee calculation + */ + public var floorBaseFee: Bool? + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Fee rate in sat/vB + */feePerUnit: String, + /** + * Base fee in satoshis (optional, added to calculated fee) + */baseFee: UInt64?, + /** + * Whether to use floor for base fee calculation + */floorBaseFee: Bool?) { + self.feePerUnit = feePerUnit + self.baseFee = baseFee + self.floorBaseFee = floorBaseFee + } +} + +#if compiler(>=6) +extension TrezorFeeLevel: Sendable {} +#endif + + +extension TrezorFeeLevel: Equatable, Hashable { + public static func ==(lhs: TrezorFeeLevel, rhs: TrezorFeeLevel) -> Bool { + if lhs.feePerUnit != rhs.feePerUnit { + return false + } + if lhs.baseFee != rhs.baseFee { + return false + } + if lhs.floorBaseFee != rhs.floorBaseFee { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(feePerUnit) + hasher.combine(baseFee) + hasher.combine(floorBaseFee) + } +} + +extension TrezorFeeLevel: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorFeeLevel: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorFeeLevel { + return + try TrezorFeeLevel( + feePerUnit: FfiConverterString.read(from: &buf), + baseFee: FfiConverterOptionUInt64.read(from: &buf), + floorBaseFee: FfiConverterOptionBool.read(from: &buf) + ) + } + + public static func write(_ value: TrezorFeeLevel, into buf: inout [UInt8]) { + FfiConverterString.write(value.feePerUnit, into: &buf) + FfiConverterOptionUInt64.write(value.baseFee, into: &buf) + FfiConverterOptionBool.write(value.floorBaseFee, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorFeeLevel_lift(_ buf: RustBuffer) throws -> TrezorFeeLevel { + return try FfiConverterTypeTrezorFeeLevel.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorFeeLevel_lower(_ value: TrezorFeeLevel) -> RustBuffer { + return FfiConverterTypeTrezorFeeLevel.lower(value) +} + + /** * Parameters for getting an address from the device. */ @@ -8619,76 +9281,362 @@ public func FfiConverterTypeTrezorGetPublicKeyParams_lower(_ value: TrezorGetPub /** - * Previous transaction data (for non-SegWit input verification). + * Parameters for precompose transaction. */ -public struct TrezorPrevTx { +public struct TrezorPrecomposeParams { /** - * Transaction hash (hex encoded) + * Desired outputs */ - public var hash: String + public var outputs: [TrezorPrecomposeOutput] /** - * Transaction version + * Coin name (e.g., "Bitcoin", "Regtest") */ - public var version: UInt32 + public var coin: String /** - * Lock time + * Account with UTXOs and addresses */ - public var lockTime: UInt32 + public var account: ComposeAccount /** - * Transaction inputs + * Fee levels to evaluate */ - public var inputs: [TrezorPrevTxInput] + public var feeLevels: [TrezorFeeLevel] /** - * Transaction outputs + * Default sequence number */ - public var outputs: [TrezorPrevTxOutput] + public var sequence: UInt32? + /** + * Sorting strategy for inputs/outputs + */ + public var sortingStrategy: TrezorSortingStrategy? // Default memberwise initializers are never public by default, so we // declare one manually. public init( /** - * Transaction hash (hex encoded) - */hash: String, + * Desired outputs + */outputs: [TrezorPrecomposeOutput], /** - * Transaction version - */version: UInt32, + * Coin name (e.g., "Bitcoin", "Regtest") + */coin: String, /** - * Lock time - */lockTime: UInt32, + * Account with UTXOs and addresses + */account: ComposeAccount, /** - * Transaction inputs - */inputs: [TrezorPrevTxInput], + * Fee levels to evaluate + */feeLevels: [TrezorFeeLevel], /** - * Transaction outputs - */outputs: [TrezorPrevTxOutput]) { - self.hash = hash - self.version = version - self.lockTime = lockTime - self.inputs = inputs + * Default sequence number + */sequence: UInt32?, + /** + * Sorting strategy for inputs/outputs + */sortingStrategy: TrezorSortingStrategy?) { self.outputs = outputs + self.coin = coin + self.account = account + self.feeLevels = feeLevels + self.sequence = sequence + self.sortingStrategy = sortingStrategy } } #if compiler(>=6) -extension TrezorPrevTx: Sendable {} +extension TrezorPrecomposeParams: Sendable {} #endif -extension TrezorPrevTx: Equatable, Hashable { - public static func ==(lhs: TrezorPrevTx, rhs: TrezorPrevTx) -> Bool { - if lhs.hash != rhs.hash { +extension TrezorPrecomposeParams: Equatable, Hashable { + public static func ==(lhs: TrezorPrecomposeParams, rhs: TrezorPrecomposeParams) -> Bool { + if lhs.outputs != rhs.outputs { return false } - if lhs.version != rhs.version { + if lhs.coin != rhs.coin { return false } - if lhs.lockTime != rhs.lockTime { + if lhs.account != rhs.account { return false } - if lhs.inputs != rhs.inputs { + if lhs.feeLevels != rhs.feeLevels { return false } - if lhs.outputs != rhs.outputs { + if lhs.sequence != rhs.sequence { + return false + } + if lhs.sortingStrategy != rhs.sortingStrategy { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(outputs) + hasher.combine(coin) + hasher.combine(account) + hasher.combine(feeLevels) + hasher.combine(sequence) + hasher.combine(sortingStrategy) + } +} + +extension TrezorPrecomposeParams: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorPrecomposeParams: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorPrecomposeParams { + return + try TrezorPrecomposeParams( + outputs: FfiConverterSequenceTypeTrezorPrecomposeOutput.read(from: &buf), + coin: FfiConverterString.read(from: &buf), + account: FfiConverterTypeComposeAccount.read(from: &buf), + feeLevels: FfiConverterSequenceTypeTrezorFeeLevel.read(from: &buf), + sequence: FfiConverterOptionUInt32.read(from: &buf), + sortingStrategy: FfiConverterOptionTypeTrezorSortingStrategy.read(from: &buf) + ) + } + + public static func write(_ value: TrezorPrecomposeParams, into buf: inout [UInt8]) { + FfiConverterSequenceTypeTrezorPrecomposeOutput.write(value.outputs, into: &buf) + FfiConverterString.write(value.coin, into: &buf) + FfiConverterTypeComposeAccount.write(value.account, into: &buf) + FfiConverterSequenceTypeTrezorFeeLevel.write(value.feeLevels, into: &buf) + FfiConverterOptionUInt32.write(value.sequence, into: &buf) + FfiConverterOptionTypeTrezorSortingStrategy.write(value.sortingStrategy, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposeParams_lift(_ buf: RustBuffer) throws -> TrezorPrecomposeParams { + return try FfiConverterTypeTrezorPrecomposeParams.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposeParams_lower(_ value: TrezorPrecomposeParams) -> RustBuffer { + return FfiConverterTypeTrezorPrecomposeParams.lower(value) +} + + +/** + * Input in a precomposed result. + */ +public struct TrezorPrecomposedInput { + /** + * Transaction ID (hex) + */ + public var txid: String + /** + * Output index + */ + public var vout: UInt32 + /** + * Amount in satoshis (as string) + */ + public var amount: String + /** + * Address + */ + public var address: String + /** + * BIP32 derivation path + */ + public var path: String + /** + * Script type + */ + public var scriptType: TrezorScriptType + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Transaction ID (hex) + */txid: String, + /** + * Output index + */vout: UInt32, + /** + * Amount in satoshis (as string) + */amount: String, + /** + * Address + */address: String, + /** + * BIP32 derivation path + */path: String, + /** + * Script type + */scriptType: TrezorScriptType) { + self.txid = txid + self.vout = vout + self.amount = amount + self.address = address + self.path = path + self.scriptType = scriptType + } +} + +#if compiler(>=6) +extension TrezorPrecomposedInput: Sendable {} +#endif + + +extension TrezorPrecomposedInput: Equatable, Hashable { + public static func ==(lhs: TrezorPrecomposedInput, rhs: TrezorPrecomposedInput) -> Bool { + if lhs.txid != rhs.txid { + return false + } + if lhs.vout != rhs.vout { + return false + } + if lhs.amount != rhs.amount { + return false + } + if lhs.address != rhs.address { + return false + } + if lhs.path != rhs.path { + return false + } + if lhs.scriptType != rhs.scriptType { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(txid) + hasher.combine(vout) + hasher.combine(amount) + hasher.combine(address) + hasher.combine(path) + hasher.combine(scriptType) + } +} + +extension TrezorPrecomposedInput: Codable {} + + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorPrecomposedInput: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorPrecomposedInput { + return + try TrezorPrecomposedInput( + txid: FfiConverterString.read(from: &buf), + vout: FfiConverterUInt32.read(from: &buf), + amount: FfiConverterString.read(from: &buf), + address: FfiConverterString.read(from: &buf), + path: FfiConverterString.read(from: &buf), + scriptType: FfiConverterTypeTrezorScriptType.read(from: &buf) + ) + } + + public static func write(_ value: TrezorPrecomposedInput, into buf: inout [UInt8]) { + FfiConverterString.write(value.txid, into: &buf) + FfiConverterUInt32.write(value.vout, into: &buf) + FfiConverterString.write(value.amount, into: &buf) + FfiConverterString.write(value.address, into: &buf) + FfiConverterString.write(value.path, into: &buf) + FfiConverterTypeTrezorScriptType.write(value.scriptType, into: &buf) + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedInput_lift(_ buf: RustBuffer) throws -> TrezorPrecomposedInput { + return try FfiConverterTypeTrezorPrecomposedInput.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedInput_lower(_ value: TrezorPrecomposedInput) -> RustBuffer { + return FfiConverterTypeTrezorPrecomposedInput.lower(value) +} + + +/** + * Previous transaction data (for non-SegWit input verification). + */ +public struct TrezorPrevTx { + /** + * Transaction hash (hex encoded) + */ + public var hash: String + /** + * Transaction version + */ + public var version: UInt32 + /** + * Lock time + */ + public var lockTime: UInt32 + /** + * Transaction inputs + */ + public var inputs: [TrezorPrevTxInput] + /** + * Transaction outputs + */ + public var outputs: [TrezorPrevTxOutput] + + // Default memberwise initializers are never public by default, so we + // declare one manually. + public init( + /** + * Transaction hash (hex encoded) + */hash: String, + /** + * Transaction version + */version: UInt32, + /** + * Lock time + */lockTime: UInt32, + /** + * Transaction inputs + */inputs: [TrezorPrevTxInput], + /** + * Transaction outputs + */outputs: [TrezorPrevTxOutput]) { + self.hash = hash + self.version = version + self.lockTime = lockTime + self.inputs = inputs + self.outputs = outputs + } +} + +#if compiler(>=6) +extension TrezorPrevTx: Sendable {} +#endif + + +extension TrezorPrevTx: Equatable, Hashable { + public static func ==(lhs: TrezorPrevTx, rhs: TrezorPrevTx) -> Bool { + if lhs.hash != rhs.hash { + return false + } + if lhs.version != rhs.version { + return false + } + if lhs.lockTime != rhs.lockTime { + return false + } + if lhs.inputs != rhs.inputs { + return false + } + if lhs.outputs != rhs.outputs { return false } return true @@ -9449,6 +10397,10 @@ public struct TrezorSignedTx { * Serialized transaction (hex) */ public var serializedTx: String + /** + * Broadcast transaction ID (populated when push=true) + */ + public var txid: String? // Default memberwise initializers are never public by default, so we // declare one manually. @@ -9458,9 +10410,13 @@ public struct TrezorSignedTx { */signatures: [String], /** * Serialized transaction (hex) - */serializedTx: String) { + */serializedTx: String, + /** + * Broadcast transaction ID (populated when push=true) + */txid: String?) { self.signatures = signatures self.serializedTx = serializedTx + self.txid = txid } } @@ -9477,12 +10433,16 @@ extension TrezorSignedTx: Equatable, Hashable { if lhs.serializedTx != rhs.serializedTx { return false } + if lhs.txid != rhs.txid { + return false + } return true } public func hash(into hasher: inout Hasher) { hasher.combine(signatures) hasher.combine(serializedTx) + hasher.combine(txid) } } @@ -9498,13 +10458,15 @@ public struct FfiConverterTypeTrezorSignedTx: FfiConverterRustBuffer { return try TrezorSignedTx( signatures: FfiConverterSequenceString.read(from: &buf), - serializedTx: FfiConverterString.read(from: &buf) + serializedTx: FfiConverterString.read(from: &buf), + txid: FfiConverterOptionString.read(from: &buf) ) } public static func write(_ value: TrezorSignedTx, into buf: inout [UInt8]) { FfiConverterSequenceString.write(value.signatures, into: &buf) FfiConverterString.write(value.serializedTx, into: &buf) + FfiConverterOptionString.write(value.txid, into: &buf) } } @@ -10492,24 +11454,305 @@ public func FfiConverterTypeValidationResult_lower(_ value: ValidationResult) -> return FfiConverterTypeValidationResult.lower(value) } -// Note that we don't yet support `indirect` for enums. -// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -public enum Activity { +/** + * Errors specific to account info operations (BDK/Electrum-based). + * + * These are separate from `TrezorError` because account info operations + * do not interact with a Trezor device — they only query the blockchain. + */ +public enum AccountInfoError: Swift.Error { + - case onchain(OnchainActivity + + /** + * The provided extended public key is invalid or cannot be parsed + */ + case InvalidExtendedKey(errorDetails: String ) - case lightning(LightningActivity + /** + * The provided address is invalid + */ + case InvalidAddress(errorDetails: String ) -} - - -#if compiler(>=6) -extension Activity: Sendable {} -#endif - -#if swift(>=5.8) -@_documentation(visibility: private) + /** + * Electrum connection or query failed + */ + case ElectrumError(errorDetails: String + ) + /** + * BDK wallet creation or operation error + */ + case WalletError(errorDetails: String + ) + /** + * Wallet sync with Electrum failed + */ + case SyncError(errorDetails: String + ) + /** + * The key type/prefix is not recognized + */ + case UnsupportedKeyType(errorDetails: String + ) + /** + * Network mismatch between key prefix and specified network + */ + case NetworkMismatch(errorDetails: String + ) + /** + * Invalid transaction ID provided + */ + case InvalidTxid(errorDetails: String + ) +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeAccountInfoError: FfiConverterRustBuffer { + typealias SwiftType = AccountInfoError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountInfoError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .InvalidExtendedKey( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 2: return .InvalidAddress( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 3: return .ElectrumError( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 4: return .WalletError( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 5: return .SyncError( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 6: return .UnsupportedKeyType( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 7: return .NetworkMismatch( + errorDetails: try FfiConverterString.read(from: &buf) + ) + case 8: return .InvalidTxid( + errorDetails: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AccountInfoError, into buf: inout [UInt8]) { + switch value { + + + + + + case let .InvalidExtendedKey(errorDetails): + writeInt(&buf, Int32(1)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .InvalidAddress(errorDetails): + writeInt(&buf, Int32(2)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .ElectrumError(errorDetails): + writeInt(&buf, Int32(3)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .WalletError(errorDetails): + writeInt(&buf, Int32(4)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .SyncError(errorDetails): + writeInt(&buf, Int32(5)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .UnsupportedKeyType(errorDetails): + writeInt(&buf, Int32(6)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .NetworkMismatch(errorDetails): + writeInt(&buf, Int32(7)) + FfiConverterString.write(errorDetails, into: &buf) + + + case let .InvalidTxid(errorDetails): + writeInt(&buf, Int32(8)) + FfiConverterString.write(errorDetails, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountInfoError_lift(_ buf: RustBuffer) throws -> AccountInfoError { + return try FfiConverterTypeAccountInfoError.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountInfoError_lower(_ value: AccountInfoError) -> RustBuffer { + return FfiConverterTypeAccountInfoError.lower(value) +} + + +extension AccountInfoError: Equatable, Hashable {} + +extension AccountInfoError: Codable {} + + + + +extension AccountInfoError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +/** + * Account type classification for extended public keys. + * + * Determines the BIP standard, derivation path purpose, and script type. + */ + +public enum AccountType { + + /** + * BIP44 legacy (P2PKH) — xpub/tpub prefix + */ + case legacy + /** + * BIP49 wrapped segwit (P2SH-P2WPKH) — ypub/upub prefix + */ + case wrappedSegwit + /** + * BIP84 native segwit (P2WPKH) — zpub/vpub prefix + */ + case nativeSegwit + /** + * BIP86 taproot (P2TR) + */ + case taproot +} + + +#if compiler(>=6) +extension AccountType: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeAccountType: FfiConverterRustBuffer { + typealias SwiftType = AccountType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> AccountType { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .legacy + + case 2: return .wrappedSegwit + + case 3: return .nativeSegwit + + case 4: return .taproot + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: AccountType, into buf: inout [UInt8]) { + switch value { + + + case .legacy: + writeInt(&buf, Int32(1)) + + + case .wrappedSegwit: + writeInt(&buf, Int32(2)) + + + case .nativeSegwit: + writeInt(&buf, Int32(3)) + + + case .taproot: + writeInt(&buf, Int32(4)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountType_lift(_ buf: RustBuffer) throws -> AccountType { + return try FfiConverterTypeAccountType.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeAccountType_lower(_ value: AccountType) -> RustBuffer { + return FfiConverterTypeAccountType.lower(value) +} + + +extension AccountType: Equatable, Hashable {} + +extension AccountType: Codable {} + + + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. + +public enum Activity { + + case onchain(OnchainActivity + ) + case lightning(LightningActivity + ) +} + + +#if compiler(>=6) +extension Activity: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) #endif public struct FfiConverterTypeActivity: FfiConverterRustBuffer { typealias SwiftType = Activity @@ -13658,95 +14901,524 @@ extension TrezorError: Foundation.LocalizedError { // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. /** - * Script types for address derivation. + * Output specification for precompose. */ -public enum TrezorScriptType { +public enum TrezorPrecomposeOutput { /** - * P2PKH (legacy) - */ - case spendAddress - /** - * P2SH-P2WPKH (nested SegWit) + * Payment to a specific address */ - case spendP2shWitness + case payment(address: String, amount: String + ) /** - * P2WPKH (native SegWit) + * Payment without address (estimation only) */ - case spendWitness + case paymentNoAddress(amount: String + ) /** - * P2TR (Taproot) + * Send all remaining funds to an address */ - case spendTaproot + case sendMax(address: String + ) /** - * P2SH multisig + * Send all remaining funds (no address) */ - case spendMultisig + case sendMaxNoAddress /** - * External/watch-only input (not signed by device) + * OP_RETURN data output */ - case external + case opReturn(dataHex: String + ) } #if compiler(>=6) -extension TrezorScriptType: Sendable {} +extension TrezorPrecomposeOutput: Sendable {} #endif #if swift(>=5.8) @_documentation(visibility: private) #endif -public struct FfiConverterTypeTrezorScriptType: FfiConverterRustBuffer { - typealias SwiftType = TrezorScriptType +public struct FfiConverterTypeTrezorPrecomposeOutput: FfiConverterRustBuffer { + typealias SwiftType = TrezorPrecomposeOutput - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorScriptType { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorPrecomposeOutput { let variant: Int32 = try readInt(&buf) switch variant { - case 1: return .spendAddress + case 1: return .payment(address: try FfiConverterString.read(from: &buf), amount: try FfiConverterString.read(from: &buf) + ) - case 2: return .spendP2shWitness + case 2: return .paymentNoAddress(amount: try FfiConverterString.read(from: &buf) + ) - case 3: return .spendWitness + case 3: return .sendMax(address: try FfiConverterString.read(from: &buf) + ) + + case 4: return .sendMaxNoAddress + + case 5: return .opReturn(dataHex: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: TrezorPrecomposeOutput, into buf: inout [UInt8]) { + switch value { + + + case let .payment(address,amount): + writeInt(&buf, Int32(1)) + FfiConverterString.write(address, into: &buf) + FfiConverterString.write(amount, into: &buf) + + + case let .paymentNoAddress(amount): + writeInt(&buf, Int32(2)) + FfiConverterString.write(amount, into: &buf) + + + case let .sendMax(address): + writeInt(&buf, Int32(3)) + FfiConverterString.write(address, into: &buf) + + + case .sendMaxNoAddress: + writeInt(&buf, Int32(4)) + + + case let .opReturn(dataHex): + writeInt(&buf, Int32(5)) + FfiConverterString.write(dataHex, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposeOutput_lift(_ buf: RustBuffer) throws -> TrezorPrecomposeOutput { + return try FfiConverterTypeTrezorPrecomposeOutput.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposeOutput_lower(_ value: TrezorPrecomposeOutput) -> RustBuffer { + return FfiConverterTypeTrezorPrecomposeOutput.lower(value) +} + + +extension TrezorPrecomposeOutput: Equatable, Hashable {} + +extension TrezorPrecomposeOutput: Codable {} + + + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +/** + * Output in a precomposed result. + */ + +public enum TrezorPrecomposedOutput { + + /** + * Payment to an address + */ + case payment(address: String, amount: String + ) + /** + * Change output + */ + case change(address: String, path: String, amount: String, scriptType: TrezorScriptType + ) + /** + * OP_RETURN data output + */ + case opReturn(dataHex: String + ) +} + + +#if compiler(>=6) +extension TrezorPrecomposedOutput: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorPrecomposedOutput: FfiConverterRustBuffer { + typealias SwiftType = TrezorPrecomposedOutput + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorPrecomposedOutput { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .payment(address: try FfiConverterString.read(from: &buf), amount: try FfiConverterString.read(from: &buf) + ) + + case 2: return .change(address: try FfiConverterString.read(from: &buf), path: try FfiConverterString.read(from: &buf), amount: try FfiConverterString.read(from: &buf), scriptType: try FfiConverterTypeTrezorScriptType.read(from: &buf) + ) + + case 3: return .opReturn(dataHex: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: TrezorPrecomposedOutput, into buf: inout [UInt8]) { + switch value { + + + case let .payment(address,amount): + writeInt(&buf, Int32(1)) + FfiConverterString.write(address, into: &buf) + FfiConverterString.write(amount, into: &buf) + + + case let .change(address,path,amount,scriptType): + writeInt(&buf, Int32(2)) + FfiConverterString.write(address, into: &buf) + FfiConverterString.write(path, into: &buf) + FfiConverterString.write(amount, into: &buf) + FfiConverterTypeTrezorScriptType.write(scriptType, into: &buf) + + + case let .opReturn(dataHex): + writeInt(&buf, Int32(3)) + FfiConverterString.write(dataHex, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedOutput_lift(_ buf: RustBuffer) throws -> TrezorPrecomposedOutput { + return try FfiConverterTypeTrezorPrecomposedOutput.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedOutput_lower(_ value: TrezorPrecomposedOutput) -> RustBuffer { + return FfiConverterTypeTrezorPrecomposedOutput.lower(value) +} + + +extension TrezorPrecomposedOutput: Equatable, Hashable {} + +extension TrezorPrecomposedOutput: Codable {} + + + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +/** + * Precomposed transaction result (one per fee level). + */ + +public enum TrezorPrecomposedResult { + + /** + * Successfully composed a sendable transaction + */ + case final(totalSpent: String, fee: String, feePerByte: String, bytes: UInt32, inputs: [TrezorPrecomposedInput], outputs: [TrezorPrecomposedOutput], outputsPermutation: [UInt32] + ) + /** + * Non-final result (e.g., send-max estimation) + */ + case nonFinal(max: String?, totalSpent: String, fee: String, feePerByte: String, bytes: UInt32 + ) + /** + * Composition failed + */ + case error(error: String + ) +} + + +#if compiler(>=6) +extension TrezorPrecomposedResult: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorPrecomposedResult: FfiConverterRustBuffer { + typealias SwiftType = TrezorPrecomposedResult + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorPrecomposedResult { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .final(totalSpent: try FfiConverterString.read(from: &buf), fee: try FfiConverterString.read(from: &buf), feePerByte: try FfiConverterString.read(from: &buf), bytes: try FfiConverterUInt32.read(from: &buf), inputs: try FfiConverterSequenceTypeTrezorPrecomposedInput.read(from: &buf), outputs: try FfiConverterSequenceTypeTrezorPrecomposedOutput.read(from: &buf), outputsPermutation: try FfiConverterSequenceUInt32.read(from: &buf) + ) + + case 2: return .nonFinal(max: try FfiConverterOptionString.read(from: &buf), totalSpent: try FfiConverterString.read(from: &buf), fee: try FfiConverterString.read(from: &buf), feePerByte: try FfiConverterString.read(from: &buf), bytes: try FfiConverterUInt32.read(from: &buf) + ) + + case 3: return .error(error: try FfiConverterString.read(from: &buf) + ) + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: TrezorPrecomposedResult, into buf: inout [UInt8]) { + switch value { + + + case let .final(totalSpent,fee,feePerByte,bytes,inputs,outputs,outputsPermutation): + writeInt(&buf, Int32(1)) + FfiConverterString.write(totalSpent, into: &buf) + FfiConverterString.write(fee, into: &buf) + FfiConverterString.write(feePerByte, into: &buf) + FfiConverterUInt32.write(bytes, into: &buf) + FfiConverterSequenceTypeTrezorPrecomposedInput.write(inputs, into: &buf) + FfiConverterSequenceTypeTrezorPrecomposedOutput.write(outputs, into: &buf) + FfiConverterSequenceUInt32.write(outputsPermutation, into: &buf) + + + case let .nonFinal(max,totalSpent,fee,feePerByte,bytes): + writeInt(&buf, Int32(2)) + FfiConverterOptionString.write(max, into: &buf) + FfiConverterString.write(totalSpent, into: &buf) + FfiConverterString.write(fee, into: &buf) + FfiConverterString.write(feePerByte, into: &buf) + FfiConverterUInt32.write(bytes, into: &buf) + + + case let .error(error): + writeInt(&buf, Int32(3)) + FfiConverterString.write(error, into: &buf) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedResult_lift(_ buf: RustBuffer) throws -> TrezorPrecomposedResult { + return try FfiConverterTypeTrezorPrecomposedResult.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorPrecomposedResult_lower(_ value: TrezorPrecomposedResult) -> RustBuffer { + return FfiConverterTypeTrezorPrecomposedResult.lower(value) +} + + +extension TrezorPrecomposedResult: Equatable, Hashable {} + +extension TrezorPrecomposedResult: Codable {} + + + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +/** + * Script types for address derivation. + */ + +public enum TrezorScriptType { + + /** + * P2PKH (legacy) + */ + case spendAddress + /** + * P2SH-P2WPKH (nested SegWit) + */ + case spendP2shWitness + /** + * P2WPKH (native SegWit) + */ + case spendWitness + /** + * P2TR (Taproot) + */ + case spendTaproot + /** + * P2SH multisig + */ + case spendMultisig + /** + * External/watch-only input (not signed by device) + */ + case external +} + + +#if compiler(>=6) +extension TrezorScriptType: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorScriptType: FfiConverterRustBuffer { + typealias SwiftType = TrezorScriptType + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorScriptType { + let variant: Int32 = try readInt(&buf) + switch variant { + + case 1: return .spendAddress + + case 2: return .spendP2shWitness + + case 3: return .spendWitness + + case 4: return .spendTaproot + + case 5: return .spendMultisig + + case 6: return .external + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: TrezorScriptType, into buf: inout [UInt8]) { + switch value { + + + case .spendAddress: + writeInt(&buf, Int32(1)) + + + case .spendP2shWitness: + writeInt(&buf, Int32(2)) + + + case .spendWitness: + writeInt(&buf, Int32(3)) + + + case .spendTaproot: + writeInt(&buf, Int32(4)) + + + case .spendMultisig: + writeInt(&buf, Int32(5)) + + + case .external: + writeInt(&buf, Int32(6)) + + } + } +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorScriptType_lift(_ buf: RustBuffer) throws -> TrezorScriptType { + return try FfiConverterTypeTrezorScriptType.lift(buf) +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public func FfiConverterTypeTrezorScriptType_lower(_ value: TrezorScriptType) -> RustBuffer { + return FfiConverterTypeTrezorScriptType.lower(value) +} + + +extension TrezorScriptType: Equatable, Hashable {} + +extension TrezorScriptType: Codable {} + + + + + + +// Note that we don't yet support `indirect` for enums. +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. +/** + * Sorting strategy for transaction inputs and outputs. + */ + +public enum TrezorSortingStrategy { + + /** + * BIP-69: deterministic lexicographic sorting + */ + case bip69 + /** + * Random shuffle (better privacy) + */ + case random + /** + * Keep original order + */ + case none +} + + +#if compiler(>=6) +extension TrezorSortingStrategy: Sendable {} +#endif + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeTrezorSortingStrategy: FfiConverterRustBuffer { + typealias SwiftType = TrezorSortingStrategy + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> TrezorSortingStrategy { + let variant: Int32 = try readInt(&buf) + switch variant { - case 4: return .spendTaproot + case 1: return .bip69 - case 5: return .spendMultisig + case 2: return .random - case 6: return .external + case 3: return .none default: throw UniffiInternalError.unexpectedEnumCase } } - public static func write(_ value: TrezorScriptType, into buf: inout [UInt8]) { + public static func write(_ value: TrezorSortingStrategy, into buf: inout [UInt8]) { switch value { - case .spendAddress: + case .bip69: writeInt(&buf, Int32(1)) - case .spendP2shWitness: + case .random: writeInt(&buf, Int32(2)) - case .spendWitness: + case .none: writeInt(&buf, Int32(3)) - - case .spendTaproot: - writeInt(&buf, Int32(4)) - - - case .spendMultisig: - writeInt(&buf, Int32(5)) - - - case .external: - writeInt(&buf, Int32(6)) - } } } @@ -13755,21 +15427,21 @@ public struct FfiConverterTypeTrezorScriptType: FfiConverterRustBuffer { #if swift(>=5.8) @_documentation(visibility: private) #endif -public func FfiConverterTypeTrezorScriptType_lift(_ buf: RustBuffer) throws -> TrezorScriptType { - return try FfiConverterTypeTrezorScriptType.lift(buf) +public func FfiConverterTypeTrezorSortingStrategy_lift(_ buf: RustBuffer) throws -> TrezorSortingStrategy { + return try FfiConverterTypeTrezorSortingStrategy.lift(buf) } #if swift(>=5.8) @_documentation(visibility: private) #endif -public func FfiConverterTypeTrezorScriptType_lower(_ value: TrezorScriptType) -> RustBuffer { - return FfiConverterTypeTrezorScriptType.lower(value) +public func FfiConverterTypeTrezorSortingStrategy_lower(_ value: TrezorSortingStrategy) -> RustBuffer { + return FfiConverterTypeTrezorSortingStrategy.lower(value) } -extension TrezorScriptType: Equatable, Hashable {} +extension TrezorSortingStrategy: Equatable, Hashable {} -extension TrezorScriptType: Codable {} +extension TrezorSortingStrategy: Codable {} @@ -14901,6 +16573,30 @@ fileprivate struct FfiConverterOptionTypeTrezorScriptType: FfiConverterRustBuffe } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterOptionTypeTrezorSortingStrategy: FfiConverterRustBuffer { + typealias SwiftType = TrezorSortingStrategy? + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + guard let value = value else { + writeInt(&buf, Int8(0)) + return + } + writeInt(&buf, Int8(1)) + FfiConverterTypeTrezorSortingStrategy.write(value, into: &buf) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + switch try readInt(&buf) as Int8 { + case 0: return nil + case 1: return try FfiConverterTypeTrezorSortingStrategy.read(from: &buf) + default: throw UniffiInternalError.unexpectedOptionalTag + } + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -14997,6 +16693,31 @@ fileprivate struct FfiConverterOptionDictionaryStringString: FfiConverterRustBuf } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceUInt32: FfiConverterRustBuffer { + typealias SwiftType = [UInt32] + + public static func write(_ value: [UInt32], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterUInt32.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [UInt32] { + let len: Int32 = try readInt(&buf) + var seq = [UInt32]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterUInt32.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -15022,6 +16743,31 @@ fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer { } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeAccountUtxo: FfiConverterRustBuffer { + typealias SwiftType = [AccountUtxo] + + public static func write(_ value: [AccountUtxo], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeAccountUtxo.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [AccountUtxo] { + let len: Int32 = try readInt(&buf) + var seq = [AccountUtxo]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeAccountUtxo.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -15397,6 +17143,56 @@ fileprivate struct FfiConverterSequenceTypeTrezorDeviceInfo: FfiConverterRustBuf } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeTrezorFeeLevel: FfiConverterRustBuffer { + typealias SwiftType = [TrezorFeeLevel] + + public static func write(_ value: [TrezorFeeLevel], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTrezorFeeLevel.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TrezorFeeLevel] { + let len: Int32 = try readInt(&buf) + var seq = [TrezorFeeLevel]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTrezorFeeLevel.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeTrezorPrecomposedInput: FfiConverterRustBuffer { + typealias SwiftType = [TrezorPrecomposedInput] + + public static func write(_ value: [TrezorPrecomposedInput], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTrezorPrecomposedInput.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TrezorPrecomposedInput] { + let len: Int32 = try readInt(&buf) + var seq = [TrezorPrecomposedInput]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTrezorPrecomposedInput.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -15597,6 +17393,81 @@ fileprivate struct FfiConverterSequenceTypeActivity: FfiConverterRustBuffer { } } +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeTrezorPrecomposeOutput: FfiConverterRustBuffer { + typealias SwiftType = [TrezorPrecomposeOutput] + + public static func write(_ value: [TrezorPrecomposeOutput], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTrezorPrecomposeOutput.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TrezorPrecomposeOutput] { + let len: Int32 = try readInt(&buf) + var seq = [TrezorPrecomposeOutput]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTrezorPrecomposeOutput.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeTrezorPrecomposedOutput: FfiConverterRustBuffer { + typealias SwiftType = [TrezorPrecomposedOutput] + + public static func write(_ value: [TrezorPrecomposedOutput], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTrezorPrecomposedOutput.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TrezorPrecomposedOutput] { + let len: Int32 = try readInt(&buf) + var seq = [TrezorPrecomposedOutput]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTrezorPrecomposedOutput.read(from: &buf)) + } + return seq + } +} + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +fileprivate struct FfiConverterSequenceTypeTrezorPrecomposedResult: FfiConverterRustBuffer { + typealias SwiftType = [TrezorPrecomposedResult] + + public static func write(_ value: [TrezorPrecomposedResult], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeTrezorPrecomposedResult.write(item, into: &buf) + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [TrezorPrecomposedResult] { + let len: Int32 = try readInt(&buf) + var seq = [TrezorPrecomposedResult]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + seq.append(try FfiConverterTypeTrezorPrecomposedResult.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -16484,6 +18355,36 @@ public func testNotification(deviceToken: String, secretMessage: String, notific errorHandler: FfiConverterTypeBlocktankError_lift ) } +/** + * Convert an account type to its corresponding script type. + */ +public func trezorAccountTypeToScriptType(accountType: AccountType) -> TrezorScriptType { + return try! FfiConverterTypeTrezorScriptType_lift(try! rustCall() { + uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type( + FfiConverterTypeAccountType_lower(accountType),$0 + ) +}) +} +/** + * Broadcast a signed raw transaction via Electrum. + * + * Takes a hex-encoded serialized transaction and an Electrum server URL. + * Returns the transaction ID on success. + */ +public func trezorBroadcastRawTx(serializedTx: String, electrumUrl: String)async throws -> String { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx(FfiConverterString.lower(serializedTx),FfiConverterString.lower(electrumUrl) + ) + }, + pollFunc: ffi_bitkitcore_rust_future_poll_rust_buffer, + completeFunc: ffi_bitkitcore_rust_future_complete_rust_buffer, + freeFunc: ffi_bitkitcore_rust_future_free_rust_buffer, + liftFunc: FfiConverterString.lift, + errorHandler: FfiConverterTypeAccountInfoError_lift + ) +} /** * Clear stored Bluetooth pairing credentials for a specific Trezor device. * @@ -16541,6 +18442,46 @@ public func trezorDisconnect()async throws { errorHandler: FfiConverterTypeTrezorError_lift ) } +/** + * Fetch previous transactions from Electrum for Trezor signing. + * + * Takes transaction IDs (from TrezorSignTxParams inputs' prev_hash fields), + * fetches the full transactions from Electrum, and returns them as + * TrezorPrevTx structures ready to merge into TrezorSignTxParams.prev_txs. + * + * Duplicate txids are automatically deduplicated. + */ +public func trezorFetchPrevTxs(txids: [String], electrumUrl: String)async throws -> [TrezorPrevTx] { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs(FfiConverterSequenceString.lower(txids),FfiConverterString.lower(electrumUrl) + ) + }, + pollFunc: ffi_bitkitcore_rust_future_poll_rust_buffer, + completeFunc: ffi_bitkitcore_rust_future_complete_rust_buffer, + freeFunc: ffi_bitkitcore_rust_future_free_rust_buffer, + liftFunc: FfiConverterSequenceTypeTrezorPrevTx.lift, + errorHandler: FfiConverterTypeAccountInfoError_lift + ) +} +/** + * Query account information for an extended public key via Electrum. + */ +public func trezorGetAccountInfo(extendedKey: String, electrumUrl: String, network: TrezorCoinType?, gapLimit: UInt32?)async throws -> AccountInfoResult { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_bitkitcore_fn_func_trezor_get_account_info(FfiConverterString.lower(extendedKey),FfiConverterString.lower(electrumUrl),FfiConverterOptionTypeTrezorCoinType.lower(network),FfiConverterOptionUInt32.lower(gapLimit) + ) + }, + pollFunc: ffi_bitkitcore_rust_future_poll_rust_buffer, + completeFunc: ffi_bitkitcore_rust_future_complete_rust_buffer, + freeFunc: ffi_bitkitcore_rust_future_free_rust_buffer, + liftFunc: FfiConverterTypeAccountInfoResult_lift, + errorHandler: FfiConverterTypeAccountInfoError_lift + ) +} /** * Get a Bitcoin address from the connected Trezor device. */ @@ -16558,6 +18499,23 @@ public func trezorGetAddress(params: TrezorGetAddressParams)async throws -> Tre errorHandler: FfiConverterTypeTrezorError_lift ) } +/** + * Query balance and UTXOs for a single Bitcoin address via Electrum. + */ +public func trezorGetAddressInfo(address: String, electrumUrl: String, network: TrezorCoinType?)async throws -> SingleAddressInfoResult { + return + try await uniffiRustCallAsync( + rustFutureFunc: { + uniffi_bitkitcore_fn_func_trezor_get_address_info(FfiConverterString.lower(address),FfiConverterString.lower(electrumUrl),FfiConverterOptionTypeTrezorCoinType.lower(network) + ) + }, + pollFunc: ffi_bitkitcore_rust_future_poll_rust_buffer, + completeFunc: ffi_bitkitcore_rust_future_complete_rust_buffer, + freeFunc: ffi_bitkitcore_rust_future_free_rust_buffer, + liftFunc: FfiConverterTypeSingleAddressInfoResult_lift, + errorHandler: FfiConverterTypeAccountInfoError_lift + ) +} /** * Get information about the currently connected Trezor device. */ @@ -16721,6 +18679,32 @@ public func trezorListDevices()async throws -> [TrezorDeviceInfo] { errorHandler: FfiConverterTypeTrezorError_lift ) } +/** + * Compose a transaction offline for multiple fee levels. + * + * No device interaction needed — pure coin selection and fee calculation. + */ +public func trezorPrecomposeTransaction(params: TrezorPrecomposeParams) -> [TrezorPrecomposedResult] { + return try! FfiConverterSequenceTypeTrezorPrecomposedResult.lift(try! rustCall() { + uniffi_bitkitcore_fn_func_trezor_precompose_transaction( + FfiConverterTypeTrezorPrecomposeParams_lower(params),$0 + ) +}) +} +/** + * Convert precomposed results into signing parameters for trezor_sign_tx. + * + * The returned params have empty prev_txs — add them before signing. + */ +public func trezorPrecomposedToSignParams(inputs: [TrezorPrecomposedInput], outputs: [TrezorPrecomposedOutput], coin: TrezorCoinType?) -> TrezorSignTxParams { + return try! FfiConverterTypeTrezorSignTxParams_lift(try! rustCall() { + uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params( + FfiConverterSequenceTypeTrezorPrecomposedInput.lower(inputs), + FfiConverterSequenceTypeTrezorPrecomposedOutput.lower(outputs), + FfiConverterOptionTypeTrezorCoinType.lower(coin),$0 + ) +}) +} /** * Scan for available Trezor devices (USB + Bluetooth). * @@ -17245,6 +19229,12 @@ private let initializationResult: InitializationResult = { if (uniffi_bitkitcore_checksum_func_test_notification() != 32857) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type() != 48918) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx() != 15100) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_trezor_clear_credentials() != 41940) { return InitializationResult.apiChecksumMismatch } @@ -17254,9 +19244,18 @@ private let initializationResult: InitializationResult = { if (uniffi_bitkitcore_checksum_func_trezor_disconnect() != 48780) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs() != 46921) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_bitkitcore_checksum_func_trezor_get_account_info() != 1783) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_trezor_get_address() != 12910) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_trezor_get_address_info() != 1337) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_trezor_get_connected_device() != 48383) { return InitializationResult.apiChecksumMismatch } @@ -17284,6 +19283,12 @@ private let initializationResult: InitializationResult = { if (uniffi_bitkitcore_checksum_func_trezor_list_devices() != 32859) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_trezor_precompose_transaction() != 56637) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params() != 30193) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_trezor_scan() != 54763) { return InitializationResult.apiChecksumMismatch } diff --git a/bindings/ios/bitkitcoreFFI.h b/bindings/ios/bitkitcoreFFI.h index e2134e2..0f360b1 100644 --- a/bindings/ios/bitkitcoreFFI.h +++ b/bindings/ios/bitkitcoreFFI.h @@ -867,6 +867,16 @@ uint64_t uniffi_bitkitcore_fn_func_start_pubky_auth(RustBuffer caps uint64_t uniffi_bitkitcore_fn_func_test_notification(RustBuffer device_token, RustBuffer secret_message, RustBuffer notification_type, RustBuffer custom_url ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +RustBuffer uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type(RustBuffer account_type, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_BROADCAST_RAW_TX +uint64_t uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx(RustBuffer serialized_tx, RustBuffer electrum_url +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_CLEAR_CREDENTIALS uint64_t uniffi_bitkitcore_fn_func_trezor_clear_credentials(RustBuffer device_id @@ -881,6 +891,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_connect(RustBuffer device_id #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_DISCONNECT uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_FETCH_PREV_TXS +uint64_t uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs(RustBuffer txids, RustBuffer electrum_url +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ACCOUNT_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_account_info(RustBuffer extended_key, RustBuffer electrum_url, RustBuffer network, RustBuffer gap_limit ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS @@ -888,6 +908,11 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_disconnect(void uint64_t uniffi_bitkitcore_fn_func_trezor_get_address(RustBuffer params ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_ADDRESS_INFO +uint64_t uniffi_bitkitcore_fn_func_trezor_get_address_info(RustBuffer address, RustBuffer electrum_url, RustBuffer network +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_GET_CONNECTED_DEVICE uint64_t uniffi_bitkitcore_fn_func_trezor_get_connected_device(void @@ -938,6 +963,16 @@ uint64_t uniffi_bitkitcore_fn_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_LIST_DEVICES uint64_t uniffi_bitkitcore_fn_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +RustBuffer uniffi_bitkitcore_fn_func_trezor_precompose_transaction(RustBuffer params, RustCallStatus *_Nonnull out_status +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +RustBuffer uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params(RustBuffer inputs, RustBuffer outputs, RustBuffer coin, RustCallStatus *_Nonnull out_status ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_TREZOR_SCAN @@ -1820,6 +1855,18 @@ uint16_t uniffi_bitkitcore_checksum_func_start_pubky_auth(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TEST_NOTIFICATION uint16_t uniffi_bitkitcore_checksum_func_test_notification(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_ACCOUNT_TYPE_TO_SCRIPT_TYPE +uint16_t uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_BROADCAST_RAW_TX +uint16_t uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_CLEAR_CREDENTIALS @@ -1838,12 +1885,30 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_connect(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_DISCONNECT uint16_t uniffi_bitkitcore_checksum_func_trezor_disconnect(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_FETCH_PREV_TXS +uint16_t uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ACCOUNT_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_account_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_ADDRESS_INFO +uint16_t uniffi_bitkitcore_checksum_func_trezor_get_address_info(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_GET_CONNECTED_DEVICE @@ -1898,6 +1963,18 @@ uint16_t uniffi_bitkitcore_checksum_func_trezor_is_initialized(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_LIST_DEVICES uint16_t uniffi_bitkitcore_checksum_func_trezor_list_devices(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSE_TRANSACTION +uint16_t uniffi_bitkitcore_checksum_func_trezor_precompose_transaction(void + +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_PRECOMPOSED_TO_SIGN_PARAMS +uint16_t uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_TREZOR_SCAN diff --git a/bindings/python/bitkitcore/bitkitcore.py b/bindings/python/bitkitcore/bitkitcore.py index cbebf11..3186b3d 100644 --- a/bindings/python/bitkitcore/bitkitcore.py +++ b/bindings/python/bitkitcore/bitkitcore.py @@ -617,14 +617,24 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_test_notification() != 32857: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type() != 48918: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx() != 15100: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_clear_credentials() != 41940: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_connect() != 6551: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_disconnect() != 48780: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs() != 46921: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_get_account_info() != 1783: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_get_address() != 12910: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_get_address_info() != 1337: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_get_connected_device() != 48383: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_get_device_fingerprint() != 20344: @@ -643,6 +653,10 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_list_devices() != 32859: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_precompose_transaction() != 56637: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params() != 30193: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_scan() != 54763: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_trezor_set_transport_callback() != 30209: @@ -1421,6 +1435,16 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiRustBuffer, ) _UniffiLib.uniffi_bitkitcore_fn_func_test_notification.restype = ctypes.c_uint64 +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type.restype = _UniffiRustBuffer +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx.restype = ctypes.c_uint64 _UniffiLib.uniffi_bitkitcore_fn_func_trezor_clear_credentials.argtypes = ( _UniffiRustBuffer, ) @@ -1432,10 +1456,28 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_fn_func_trezor_disconnect.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_fn_func_trezor_disconnect.restype = ctypes.c_uint64 +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs.restype = ctypes.c_uint64 +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_account_info.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_account_info.restype = ctypes.c_uint64 _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address.argtypes = ( _UniffiRustBuffer, ) _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address.restype = ctypes.c_uint64 +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address_info.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address_info.restype = ctypes.c_uint64 _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_connected_device.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_connected_device.restype = ctypes.c_uint64 @@ -1466,6 +1508,18 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_fn_func_trezor_list_devices.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_fn_func_trezor_list_devices.restype = ctypes.c_uint64 +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precompose_transaction.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precompose_transaction.restype = _UniffiRustBuffer +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params.argtypes = ( + _UniffiRustBuffer, + _UniffiRustBuffer, + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params.restype = _UniffiRustBuffer _UniffiLib.uniffi_bitkitcore_fn_func_trezor_scan.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_fn_func_trezor_scan.restype = ctypes.c_uint64 @@ -2086,6 +2140,12 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_checksum_func_test_notification.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_test_notification.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_account_type_to_script_type.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_broadcast_raw_tx.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_clear_credentials.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_clear_credentials.restype = ctypes.c_uint16 @@ -2095,9 +2155,18 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_disconnect.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_disconnect.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_fetch_prev_txs.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_account_info.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_account_info.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_address.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_address.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_address_info.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_address_info.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_connected_device.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_get_connected_device.restype = ctypes.c_uint16 @@ -2125,6 +2194,12 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_list_devices.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_list_devices.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_precompose_transaction.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_precompose_transaction.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_trezor_precomposed_to_sign_params.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_scan.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_trezor_scan.restype = ctypes.c_uint16 @@ -2424,17 +2499,17 @@ def write(value, buf): class AccountAddresses: """ - Account addresses + Grouped address lists for an account. """ used: "typing.List[AddressInfo]" """ - Used addresses + Used receive addresses (have at least one transaction) """ unused: "typing.List[AddressInfo]" """ - Unused addresses + Unused receive addresses (no transactions yet) """ change: "typing.List[AddressInfo]" @@ -2481,6 +2556,223 @@ def write(value, buf): _UniffiConverterSequenceTypeAddressInfo.write(value.change, buf) +class AccountInfoResult: + """ + Result from querying an extended public key — ready for Trezor compose. + """ + + account: "ComposeAccount" + """ + The compose-compatible account structure + """ + + balance: "int" + """ + Total confirmed balance in satoshis + """ + + utxo_count: "int" + """ + Number of UTXOs + """ + + account_type: "AccountType" + """ + The detected or specified account type + """ + + block_height: "int" + """ + The current blockchain tip height + """ + + def __init__(self, *, account: "ComposeAccount", balance: "int", utxo_count: "int", account_type: "AccountType", block_height: "int"): + self.account = account + self.balance = balance + self.utxo_count = utxo_count + self.account_type = account_type + self.block_height = block_height + + def __str__(self): + return "AccountInfoResult(account={}, balance={}, utxo_count={}, account_type={}, block_height={})".format(self.account, self.balance, self.utxo_count, self.account_type, self.block_height) + + def __eq__(self, other): + if self.account != other.account: + return False + if self.balance != other.balance: + return False + if self.utxo_count != other.utxo_count: + return False + if self.account_type != other.account_type: + return False + if self.block_height != other.block_height: + return False + return True + +class _UniffiConverterTypeAccountInfoResult(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return AccountInfoResult( + account=_UniffiConverterTypeComposeAccount.read(buf), + balance=_UniffiConverterUInt64.read(buf), + utxo_count=_UniffiConverterUInt32.read(buf), + account_type=_UniffiConverterTypeAccountType.read(buf), + block_height=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypeComposeAccount.check_lower(value.account) + _UniffiConverterUInt64.check_lower(value.balance) + _UniffiConverterUInt32.check_lower(value.utxo_count) + _UniffiConverterTypeAccountType.check_lower(value.account_type) + _UniffiConverterUInt32.check_lower(value.block_height) + + @staticmethod + def write(value, buf): + _UniffiConverterTypeComposeAccount.write(value.account, buf) + _UniffiConverterUInt64.write(value.balance, buf) + _UniffiConverterUInt32.write(value.utxo_count, buf) + _UniffiConverterTypeAccountType.write(value.account_type, buf) + _UniffiConverterUInt32.write(value.block_height, buf) + + +class AccountUtxo: + """ + A UTXO in the format expected by Trezor compose. + """ + + txid: "str" + """ + Transaction ID (hex) + """ + + vout: "int" + """ + Output index + """ + + amount: "int" + """ + Amount in satoshis + """ + + block_height: "int" + """ + Block height where the UTXO was confirmed (0 if unconfirmed) + """ + + address: "str" + """ + Address holding this UTXO + """ + + path: "str" + """ + BIP32 derivation path (e.g., "m/84'/0'/0'/0/0") + """ + + confirmations: "int" + """ + Number of confirmations (0 if unconfirmed) + """ + + coinbase: "bool" + """ + Whether this is a coinbase output + """ + + own: "bool" + """ + Whether this UTXO is owned by the account + """ + + required: "typing.Optional[bool]" + """ + Whether this UTXO must be included in the transaction + """ + + def __init__(self, *, txid: "str", vout: "int", amount: "int", block_height: "int", address: "str", path: "str", confirmations: "int", coinbase: "bool", own: "bool", required: "typing.Optional[bool]"): + self.txid = txid + self.vout = vout + self.amount = amount + self.block_height = block_height + self.address = address + self.path = path + self.confirmations = confirmations + self.coinbase = coinbase + self.own = own + self.required = required + + def __str__(self): + return "AccountUtxo(txid={}, vout={}, amount={}, block_height={}, address={}, path={}, confirmations={}, coinbase={}, own={}, required={})".format(self.txid, self.vout, self.amount, self.block_height, self.address, self.path, self.confirmations, self.coinbase, self.own, self.required) + + def __eq__(self, other): + if self.txid != other.txid: + return False + if self.vout != other.vout: + return False + if self.amount != other.amount: + return False + if self.block_height != other.block_height: + return False + if self.address != other.address: + return False + if self.path != other.path: + return False + if self.confirmations != other.confirmations: + return False + if self.coinbase != other.coinbase: + return False + if self.own != other.own: + return False + if self.required != other.required: + return False + return True + +class _UniffiConverterTypeAccountUtxo(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return AccountUtxo( + txid=_UniffiConverterString.read(buf), + vout=_UniffiConverterUInt32.read(buf), + amount=_UniffiConverterUInt64.read(buf), + block_height=_UniffiConverterUInt32.read(buf), + address=_UniffiConverterString.read(buf), + path=_UniffiConverterString.read(buf), + confirmations=_UniffiConverterUInt32.read(buf), + coinbase=_UniffiConverterBool.read(buf), + own=_UniffiConverterBool.read(buf), + required=_UniffiConverterOptionalBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.txid) + _UniffiConverterUInt32.check_lower(value.vout) + _UniffiConverterUInt64.check_lower(value.amount) + _UniffiConverterUInt32.check_lower(value.block_height) + _UniffiConverterString.check_lower(value.address) + _UniffiConverterString.check_lower(value.path) + _UniffiConverterUInt32.check_lower(value.confirmations) + _UniffiConverterBool.check_lower(value.coinbase) + _UniffiConverterBool.check_lower(value.own) + _UniffiConverterOptionalBool.check_lower(value.required) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.txid, buf) + _UniffiConverterUInt32.write(value.vout, buf) + _UniffiConverterUInt64.write(value.amount, buf) + _UniffiConverterUInt32.write(value.block_height, buf) + _UniffiConverterString.write(value.address, buf) + _UniffiConverterString.write(value.path, buf) + _UniffiConverterUInt32.write(value.confirmations, buf) + _UniffiConverterBool.write(value.coinbase, buf) + _UniffiConverterBool.write(value.own, buf) + _UniffiConverterOptionalBool.write(value.required, buf) + + class ActivityTags: activity_id: "str" tags: "typing.List[str]" @@ -2519,22 +2811,22 @@ def write(value, buf): class AddressInfo: """ - Address information + Information about a single address in an account. """ address: "str" """ - Address string + The Bitcoin address """ path: "str" """ - Derivation path + BIP32 derivation path """ transfers: "int" """ - Number of transfers + Number of transactions involving this address """ def __init__(self, *, address: "str", path: "str", transfers: "int"): @@ -2803,6 +3095,68 @@ def write(value, buf): _UniffiConverterString.write(value.channel_closure_reason, buf) +class ComposeAccount: + """ + Full account structure for Trezor compose. + + This is the `account` object expected by `composeTransaction` in + precompose mode. + """ + + path: "str" + """ + Account derivation path (e.g., "m/84'/0'/0'") + """ + + addresses: "AccountAddresses" + """ + Categorized addresses + """ + + utxo: "typing.List[AccountUtxo]" + """ + Unspent transaction outputs + """ + + def __init__(self, *, path: "str", addresses: "AccountAddresses", utxo: "typing.List[AccountUtxo]"): + self.path = path + self.addresses = addresses + self.utxo = utxo + + def __str__(self): + return "ComposeAccount(path={}, addresses={}, utxo={})".format(self.path, self.addresses, self.utxo) + + def __eq__(self, other): + if self.path != other.path: + return False + if self.addresses != other.addresses: + return False + if self.utxo != other.utxo: + return False + return True + +class _UniffiConverterTypeComposeAccount(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ComposeAccount( + path=_UniffiConverterString.read(buf), + addresses=_UniffiConverterTypeAccountAddresses.read(buf), + utxo=_UniffiConverterSequenceTypeAccountUtxo.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.path) + _UniffiConverterTypeAccountAddresses.check_lower(value.addresses) + _UniffiConverterSequenceTypeAccountUtxo.check_lower(value.utxo) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.path, buf) + _UniffiConverterTypeAccountAddresses.write(value.addresses, buf) + _UniffiConverterSequenceTypeAccountUtxo.write(value.utxo, buf) + + class CreateCjitOptions: source: "typing.Optional[str]" discount_code: "typing.Optional[str]" @@ -6038,53 +6392,134 @@ def write(value, buf): _UniffiConverterString.write(value.data, buf) -class SweepResult: - txid: "str" +class SingleAddressInfoResult: """ - The transaction ID of the sweep transaction + Result from querying a single Bitcoin address. """ - amount_swept: "int" + address: "str" """ - The total amount swept (in satoshis) + The queried address """ - fee_paid: "int" + balance: "int" """ - The fee paid (in satoshis) + Total confirmed balance in satoshis """ - utxos_swept: "int" + utxos: "typing.List[AccountUtxo]" """ - The number of UTXOs swept + UTXOs for this address """ - def __init__(self, *, txid: "str", amount_swept: "int", fee_paid: "int", utxos_swept: "int"): - self.txid = txid - self.amount_swept = amount_swept - self.fee_paid = fee_paid - self.utxos_swept = utxos_swept + transfers: "int" + """ + Number of transactions involving this address + """ + + block_height: "int" + """ + Current blockchain tip height + """ + + def __init__(self, *, address: "str", balance: "int", utxos: "typing.List[AccountUtxo]", transfers: "int", block_height: "int"): + self.address = address + self.balance = balance + self.utxos = utxos + self.transfers = transfers + self.block_height = block_height def __str__(self): - return "SweepResult(txid={}, amount_swept={}, fee_paid={}, utxos_swept={})".format(self.txid, self.amount_swept, self.fee_paid, self.utxos_swept) + return "SingleAddressInfoResult(address={}, balance={}, utxos={}, transfers={}, block_height={})".format(self.address, self.balance, self.utxos, self.transfers, self.block_height) def __eq__(self, other): - if self.txid != other.txid: + if self.address != other.address: return False - if self.amount_swept != other.amount_swept: + if self.balance != other.balance: return False - if self.fee_paid != other.fee_paid: + if self.utxos != other.utxos: return False - if self.utxos_swept != other.utxos_swept: + if self.transfers != other.transfers: + return False + if self.block_height != other.block_height: return False return True -class _UniffiConverterTypeSweepResult(_UniffiConverterRustBuffer): +class _UniffiConverterTypeSingleAddressInfoResult(_UniffiConverterRustBuffer): @staticmethod def read(buf): - return SweepResult( - txid=_UniffiConverterString.read(buf), - amount_swept=_UniffiConverterUInt64.read(buf), + return SingleAddressInfoResult( + address=_UniffiConverterString.read(buf), + balance=_UniffiConverterUInt64.read(buf), + utxos=_UniffiConverterSequenceTypeAccountUtxo.read(buf), + transfers=_UniffiConverterUInt32.read(buf), + block_height=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.address) + _UniffiConverterUInt64.check_lower(value.balance) + _UniffiConverterSequenceTypeAccountUtxo.check_lower(value.utxos) + _UniffiConverterUInt32.check_lower(value.transfers) + _UniffiConverterUInt32.check_lower(value.block_height) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.address, buf) + _UniffiConverterUInt64.write(value.balance, buf) + _UniffiConverterSequenceTypeAccountUtxo.write(value.utxos, buf) + _UniffiConverterUInt32.write(value.transfers, buf) + _UniffiConverterUInt32.write(value.block_height, buf) + + +class SweepResult: + txid: "str" + """ + The transaction ID of the sweep transaction + """ + + amount_swept: "int" + """ + The total amount swept (in satoshis) + """ + + fee_paid: "int" + """ + The fee paid (in satoshis) + """ + + utxos_swept: "int" + """ + The number of UTXOs swept + """ + + def __init__(self, *, txid: "str", amount_swept: "int", fee_paid: "int", utxos_swept: "int"): + self.txid = txid + self.amount_swept = amount_swept + self.fee_paid = fee_paid + self.utxos_swept = utxos_swept + + def __str__(self): + return "SweepResult(txid={}, amount_swept={}, fee_paid={}, utxos_swept={})".format(self.txid, self.amount_swept, self.fee_paid, self.utxos_swept) + + def __eq__(self, other): + if self.txid != other.txid: + return False + if self.amount_swept != other.amount_swept: + return False + if self.fee_paid != other.fee_paid: + return False + if self.utxos_swept != other.utxos_swept: + return False + return True + +class _UniffiConverterTypeSweepResult(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return SweepResult( + txid=_UniffiConverterString.read(buf), + amount_swept=_UniffiConverterUInt64.read(buf), fee_paid=_UniffiConverterUInt64.read(buf), utxos_swept=_UniffiConverterUInt32.read(buf), ) @@ -6756,6 +7191,65 @@ def write(value, buf): _UniffiConverterOptionalBool.write(value.needs_backup, buf) +class TrezorFeeLevel: + """ + Fee level for transaction composition. + """ + + fee_per_unit: "str" + """ + Fee rate in sat/vB + """ + + base_fee: "typing.Optional[int]" + """ + Base fee in satoshis (optional, added to calculated fee) + """ + + floor_base_fee: "typing.Optional[bool]" + """ + Whether to use floor for base fee calculation + """ + + def __init__(self, *, fee_per_unit: "str", base_fee: "typing.Optional[int]", floor_base_fee: "typing.Optional[bool]"): + self.fee_per_unit = fee_per_unit + self.base_fee = base_fee + self.floor_base_fee = floor_base_fee + + def __str__(self): + return "TrezorFeeLevel(fee_per_unit={}, base_fee={}, floor_base_fee={})".format(self.fee_per_unit, self.base_fee, self.floor_base_fee) + + def __eq__(self, other): + if self.fee_per_unit != other.fee_per_unit: + return False + if self.base_fee != other.base_fee: + return False + if self.floor_base_fee != other.floor_base_fee: + return False + return True + +class _UniffiConverterTypeTrezorFeeLevel(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TrezorFeeLevel( + fee_per_unit=_UniffiConverterString.read(buf), + base_fee=_UniffiConverterOptionalUInt64.read(buf), + floor_base_fee=_UniffiConverterOptionalBool.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.fee_per_unit) + _UniffiConverterOptionalUInt64.check_lower(value.base_fee) + _UniffiConverterOptionalBool.check_lower(value.floor_base_fee) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.fee_per_unit, buf) + _UniffiConverterOptionalUInt64.write(value.base_fee, buf) + _UniffiConverterOptionalBool.write(value.floor_base_fee, buf) + + class TrezorGetAddressParams: """ Parameters for getting an address from the device. @@ -6885,6 +7379,190 @@ def write(value, buf): _UniffiConverterBool.write(value.show_on_trezor, buf) +class TrezorPrecomposeParams: + """ + Parameters for precompose transaction. + """ + + outputs: "typing.List[TrezorPrecomposeOutput]" + """ + Desired outputs + """ + + coin: "str" + """ + Coin name (e.g., "Bitcoin", "Regtest") + """ + + account: "ComposeAccount" + """ + Account with UTXOs and addresses + """ + + fee_levels: "typing.List[TrezorFeeLevel]" + """ + Fee levels to evaluate + """ + + sequence: "typing.Optional[int]" + """ + Default sequence number + """ + + sorting_strategy: "typing.Optional[TrezorSortingStrategy]" + """ + Sorting strategy for inputs/outputs + """ + + def __init__(self, *, outputs: "typing.List[TrezorPrecomposeOutput]", coin: "str", account: "ComposeAccount", fee_levels: "typing.List[TrezorFeeLevel]", sequence: "typing.Optional[int]", sorting_strategy: "typing.Optional[TrezorSortingStrategy]"): + self.outputs = outputs + self.coin = coin + self.account = account + self.fee_levels = fee_levels + self.sequence = sequence + self.sorting_strategy = sorting_strategy + + def __str__(self): + return "TrezorPrecomposeParams(outputs={}, coin={}, account={}, fee_levels={}, sequence={}, sorting_strategy={})".format(self.outputs, self.coin, self.account, self.fee_levels, self.sequence, self.sorting_strategy) + + def __eq__(self, other): + if self.outputs != other.outputs: + return False + if self.coin != other.coin: + return False + if self.account != other.account: + return False + if self.fee_levels != other.fee_levels: + return False + if self.sequence != other.sequence: + return False + if self.sorting_strategy != other.sorting_strategy: + return False + return True + +class _UniffiConverterTypeTrezorPrecomposeParams(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TrezorPrecomposeParams( + outputs=_UniffiConverterSequenceTypeTrezorPrecomposeOutput.read(buf), + coin=_UniffiConverterString.read(buf), + account=_UniffiConverterTypeComposeAccount.read(buf), + fee_levels=_UniffiConverterSequenceTypeTrezorFeeLevel.read(buf), + sequence=_UniffiConverterOptionalUInt32.read(buf), + sorting_strategy=_UniffiConverterOptionalTypeTrezorSortingStrategy.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterSequenceTypeTrezorPrecomposeOutput.check_lower(value.outputs) + _UniffiConverterString.check_lower(value.coin) + _UniffiConverterTypeComposeAccount.check_lower(value.account) + _UniffiConverterSequenceTypeTrezorFeeLevel.check_lower(value.fee_levels) + _UniffiConverterOptionalUInt32.check_lower(value.sequence) + _UniffiConverterOptionalTypeTrezorSortingStrategy.check_lower(value.sorting_strategy) + + @staticmethod + def write(value, buf): + _UniffiConverterSequenceTypeTrezorPrecomposeOutput.write(value.outputs, buf) + _UniffiConverterString.write(value.coin, buf) + _UniffiConverterTypeComposeAccount.write(value.account, buf) + _UniffiConverterSequenceTypeTrezorFeeLevel.write(value.fee_levels, buf) + _UniffiConverterOptionalUInt32.write(value.sequence, buf) + _UniffiConverterOptionalTypeTrezorSortingStrategy.write(value.sorting_strategy, buf) + + +class TrezorPrecomposedInput: + """ + Input in a precomposed result. + """ + + txid: "str" + """ + Transaction ID (hex) + """ + + vout: "int" + """ + Output index + """ + + amount: "str" + """ + Amount in satoshis (as string) + """ + + address: "str" + """ + Address + """ + + path: "str" + """ + BIP32 derivation path + """ + + script_type: "TrezorScriptType" + """ + Script type + """ + + def __init__(self, *, txid: "str", vout: "int", amount: "str", address: "str", path: "str", script_type: "TrezorScriptType"): + self.txid = txid + self.vout = vout + self.amount = amount + self.address = address + self.path = path + self.script_type = script_type + + def __str__(self): + return "TrezorPrecomposedInput(txid={}, vout={}, amount={}, address={}, path={}, script_type={})".format(self.txid, self.vout, self.amount, self.address, self.path, self.script_type) + + def __eq__(self, other): + if self.txid != other.txid: + return False + if self.vout != other.vout: + return False + if self.amount != other.amount: + return False + if self.address != other.address: + return False + if self.path != other.path: + return False + if self.script_type != other.script_type: + return False + return True + +class _UniffiConverterTypeTrezorPrecomposedInput(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return TrezorPrecomposedInput( + txid=_UniffiConverterString.read(buf), + vout=_UniffiConverterUInt32.read(buf), + amount=_UniffiConverterString.read(buf), + address=_UniffiConverterString.read(buf), + path=_UniffiConverterString.read(buf), + script_type=_UniffiConverterTypeTrezorScriptType.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterString.check_lower(value.txid) + _UniffiConverterUInt32.check_lower(value.vout) + _UniffiConverterString.check_lower(value.amount) + _UniffiConverterString.check_lower(value.address) + _UniffiConverterString.check_lower(value.path) + _UniffiConverterTypeTrezorScriptType.check_lower(value.script_type) + + @staticmethod + def write(value, buf): + _UniffiConverterString.write(value.txid, buf) + _UniffiConverterUInt32.write(value.vout, buf) + _UniffiConverterString.write(value.amount, buf) + _UniffiConverterString.write(value.address, buf) + _UniffiConverterString.write(value.path, buf) + _UniffiConverterTypeTrezorScriptType.write(value.script_type, buf) + + class TrezorPrevTx: """ Previous transaction data (for non-SegWit input verification). @@ -7401,18 +8079,26 @@ class TrezorSignedTx: Serialized transaction (hex) """ - def __init__(self, *, signatures: "typing.List[str]", serialized_tx: "str"): + txid: "typing.Optional[str]" + """ + Broadcast transaction ID (populated when push=true) + """ + + def __init__(self, *, signatures: "typing.List[str]", serialized_tx: "str", txid: "typing.Optional[str]"): self.signatures = signatures self.serialized_tx = serialized_tx + self.txid = txid def __str__(self): - return "TrezorSignedTx(signatures={}, serialized_tx={})".format(self.signatures, self.serialized_tx) + return "TrezorSignedTx(signatures={}, serialized_tx={}, txid={})".format(self.signatures, self.serialized_tx, self.txid) def __eq__(self, other): if self.signatures != other.signatures: return False if self.serialized_tx != other.serialized_tx: return False + if self.txid != other.txid: + return False return True class _UniffiConverterTypeTrezorSignedTx(_UniffiConverterRustBuffer): @@ -7421,17 +8107,20 @@ def read(buf): return TrezorSignedTx( signatures=_UniffiConverterSequenceString.read(buf), serialized_tx=_UniffiConverterString.read(buf), + txid=_UniffiConverterOptionalString.read(buf), ) @staticmethod def check_lower(value): _UniffiConverterSequenceString.check_lower(value.signatures) _UniffiConverterString.check_lower(value.serialized_tx) + _UniffiConverterOptionalString.check_lower(value.txid) @staticmethod def write(value, buf): _UniffiConverterSequenceString.write(value.signatures, buf) _UniffiConverterString.write(value.serialized_tx, buf) + _UniffiConverterOptionalString.write(value.txid, buf) class TrezorTransportReadResult: @@ -8033,25 +8722,337 @@ def write(value, buf): _UniffiConverterTypeAddressType.write(value.address_type, buf) +# AccountInfoError +# We want to define each variant as a nested class that's also a subclass, +# which is tricky in Python. To accomplish this we're going to create each +# class separately, then manually add the child classes to the base class's +# __dict__. All of this happens in dummy class to avoid polluting the module +# namespace. +class AccountInfoError(Exception): + """ + Errors specific to account info operations (BDK/Electrum-based). + These are separate from `TrezorError` because account info operations + do not interact with a Trezor device — they only query the blockchain. + """ + pass -class Activity: - def __init__(self): - raise RuntimeError("Activity cannot be instantiated directly") +_UniffiTempAccountInfoError = AccountInfoError - # Each enum variant is a nested class of the enum itself. - class ONCHAIN: - def __init__(self, *values): - if len(values) != 1: - raise TypeError(f"Expected 1 arguments, found {len(values)}") - self._values = values +class AccountInfoError: # type: ignore + """ + Errors specific to account info operations (BDK/Electrum-based). - def __getitem__(self, index): - return self._values[index] + These are separate from `TrezorError` because account info operations + do not interact with a Trezor device — they only query the blockchain. + """ - def __str__(self): - return f"Activity.ONCHAIN{self._values!r}" + class InvalidExtendedKey(_UniffiTempAccountInfoError): + """ + The provided extended public key is invalid or cannot be parsed + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.InvalidExtendedKey({})".format(str(self)) + _UniffiTempAccountInfoError.InvalidExtendedKey = InvalidExtendedKey # type: ignore + class InvalidAddress(_UniffiTempAccountInfoError): + """ + The provided address is invalid + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.InvalidAddress({})".format(str(self)) + _UniffiTempAccountInfoError.InvalidAddress = InvalidAddress # type: ignore + class ElectrumError(_UniffiTempAccountInfoError): + """ + Electrum connection or query failed + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.ElectrumError({})".format(str(self)) + _UniffiTempAccountInfoError.ElectrumError = ElectrumError # type: ignore + class WalletError(_UniffiTempAccountInfoError): + """ + BDK wallet creation or operation error + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.WalletError({})".format(str(self)) + _UniffiTempAccountInfoError.WalletError = WalletError # type: ignore + class SyncError(_UniffiTempAccountInfoError): + """ + Wallet sync with Electrum failed + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.SyncError({})".format(str(self)) + _UniffiTempAccountInfoError.SyncError = SyncError # type: ignore + class UnsupportedKeyType(_UniffiTempAccountInfoError): + """ + The key type/prefix is not recognized + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.UnsupportedKeyType({})".format(str(self)) + _UniffiTempAccountInfoError.UnsupportedKeyType = UnsupportedKeyType # type: ignore + class NetworkMismatch(_UniffiTempAccountInfoError): + """ + Network mismatch between key prefix and specified network + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.NetworkMismatch({})".format(str(self)) + _UniffiTempAccountInfoError.NetworkMismatch = NetworkMismatch # type: ignore + class InvalidTxid(_UniffiTempAccountInfoError): + """ + Invalid transaction ID provided + """ + + def __init__(self, error_details): + super().__init__(", ".join([ + "error_details={!r}".format(error_details), + ])) + self.error_details = error_details + + def __repr__(self): + return "AccountInfoError.InvalidTxid({})".format(str(self)) + _UniffiTempAccountInfoError.InvalidTxid = InvalidTxid # type: ignore + +AccountInfoError = _UniffiTempAccountInfoError # type: ignore +del _UniffiTempAccountInfoError + + +class _UniffiConverterTypeAccountInfoError(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return AccountInfoError.InvalidExtendedKey( + _UniffiConverterString.read(buf), + ) + if variant == 2: + return AccountInfoError.InvalidAddress( + _UniffiConverterString.read(buf), + ) + if variant == 3: + return AccountInfoError.ElectrumError( + _UniffiConverterString.read(buf), + ) + if variant == 4: + return AccountInfoError.WalletError( + _UniffiConverterString.read(buf), + ) + if variant == 5: + return AccountInfoError.SyncError( + _UniffiConverterString.read(buf), + ) + if variant == 6: + return AccountInfoError.UnsupportedKeyType( + _UniffiConverterString.read(buf), + ) + if variant == 7: + return AccountInfoError.NetworkMismatch( + _UniffiConverterString.read(buf), + ) + if variant == 8: + return AccountInfoError.InvalidTxid( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if isinstance(value, AccountInfoError.InvalidExtendedKey): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.InvalidAddress): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.ElectrumError): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.WalletError): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.SyncError): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.UnsupportedKeyType): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.NetworkMismatch): + _UniffiConverterString.check_lower(value.error_details) + return + if isinstance(value, AccountInfoError.InvalidTxid): + _UniffiConverterString.check_lower(value.error_details) + return + + @staticmethod + def write(value, buf): + if isinstance(value, AccountInfoError.InvalidExtendedKey): + buf.write_i32(1) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.InvalidAddress): + buf.write_i32(2) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.ElectrumError): + buf.write_i32(3) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.WalletError): + buf.write_i32(4) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.SyncError): + buf.write_i32(5) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.UnsupportedKeyType): + buf.write_i32(6) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.NetworkMismatch): + buf.write_i32(7) + _UniffiConverterString.write(value.error_details, buf) + if isinstance(value, AccountInfoError.InvalidTxid): + buf.write_i32(8) + _UniffiConverterString.write(value.error_details, buf) + + + + + +class AccountType(enum.Enum): + """ + Account type classification for extended public keys. + + Determines the BIP standard, derivation path purpose, and script type. + """ + + LEGACY = 0 + """ + BIP44 legacy (P2PKH) — xpub/tpub prefix + """ + + + WRAPPED_SEGWIT = 1 + """ + BIP49 wrapped segwit (P2SH-P2WPKH) — ypub/upub prefix + """ + + + NATIVE_SEGWIT = 2 + """ + BIP84 native segwit (P2WPKH) — zpub/vpub prefix + """ + + + TAPROOT = 3 + """ + BIP86 taproot (P2TR) + """ + + + + +class _UniffiConverterTypeAccountType(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return AccountType.LEGACY + if variant == 2: + return AccountType.WRAPPED_SEGWIT + if variant == 3: + return AccountType.NATIVE_SEGWIT + if variant == 4: + return AccountType.TAPROOT + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == AccountType.LEGACY: + return + if value == AccountType.WRAPPED_SEGWIT: + return + if value == AccountType.NATIVE_SEGWIT: + return + if value == AccountType.TAPROOT: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == AccountType.LEGACY: + buf.write_i32(1) + if value == AccountType.WRAPPED_SEGWIT: + buf.write_i32(2) + if value == AccountType.NATIVE_SEGWIT: + buf.write_i32(3) + if value == AccountType.TAPROOT: + buf.write_i32(4) + + + + + + + +class Activity: + def __init__(self): + raise RuntimeError("Activity cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class ONCHAIN: + def __init__(self, *values): + if len(values) != 1: + raise TypeError(f"Expected 1 arguments, found {len(values)}") + self._values = values + + def __getitem__(self, index): + return self._values[index] + + def __str__(self): + return f"Activity.ONCHAIN{self._values!r}" def __eq__(self, other): if not other.is_ONCHAIN(): @@ -11192,44 +12193,651 @@ def write(value, buf): -class TrezorScriptType(enum.Enum): +class TrezorPrecomposeOutput: """ - Script types for address derivation. + Output specification for precompose. """ - SPEND_ADDRESS = 0 - """ - P2PKH (legacy) - """ + def __init__(self): + raise RuntimeError("TrezorPrecomposeOutput cannot be instantiated directly") - - SPEND_P2SH_WITNESS = 1 - """ - P2SH-P2WPKH (nested SegWit) - """ + # Each enum variant is a nested class of the enum itself. + class PAYMENT: + """ + Payment to a specific address + """ - - SPEND_WITNESS = 2 - """ - P2WPKH (native SegWit) - """ + address: "str" + amount: "str" - - SPEND_TAPROOT = 3 - """ - P2TR (Taproot) - """ + def __init__(self,address: "str", amount: "str"): + self.address = address + self.amount = amount - - SPEND_MULTISIG = 4 - """ - P2SH multisig - """ + def __str__(self): + return "TrezorPrecomposeOutput.PAYMENT(address={}, amount={})".format(self.address, self.amount) - - EXTERNAL = 5 - """ - External/watch-only input (not signed by device) + def __eq__(self, other): + if not other.is_PAYMENT(): + return False + if self.address != other.address: + return False + if self.amount != other.amount: + return False + return True + + class PAYMENT_NO_ADDRESS: + """ + Payment without address (estimation only) + """ + + amount: "str" + + def __init__(self,amount: "str"): + self.amount = amount + + def __str__(self): + return "TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS(amount={})".format(self.amount) + + def __eq__(self, other): + if not other.is_PAYMENT_NO_ADDRESS(): + return False + if self.amount != other.amount: + return False + return True + + class SEND_MAX: + """ + Send all remaining funds to an address + """ + + address: "str" + + def __init__(self,address: "str"): + self.address = address + + def __str__(self): + return "TrezorPrecomposeOutput.SEND_MAX(address={})".format(self.address) + + def __eq__(self, other): + if not other.is_SEND_MAX(): + return False + if self.address != other.address: + return False + return True + + class SEND_MAX_NO_ADDRESS: + """ + Send all remaining funds (no address) + """ + + + def __init__(self,): + pass + + def __str__(self): + return "TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS()".format() + + def __eq__(self, other): + if not other.is_SEND_MAX_NO_ADDRESS(): + return False + return True + + class OP_RETURN: + """ + OP_RETURN data output + """ + + data_hex: "str" + + def __init__(self,data_hex: "str"): + self.data_hex = data_hex + + def __str__(self): + return "TrezorPrecomposeOutput.OP_RETURN(data_hex={})".format(self.data_hex) + + def __eq__(self, other): + if not other.is_OP_RETURN(): + return False + if self.data_hex != other.data_hex: + return False + return True + + + + # For each variant, we have `is_NAME` and `is_name` methods for easily checking + # whether an instance is that variant. + def is_PAYMENT(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.PAYMENT) + def is_payment(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.PAYMENT) + def is_PAYMENT_NO_ADDRESS(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS) + def is_payment_no_address(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS) + def is_SEND_MAX(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.SEND_MAX) + def is_send_max(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.SEND_MAX) + def is_SEND_MAX_NO_ADDRESS(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS) + def is_send_max_no_address(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS) + def is_OP_RETURN(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.OP_RETURN) + def is_op_return(self) -> bool: + return isinstance(self, TrezorPrecomposeOutput.OP_RETURN) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +TrezorPrecomposeOutput.PAYMENT = type("TrezorPrecomposeOutput.PAYMENT", (TrezorPrecomposeOutput.PAYMENT, TrezorPrecomposeOutput,), {}) # type: ignore +TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS = type("TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS", (TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS, TrezorPrecomposeOutput,), {}) # type: ignore +TrezorPrecomposeOutput.SEND_MAX = type("TrezorPrecomposeOutput.SEND_MAX", (TrezorPrecomposeOutput.SEND_MAX, TrezorPrecomposeOutput,), {}) # type: ignore +TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS = type("TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS", (TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS, TrezorPrecomposeOutput,), {}) # type: ignore +TrezorPrecomposeOutput.OP_RETURN = type("TrezorPrecomposeOutput.OP_RETURN", (TrezorPrecomposeOutput.OP_RETURN, TrezorPrecomposeOutput,), {}) # type: ignore + + + + +class _UniffiConverterTypeTrezorPrecomposeOutput(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return TrezorPrecomposeOutput.PAYMENT( + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + ) + if variant == 2: + return TrezorPrecomposeOutput.PAYMENT_NO_ADDRESS( + _UniffiConverterString.read(buf), + ) + if variant == 3: + return TrezorPrecomposeOutput.SEND_MAX( + _UniffiConverterString.read(buf), + ) + if variant == 4: + return TrezorPrecomposeOutput.SEND_MAX_NO_ADDRESS( + ) + if variant == 5: + return TrezorPrecomposeOutput.OP_RETURN( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_PAYMENT(): + _UniffiConverterString.check_lower(value.address) + _UniffiConverterString.check_lower(value.amount) + return + if value.is_PAYMENT_NO_ADDRESS(): + _UniffiConverterString.check_lower(value.amount) + return + if value.is_SEND_MAX(): + _UniffiConverterString.check_lower(value.address) + return + if value.is_SEND_MAX_NO_ADDRESS(): + return + if value.is_OP_RETURN(): + _UniffiConverterString.check_lower(value.data_hex) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_PAYMENT(): + buf.write_i32(1) + _UniffiConverterString.write(value.address, buf) + _UniffiConverterString.write(value.amount, buf) + if value.is_PAYMENT_NO_ADDRESS(): + buf.write_i32(2) + _UniffiConverterString.write(value.amount, buf) + if value.is_SEND_MAX(): + buf.write_i32(3) + _UniffiConverterString.write(value.address, buf) + if value.is_SEND_MAX_NO_ADDRESS(): + buf.write_i32(4) + if value.is_OP_RETURN(): + buf.write_i32(5) + _UniffiConverterString.write(value.data_hex, buf) + + + + + + + +class TrezorPrecomposedOutput: + """ + Output in a precomposed result. + """ + + def __init__(self): + raise RuntimeError("TrezorPrecomposedOutput cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class PAYMENT: + """ + Payment to an address + """ + + address: "str" + amount: "str" + + def __init__(self,address: "str", amount: "str"): + self.address = address + self.amount = amount + + def __str__(self): + return "TrezorPrecomposedOutput.PAYMENT(address={}, amount={})".format(self.address, self.amount) + + def __eq__(self, other): + if not other.is_PAYMENT(): + return False + if self.address != other.address: + return False + if self.amount != other.amount: + return False + return True + + class CHANGE: + """ + Change output + """ + + address: "str" + path: "str" + amount: "str" + script_type: "TrezorScriptType" + + def __init__(self,address: "str", path: "str", amount: "str", script_type: "TrezorScriptType"): + self.address = address + self.path = path + self.amount = amount + self.script_type = script_type + + def __str__(self): + return "TrezorPrecomposedOutput.CHANGE(address={}, path={}, amount={}, script_type={})".format(self.address, self.path, self.amount, self.script_type) + + def __eq__(self, other): + if not other.is_CHANGE(): + return False + if self.address != other.address: + return False + if self.path != other.path: + return False + if self.amount != other.amount: + return False + if self.script_type != other.script_type: + return False + return True + + class OP_RETURN: + """ + OP_RETURN data output + """ + + data_hex: "str" + + def __init__(self,data_hex: "str"): + self.data_hex = data_hex + + def __str__(self): + return "TrezorPrecomposedOutput.OP_RETURN(data_hex={})".format(self.data_hex) + + def __eq__(self, other): + if not other.is_OP_RETURN(): + return False + if self.data_hex != other.data_hex: + return False + return True + + + + # For each variant, we have `is_NAME` and `is_name` methods for easily checking + # whether an instance is that variant. + def is_PAYMENT(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.PAYMENT) + def is_payment(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.PAYMENT) + def is_CHANGE(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.CHANGE) + def is_change(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.CHANGE) + def is_OP_RETURN(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.OP_RETURN) + def is_op_return(self) -> bool: + return isinstance(self, TrezorPrecomposedOutput.OP_RETURN) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +TrezorPrecomposedOutput.PAYMENT = type("TrezorPrecomposedOutput.PAYMENT", (TrezorPrecomposedOutput.PAYMENT, TrezorPrecomposedOutput,), {}) # type: ignore +TrezorPrecomposedOutput.CHANGE = type("TrezorPrecomposedOutput.CHANGE", (TrezorPrecomposedOutput.CHANGE, TrezorPrecomposedOutput,), {}) # type: ignore +TrezorPrecomposedOutput.OP_RETURN = type("TrezorPrecomposedOutput.OP_RETURN", (TrezorPrecomposedOutput.OP_RETURN, TrezorPrecomposedOutput,), {}) # type: ignore + + + + +class _UniffiConverterTypeTrezorPrecomposedOutput(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return TrezorPrecomposedOutput.PAYMENT( + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + ) + if variant == 2: + return TrezorPrecomposedOutput.CHANGE( + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterTypeTrezorScriptType.read(buf), + ) + if variant == 3: + return TrezorPrecomposedOutput.OP_RETURN( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_PAYMENT(): + _UniffiConverterString.check_lower(value.address) + _UniffiConverterString.check_lower(value.amount) + return + if value.is_CHANGE(): + _UniffiConverterString.check_lower(value.address) + _UniffiConverterString.check_lower(value.path) + _UniffiConverterString.check_lower(value.amount) + _UniffiConverterTypeTrezorScriptType.check_lower(value.script_type) + return + if value.is_OP_RETURN(): + _UniffiConverterString.check_lower(value.data_hex) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_PAYMENT(): + buf.write_i32(1) + _UniffiConverterString.write(value.address, buf) + _UniffiConverterString.write(value.amount, buf) + if value.is_CHANGE(): + buf.write_i32(2) + _UniffiConverterString.write(value.address, buf) + _UniffiConverterString.write(value.path, buf) + _UniffiConverterString.write(value.amount, buf) + _UniffiConverterTypeTrezorScriptType.write(value.script_type, buf) + if value.is_OP_RETURN(): + buf.write_i32(3) + _UniffiConverterString.write(value.data_hex, buf) + + + + + + + +class TrezorPrecomposedResult: + """ + Precomposed transaction result (one per fee level). + """ + + def __init__(self): + raise RuntimeError("TrezorPrecomposedResult cannot be instantiated directly") + + # Each enum variant is a nested class of the enum itself. + class FINAL: + """ + Successfully composed a sendable transaction + """ + + total_spent: "str" + fee: "str" + fee_per_byte: "str" + bytes: "int" + inputs: "typing.List[TrezorPrecomposedInput]" + outputs: "typing.List[TrezorPrecomposedOutput]" + outputs_permutation: "typing.List[int]" + + def __init__(self,total_spent: "str", fee: "str", fee_per_byte: "str", bytes: "int", inputs: "typing.List[TrezorPrecomposedInput]", outputs: "typing.List[TrezorPrecomposedOutput]", outputs_permutation: "typing.List[int]"): + self.total_spent = total_spent + self.fee = fee + self.fee_per_byte = fee_per_byte + self.bytes = bytes + self.inputs = inputs + self.outputs = outputs + self.outputs_permutation = outputs_permutation + + def __str__(self): + return "TrezorPrecomposedResult.FINAL(total_spent={}, fee={}, fee_per_byte={}, bytes={}, inputs={}, outputs={}, outputs_permutation={})".format(self.total_spent, self.fee, self.fee_per_byte, self.bytes, self.inputs, self.outputs, self.outputs_permutation) + + def __eq__(self, other): + if not other.is_FINAL(): + return False + if self.total_spent != other.total_spent: + return False + if self.fee != other.fee: + return False + if self.fee_per_byte != other.fee_per_byte: + return False + if self.bytes != other.bytes: + return False + if self.inputs != other.inputs: + return False + if self.outputs != other.outputs: + return False + if self.outputs_permutation != other.outputs_permutation: + return False + return True + + class NON_FINAL: + """ + Non-final result (e.g., send-max estimation) + """ + + max: "typing.Optional[str]" + total_spent: "str" + fee: "str" + fee_per_byte: "str" + bytes: "int" + + def __init__(self,max: "typing.Optional[str]", total_spent: "str", fee: "str", fee_per_byte: "str", bytes: "int"): + self.max = max + self.total_spent = total_spent + self.fee = fee + self.fee_per_byte = fee_per_byte + self.bytes = bytes + + def __str__(self): + return "TrezorPrecomposedResult.NON_FINAL(max={}, total_spent={}, fee={}, fee_per_byte={}, bytes={})".format(self.max, self.total_spent, self.fee, self.fee_per_byte, self.bytes) + + def __eq__(self, other): + if not other.is_NON_FINAL(): + return False + if self.max != other.max: + return False + if self.total_spent != other.total_spent: + return False + if self.fee != other.fee: + return False + if self.fee_per_byte != other.fee_per_byte: + return False + if self.bytes != other.bytes: + return False + return True + + class ERROR: + """ + Composition failed + """ + + error: "str" + + def __init__(self,error: "str"): + self.error = error + + def __str__(self): + return "TrezorPrecomposedResult.ERROR(error={})".format(self.error) + + def __eq__(self, other): + if not other.is_ERROR(): + return False + if self.error != other.error: + return False + return True + + + + # For each variant, we have `is_NAME` and `is_name` methods for easily checking + # whether an instance is that variant. + def is_FINAL(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.FINAL) + def is_final(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.FINAL) + def is_NON_FINAL(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.NON_FINAL) + def is_non_final(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.NON_FINAL) + def is_ERROR(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.ERROR) + def is_error(self) -> bool: + return isinstance(self, TrezorPrecomposedResult.ERROR) + + +# Now, a little trick - we make each nested variant class be a subclass of the main +# enum class, so that method calls and instance checks etc will work intuitively. +# We might be able to do this a little more neatly with a metaclass, but this'll do. +TrezorPrecomposedResult.FINAL = type("TrezorPrecomposedResult.FINAL", (TrezorPrecomposedResult.FINAL, TrezorPrecomposedResult,), {}) # type: ignore +TrezorPrecomposedResult.NON_FINAL = type("TrezorPrecomposedResult.NON_FINAL", (TrezorPrecomposedResult.NON_FINAL, TrezorPrecomposedResult,), {}) # type: ignore +TrezorPrecomposedResult.ERROR = type("TrezorPrecomposedResult.ERROR", (TrezorPrecomposedResult.ERROR, TrezorPrecomposedResult,), {}) # type: ignore + + + + +class _UniffiConverterTypeTrezorPrecomposedResult(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return TrezorPrecomposedResult.FINAL( + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterUInt32.read(buf), + _UniffiConverterSequenceTypeTrezorPrecomposedInput.read(buf), + _UniffiConverterSequenceTypeTrezorPrecomposedOutput.read(buf), + _UniffiConverterSequenceUInt32.read(buf), + ) + if variant == 2: + return TrezorPrecomposedResult.NON_FINAL( + _UniffiConverterOptionalString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterString.read(buf), + _UniffiConverterUInt32.read(buf), + ) + if variant == 3: + return TrezorPrecomposedResult.ERROR( + _UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value.is_FINAL(): + _UniffiConverterString.check_lower(value.total_spent) + _UniffiConverterString.check_lower(value.fee) + _UniffiConverterString.check_lower(value.fee_per_byte) + _UniffiConverterUInt32.check_lower(value.bytes) + _UniffiConverterSequenceTypeTrezorPrecomposedInput.check_lower(value.inputs) + _UniffiConverterSequenceTypeTrezorPrecomposedOutput.check_lower(value.outputs) + _UniffiConverterSequenceUInt32.check_lower(value.outputs_permutation) + return + if value.is_NON_FINAL(): + _UniffiConverterOptionalString.check_lower(value.max) + _UniffiConverterString.check_lower(value.total_spent) + _UniffiConverterString.check_lower(value.fee) + _UniffiConverterString.check_lower(value.fee_per_byte) + _UniffiConverterUInt32.check_lower(value.bytes) + return + if value.is_ERROR(): + _UniffiConverterString.check_lower(value.error) + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value.is_FINAL(): + buf.write_i32(1) + _UniffiConverterString.write(value.total_spent, buf) + _UniffiConverterString.write(value.fee, buf) + _UniffiConverterString.write(value.fee_per_byte, buf) + _UniffiConverterUInt32.write(value.bytes, buf) + _UniffiConverterSequenceTypeTrezorPrecomposedInput.write(value.inputs, buf) + _UniffiConverterSequenceTypeTrezorPrecomposedOutput.write(value.outputs, buf) + _UniffiConverterSequenceUInt32.write(value.outputs_permutation, buf) + if value.is_NON_FINAL(): + buf.write_i32(2) + _UniffiConverterOptionalString.write(value.max, buf) + _UniffiConverterString.write(value.total_spent, buf) + _UniffiConverterString.write(value.fee, buf) + _UniffiConverterString.write(value.fee_per_byte, buf) + _UniffiConverterUInt32.write(value.bytes, buf) + if value.is_ERROR(): + buf.write_i32(3) + _UniffiConverterString.write(value.error, buf) + + + + + + + +class TrezorScriptType(enum.Enum): + """ + Script types for address derivation. + """ + + SPEND_ADDRESS = 0 + """ + P2PKH (legacy) + """ + + + SPEND_P2SH_WITNESS = 1 + """ + P2SH-P2WPKH (nested SegWit) + """ + + + SPEND_WITNESS = 2 + """ + P2WPKH (native SegWit) + """ + + + SPEND_TAPROOT = 3 + """ + P2TR (Taproot) + """ + + + SPEND_MULTISIG = 4 + """ + P2SH multisig + """ + + + EXTERNAL = 5 + """ + External/watch-only input (not signed by device) """ @@ -11290,6 +12898,68 @@ def write(value, buf): +class TrezorSortingStrategy(enum.Enum): + """ + Sorting strategy for transaction inputs and outputs. + """ + + BIP69 = 0 + """ + BIP-69: deterministic lexicographic sorting + """ + + + RANDOM = 1 + """ + Random shuffle (better privacy) + """ + + + NONE = 2 + """ + Keep original order + """ + + + + +class _UniffiConverterTypeTrezorSortingStrategy(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return TrezorSortingStrategy.BIP69 + if variant == 2: + return TrezorSortingStrategy.RANDOM + if variant == 3: + return TrezorSortingStrategy.NONE + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if value == TrezorSortingStrategy.BIP69: + return + if value == TrezorSortingStrategy.RANDOM: + return + if value == TrezorSortingStrategy.NONE: + return + raise ValueError(value) + + @staticmethod + def write(value, buf): + if value == TrezorSortingStrategy.BIP69: + buf.write_i32(1) + if value == TrezorSortingStrategy.RANDOM: + buf.write_i32(2) + if value == TrezorSortingStrategy.NONE: + buf.write_i32(3) + + + + + + + class TrezorTransportType(enum.Enum): """ Transport type for Trezor devices. @@ -12440,17 +14110,44 @@ def read(cls, buf): if flag == 0: return None elif flag == 1: - return _UniffiConverterTypeTrezorCoinType.read(buf) + return _UniffiConverterTypeTrezorCoinType.read(buf) + else: + raise InternalError("Unexpected flag byte for optional type") + + + +class _UniffiConverterOptionalTypeTrezorScriptType(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + if value is not None: + _UniffiConverterTypeTrezorScriptType.check_lower(value) + + @classmethod + def write(cls, value, buf): + if value is None: + buf.write_u8(0) + return + + buf.write_u8(1) + _UniffiConverterTypeTrezorScriptType.write(value, buf) + + @classmethod + def read(cls, buf): + flag = buf.read_u8() + if flag == 0: + return None + elif flag == 1: + return _UniffiConverterTypeTrezorScriptType.read(buf) else: raise InternalError("Unexpected flag byte for optional type") -class _UniffiConverterOptionalTypeTrezorScriptType(_UniffiConverterRustBuffer): +class _UniffiConverterOptionalTypeTrezorSortingStrategy(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, value): if value is not None: - _UniffiConverterTypeTrezorScriptType.check_lower(value) + _UniffiConverterTypeTrezorSortingStrategy.check_lower(value) @classmethod def write(cls, value, buf): @@ -12459,7 +14156,7 @@ def write(cls, value, buf): return buf.write_u8(1) - _UniffiConverterTypeTrezorScriptType.write(value, buf) + _UniffiConverterTypeTrezorSortingStrategy.write(value, buf) @classmethod def read(cls, buf): @@ -12467,7 +14164,7 @@ def read(cls, buf): if flag == 0: return None elif flag == 1: - return _UniffiConverterTypeTrezorScriptType.read(buf) + return _UniffiConverterTypeTrezorSortingStrategy.read(buf) else: raise InternalError("Unexpected flag byte for optional type") @@ -12581,6 +14278,31 @@ def read(cls, buf): +class _UniffiConverterSequenceUInt32(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterUInt32.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterUInt32.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterUInt32.read(buf) for i in range(count) + ] + + + class _UniffiConverterSequenceString(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, value): @@ -12606,6 +14328,31 @@ def read(cls, buf): +class _UniffiConverterSequenceTypeAccountUtxo(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeAccountUtxo.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeAccountUtxo.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeAccountUtxo.read(buf) for i in range(count) + ] + + + class _UniffiConverterSequenceTypeActivityTags(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, value): @@ -12981,6 +14728,56 @@ def read(cls, buf): +class _UniffiConverterSequenceTypeTrezorFeeLevel(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTrezorFeeLevel.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTrezorFeeLevel.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTrezorFeeLevel.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTrezorPrecomposedInput(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTrezorPrecomposedInput.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTrezorPrecomposedInput.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTrezorPrecomposedInput.read(buf) for i in range(count) + ] + + + class _UniffiConverterSequenceTypeTrezorPrevTx(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, value): @@ -13181,6 +14978,81 @@ def read(cls, buf): +class _UniffiConverterSequenceTypeTrezorPrecomposeOutput(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTrezorPrecomposeOutput.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTrezorPrecomposeOutput.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTrezorPrecomposeOutput.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTrezorPrecomposedOutput(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTrezorPrecomposedOutput.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTrezorPrecomposedOutput.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTrezorPrecomposedOutput.read(buf) for i in range(count) + ] + + + +class _UniffiConverterSequenceTypeTrezorPrecomposedResult(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeTrezorPrecomposedResult.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeTrezorPrecomposedResult.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeTrezorPrecomposedResult.read(buf) for i in range(count) + ] + + + class _UniffiConverterMapStringString(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, items): @@ -15490,6 +17362,44 @@ async def test_notification(device_token: "str",secret_message: "str",notificati _UniffiConverterTypeBlocktankError, ) + +def trezor_account_type_to_script_type(account_type: "AccountType") -> "TrezorScriptType": + """ + Convert an account type to its corresponding script type. + """ + + _UniffiConverterTypeAccountType.check_lower(account_type) + + return _UniffiConverterTypeTrezorScriptType.lift(_uniffi_rust_call(_UniffiLib.uniffi_bitkitcore_fn_func_trezor_account_type_to_script_type, + _UniffiConverterTypeAccountType.lower(account_type))) + +async def trezor_broadcast_raw_tx(serialized_tx: "str",electrum_url: "str") -> "str": + + """ + Broadcast a signed raw transaction via Electrum. + + Takes a hex-encoded serialized transaction and an Electrum server URL. + Returns the transaction ID on success. + """ + + _UniffiConverterString.check_lower(serialized_tx) + + _UniffiConverterString.check_lower(electrum_url) + + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_bitkitcore_fn_func_trezor_broadcast_raw_tx( + _UniffiConverterString.lower(serialized_tx), + _UniffiConverterString.lower(electrum_url)), + _UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer, + # lift function + _UniffiConverterString.lift, + + # Error FFI converter +_UniffiConverterTypeAccountInfoError, + + ) async def trezor_clear_credentials(device_id: "str") -> None: """ @@ -15557,6 +17467,66 @@ async def trezor_disconnect() -> None: # Error FFI converter _UniffiConverterTypeTrezorError, + ) +async def trezor_fetch_prev_txs(txids: "typing.List[str]",electrum_url: "str") -> "typing.List[TrezorPrevTx]": + + """ + Fetch previous transactions from Electrum for Trezor signing. + + Takes transaction IDs (from TrezorSignTxParams inputs' prev_hash fields), + fetches the full transactions from Electrum, and returns them as + TrezorPrevTx structures ready to merge into TrezorSignTxParams.prev_txs. + + Duplicate txids are automatically deduplicated. + """ + + _UniffiConverterSequenceString.check_lower(txids) + + _UniffiConverterString.check_lower(electrum_url) + + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_bitkitcore_fn_func_trezor_fetch_prev_txs( + _UniffiConverterSequenceString.lower(txids), + _UniffiConverterString.lower(electrum_url)), + _UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer, + # lift function + _UniffiConverterSequenceTypeTrezorPrevTx.lift, + + # Error FFI converter +_UniffiConverterTypeAccountInfoError, + + ) +async def trezor_get_account_info(extended_key: "str",electrum_url: "str",network: "typing.Optional[TrezorCoinType]",gap_limit: "typing.Optional[int]") -> "AccountInfoResult": + + """ + Query account information for an extended public key via Electrum. + """ + + _UniffiConverterString.check_lower(extended_key) + + _UniffiConverterString.check_lower(electrum_url) + + _UniffiConverterOptionalTypeTrezorCoinType.check_lower(network) + + _UniffiConverterOptionalUInt32.check_lower(gap_limit) + + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_account_info( + _UniffiConverterString.lower(extended_key), + _UniffiConverterString.lower(electrum_url), + _UniffiConverterOptionalTypeTrezorCoinType.lower(network), + _UniffiConverterOptionalUInt32.lower(gap_limit)), + _UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer, + # lift function + _UniffiConverterTypeAccountInfoResult.lift, + + # Error FFI converter +_UniffiConverterTypeAccountInfoError, + ) async def trezor_get_address(params: "TrezorGetAddressParams") -> "TrezorAddressResponse": @@ -15578,6 +17548,33 @@ async def trezor_get_address(params: "TrezorGetAddressParams") -> "TrezorAddress # Error FFI converter _UniffiConverterTypeTrezorError, + ) +async def trezor_get_address_info(address: "str",electrum_url: "str",network: "typing.Optional[TrezorCoinType]") -> "SingleAddressInfoResult": + + """ + Query balance and UTXOs for a single Bitcoin address via Electrum. + """ + + _UniffiConverterString.check_lower(address) + + _UniffiConverterString.check_lower(electrum_url) + + _UniffiConverterOptionalTypeTrezorCoinType.check_lower(network) + + return await _uniffi_rust_call_async( + _UniffiLib.uniffi_bitkitcore_fn_func_trezor_get_address_info( + _UniffiConverterString.lower(address), + _UniffiConverterString.lower(electrum_url), + _UniffiConverterOptionalTypeTrezorCoinType.lower(network)), + _UniffiLib.ffi_bitkitcore_rust_future_poll_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_complete_rust_buffer, + _UniffiLib.ffi_bitkitcore_rust_future_free_rust_buffer, + # lift function + _UniffiConverterTypeSingleAddressInfoResult.lift, + + # Error FFI converter +_UniffiConverterTypeAccountInfoError, + ) async def trezor_get_connected_device() -> "typing.Optional[TrezorDeviceInfo]": @@ -15756,6 +17753,38 @@ async def trezor_list_devices() -> "typing.List[TrezorDeviceInfo]": _UniffiConverterTypeTrezorError, ) + +def trezor_precompose_transaction(params: "TrezorPrecomposeParams") -> "typing.List[TrezorPrecomposedResult]": + """ + Compose a transaction offline for multiple fee levels. + + No device interaction needed — pure coin selection and fee calculation. + """ + + _UniffiConverterTypeTrezorPrecomposeParams.check_lower(params) + + return _UniffiConverterSequenceTypeTrezorPrecomposedResult.lift(_uniffi_rust_call(_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precompose_transaction, + _UniffiConverterTypeTrezorPrecomposeParams.lower(params))) + + +def trezor_precomposed_to_sign_params(inputs: "typing.List[TrezorPrecomposedInput]",outputs: "typing.List[TrezorPrecomposedOutput]",coin: "typing.Optional[TrezorCoinType]") -> "TrezorSignTxParams": + """ + Convert precomposed results into signing parameters for trezor_sign_tx. + + The returned params have empty prev_txs — add them before signing. + """ + + _UniffiConverterSequenceTypeTrezorPrecomposedInput.check_lower(inputs) + + _UniffiConverterSequenceTypeTrezorPrecomposedOutput.check_lower(outputs) + + _UniffiConverterOptionalTypeTrezorCoinType.check_lower(coin) + + return _UniffiConverterTypeTrezorSignTxParams.lift(_uniffi_rust_call(_UniffiLib.uniffi_bitkitcore_fn_func_trezor_precomposed_to_sign_params, + _UniffiConverterSequenceTypeTrezorPrecomposedInput.lower(inputs), + _UniffiConverterSequenceTypeTrezorPrecomposedOutput.lower(outputs), + _UniffiConverterOptionalTypeTrezorCoinType.lower(coin))) + async def trezor_scan() -> "typing.List[TrezorDeviceInfo]": """ @@ -16084,6 +18113,8 @@ def wipe_all_transaction_details() -> None: __all__ = [ "InternalError", + "AccountInfoError", + "AccountType", "Activity", "ActivityError", "ActivityFilter", @@ -16114,15 +18145,22 @@ def wipe_all_transaction_details() -> None: "SweepError", "TrezorCoinType", "TrezorError", + "TrezorPrecomposeOutput", + "TrezorPrecomposedOutput", + "TrezorPrecomposedResult", "TrezorScriptType", + "TrezorSortingStrategy", "TrezorTransportType", "WordCount", "AccountAddresses", + "AccountInfoResult", + "AccountUtxo", "ActivityTags", "AddressInfo", "ChannelLiquidityOptions", "ChannelLiquidityParams", "ClosedChannelDetails", + "ComposeAccount", "CreateCjitOptions", "CreateOrderOptions", "DefaultLspBalanceParams", @@ -16168,6 +18206,7 @@ def wipe_all_transaction_details() -> None: "OnchainActivity", "PreActivityMetadata", "PubkyAuth", + "SingleAddressInfoResult", "SweepResult", "SweepTransactionPreview", "SweepableBalances", @@ -16176,8 +18215,11 @@ def wipe_all_transaction_details() -> None: "TrezorCallMessageResult", "TrezorDeviceInfo", "TrezorFeatures", + "TrezorFeeLevel", "TrezorGetAddressParams", "TrezorGetPublicKeyParams", + "TrezorPrecomposeParams", + "TrezorPrecomposedInput", "TrezorPrevTx", "TrezorPrevTxInput", "TrezorPrevTxOutput", @@ -16272,10 +18314,15 @@ def wipe_all_transaction_details() -> None: "resolve_pubky_url", "start_pubky_auth", "test_notification", + "trezor_account_type_to_script_type", + "trezor_broadcast_raw_tx", "trezor_clear_credentials", "trezor_connect", "trezor_disconnect", + "trezor_fetch_prev_txs", + "trezor_get_account_info", "trezor_get_address", + "trezor_get_address_info", "trezor_get_connected_device", "trezor_get_device_fingerprint", "trezor_get_features", @@ -16285,6 +18332,8 @@ def wipe_all_transaction_details() -> None: "trezor_is_connected", "trezor_is_initialized", "trezor_list_devices", + "trezor_precompose_transaction", + "trezor_precomposed_to_sign_params", "trezor_scan", "trezor_set_transport_callback", "trezor_set_ui_callback", diff --git a/bindings/python/bitkitcore/libbitkitcore.dylib b/bindings/python/bitkitcore/libbitkitcore.dylib index 23cb8c5..b2985a5 100755 Binary files a/bindings/python/bitkitcore/libbitkitcore.dylib and b/bindings/python/bitkitcore/libbitkitcore.dylib differ diff --git a/src/lib.rs b/src/lib.rs index 48a4e1c..7a0f442 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ use crate::activity::{ActivityError, ActivityDB, OnchainActivity, LightningActiv use crate::modules::blocktank::{BlocktankDB, BlocktankError, IBtInfo, IBtOrder, CreateOrderOptions, BtOrderState2, IBt0ConfMinTxFeeWindow, IBtEstimateFeeResponse, IBtEstimateFeeResponse2, CreateCjitOptions, ICJitEntry, CJitStateEnum, IBtBolt11Invoice, IGift, ChannelLiquidityOptions, ChannelLiquidityParams, DefaultLspBalanceParams}; use crate::onchain::{AddressError, ValidationResult, GetAddressResponse, Network, GetAddressesResponse, SweepError, SweepResult, SweepTransactionPreview, SweepableBalances}; use crate::modules::trezor::{TrezorError, TrezorDeviceInfo, TrezorTransportType, TrezorFeatures, TrezorGetAddressParams, TrezorAddressResponse, TrezorGetPublicKeyParams, TrezorPublicKeyResponse, TrezorScriptType, TrezorManager, TrezorSignMessageParams, TrezorSignedMessageResponse, TrezorVerifyMessageParams, TrezorSignTxParams, TrezorSignedTx, TrezorTxInput, TrezorTxOutput, TrezorCoinType, AddressInfo, AccountAddresses}; +use crate::modules::trezor::{AccountInfoError, AccountInfoResult, SingleAddressInfoResult, AccountType, AccountUtxo, ComposeAccount, get_account_info, get_address_info, account_type_to_script_type, fetch_prev_txs, broadcast_raw_tx, TrezorFeeLevel, TrezorSortingStrategy, TrezorPrecomposeOutput, TrezorPrecomposeParams, TrezorPrecomposedInput, TrezorPrecomposedOutput, TrezorPrecomposedResult, precompose_transaction, precomposed_to_sign_params, TrezorPrevTx}; pub use crate::onchain::WordCount; use std::sync::Mutex as StdMutex; @@ -1723,3 +1724,105 @@ pub async fn trezor_clear_credentials(device_id: String) -> Result<(), TrezorErr get_trezor_manager().clear_credentials(&device_id).await }).await.unwrap_or_else(|e| Err(TrezorError::IoError { error_details: format!("Runtime error: {}", e) })) } + +// ============================================================================ +// Account info FFI exports +// ============================================================================ + +/// Query account information for an extended public key via Electrum. +#[uniffi::export] +pub async fn trezor_get_account_info( + extended_key: String, + electrum_url: String, + network: Option, + gap_limit: Option, +) -> Result { + let rt = ensure_runtime(); + rt.spawn(async move { + get_account_info(&extended_key, &electrum_url, network, gap_limit).await + }).await.unwrap_or_else(|e| Err(AccountInfoError::SyncError { + error_details: format!("Runtime error: {}", e), + })) +} + +/// Query balance and UTXOs for a single Bitcoin address via Electrum. +#[uniffi::export] +pub async fn trezor_get_address_info( + address: String, + electrum_url: String, + network: Option, +) -> Result { + let rt = ensure_runtime(); + rt.spawn(async move { + get_address_info(&address, &electrum_url, network).await + }).await.unwrap_or_else(|e| Err(AccountInfoError::SyncError { + error_details: format!("Runtime error: {}", e), + })) +} + +/// Convert an account type to its corresponding script type. +#[uniffi::export] +pub fn trezor_account_type_to_script_type(account_type: AccountType) -> TrezorScriptType { + account_type_to_script_type(account_type) +} + +// ============================================================================ +// Compose FFI exports +// ============================================================================ + +/// Compose a transaction offline for multiple fee levels. +/// +/// No device interaction needed — pure coin selection and fee calculation. +#[uniffi::export] +pub fn trezor_precompose_transaction(params: TrezorPrecomposeParams) -> Vec { + precompose_transaction(params) +} + +/// Convert precomposed results into signing parameters for trezor_sign_tx. +/// +/// The returned params have empty prev_txs — add them before signing. +#[uniffi::export] +pub fn trezor_precomposed_to_sign_params( + inputs: Vec, + outputs: Vec, + coin: Option, +) -> TrezorSignTxParams { + precomposed_to_sign_params(inputs, outputs, coin) +} + +/// Fetch previous transactions from Electrum for Trezor signing. +/// +/// Takes transaction IDs (from TrezorSignTxParams inputs' prev_hash fields), +/// fetches the full transactions from Electrum, and returns them as +/// TrezorPrevTx structures ready to merge into TrezorSignTxParams.prev_txs. +/// +/// Duplicate txids are automatically deduplicated. +#[uniffi::export] +pub async fn trezor_fetch_prev_txs( + txids: Vec, + electrum_url: String, +) -> Result, AccountInfoError> { + let rt = ensure_runtime(); + rt.spawn(async move { + fetch_prev_txs(txids, &electrum_url).await + }).await.unwrap_or_else(|e| Err(AccountInfoError::SyncError { + error_details: format!("Runtime error: {}", e), + })) +} + +/// Broadcast a signed raw transaction via Electrum. +/// +/// Takes a hex-encoded serialized transaction and an Electrum server URL. +/// Returns the transaction ID on success. +#[uniffi::export] +pub async fn trezor_broadcast_raw_tx( + serialized_tx: String, + electrum_url: String, +) -> Result { + let rt = ensure_runtime(); + rt.spawn(async move { + broadcast_raw_tx(serialized_tx, &electrum_url).await + }).await.unwrap_or_else(|e| Err(AccountInfoError::SyncError { + error_details: format!("Runtime error: {}", e), + })) +} diff --git a/src/modules/activity/implementation.rs b/src/modules/activity/implementation.rs index 9af5534..6cca27e 100644 --- a/src/modules/activity/implementation.rs +++ b/src/modules/activity/implementation.rs @@ -178,6 +178,11 @@ const TRIGGER_STATEMENTS: &[&str] = &[ END" ]; +const MIGRATION_STATEMENTS: &[&str] = &[ + // Add seen_at column to activities table + "ALTER TABLE activities ADD COLUMN seen_at INTEGER CHECK (seen_at IS NULL OR seen_at > 0)", +]; + impl ActivityDB { /// Creates a new ActivityDB instance with the specified database path. /// Initializes the database schema if it doesn't exist. @@ -281,6 +286,21 @@ impl ActivityDB { } } + // Run migrations (idempotent — duplicate column errors are expected and ignored) + for statement in MIGRATION_STATEMENTS { + match self.conn.execute(statement, []) { + Ok(_) => {}, + Err(e) => { + let err_msg = e.to_string(); + if !err_msg.contains("duplicate column name") { + return Err(ActivityError::InitializationError { + error_details: format!("Error running migration: {}", e), + }); + } + } + } + } + Ok(()) } diff --git a/src/modules/trezor/README.md b/src/modules/trezor/README.md index 0aefe4a..9c25a15 100644 --- a/src/modules/trezor/README.md +++ b/src/modules/trezor/README.md @@ -62,6 +62,38 @@ FFI-compatible types exposed via UniFFI: #### `errors.rs` Error types with UniFFI support: - `TrezorError` - Main error enum with variants for transport, connection, device errors +- `AccountInfoError` - Errors for blockchain query operations (not device-related): + - `InvalidExtendedKey` - Invalid xpub/ypub/zpub format + - `InvalidAddress` - Unparseable Bitcoin address + - `ElectrumError` - Electrum connection or query failures + - `WalletError` - BDK wallet creation/operation errors + - `SyncError` - Wallet sync failures + - `UnsupportedKeyType` - Unrecognized key prefix + - `NetworkMismatch` - Key prefix doesn't match specified network + +#### `account_info.rs` +Blockchain query functions that do **not** require a connected Trezor device. These connect to an Electrum server via BDK to retrieve account and address data, returning structures compatible with Trezor's `composeTransaction` in precompose mode. + +Types (defined in `types.rs`): +- `AccountType` - Enum: Legacy (BIP44), WrappedSegwit (BIP49), NativeSegwit (BIP84), Taproot (BIP86) +- `AccountUtxo` - UTXO with txid, vout, amount (decimal string), block_height, address, path, confirmations +- `AddressInfo` - Single address with derivation path and transaction count +- `AccountAddresses` - Grouped address lists: used, unused, change +- `ComposeAccount` - Account path, addresses, and UTXOs for Trezor compose +- `AccountInfoResult` - Full query result: account, balance (string), utxo_count, account_type, block_height +- `SingleAddressInfoResult` - Single address query result: address, balance, utxos, transfers, block_height + +Helper functions: +- `detect_account_type(key)` - Identifies account type from xpub/ypub/zpub/tpub/upub/vpub prefix +- `detect_network_from_key(key)` - Detects mainnet vs testnet from key prefix +- `normalize_extended_key(key)` - Converts ypub/zpub/upub/vpub to standard xpub/tpub for BDK +- `build_descriptors(xpub, account_type)` - Creates BDK descriptor strings (pkh, sh(wpkh), wpkh, tr) +- `derive_base_path(account_type, network, account_index)` - Determines BIP derivation path (e.g., `m/84'/0'/0'`) +- `account_type_to_script_type(account_type)` - Maps to `TrezorScriptType` for transaction inputs + +Main functions: +- `get_account_info(extended_key, electrum_url, network, gap_limit)` - Queries full account data from an extended public key +- `get_address_info(address, electrum_url, network)` - Queries balance and UTXOs for a single Bitcoin address #### `implementation.rs` Core `TrezorManager` struct: @@ -94,6 +126,20 @@ pub async fn trezor_get_address(params: TrezorGetAddressParams) -> Result Result; pub async fn trezor_verify_message(params: TrezorVerifyMessageParams) -> Result; pub async fn trezor_disconnect() -> Result<(), TrezorError>; + +// Account info functions (no device required — queries Electrum directly) +pub async fn get_account_info_from_xpub( + extended_key: String, + electrum_url: String, + network: Option, + gap_limit: Option, +) -> Result; + +pub async fn get_address_info_from_address( + address: String, + electrum_url: String, + network: Option, +) -> Result; ``` ## Connection Flow diff --git a/src/modules/trezor/account_info.rs b/src/modules/trezor/account_info.rs new file mode 100644 index 0000000..7d6520c --- /dev/null +++ b/src/modules/trezor/account_info.rs @@ -0,0 +1,693 @@ +//! Account information retrieval for Trezor compose. +//! +//! These functions query the blockchain via Electrum to build account +//! structures compatible with Trezor's transaction compose flow. +//! They do not require a connected Trezor device. + +use std::collections::{HashMap, HashSet}; +use std::str::FromStr; + +use bdk::bitcoin::bip32::ExtendedPubKey; +use bdk::bitcoin::consensus::deserialize; +use bdk::bitcoin::{Network as BdkNetwork, Transaction, Txid}; +use bdk::bitcoin::Address as BdkAddress; +use bdk::blockchain::ElectrumBlockchain; +use bdk::electrum_client::ElectrumApi; +use bdk::wallet::{AddressIndex as BdkAddressIndex, SyncOptions, Wallet}; +use bitcoin::address::Address; + +use super::errors::AccountInfoError; +use super::types::{ + AccountAddresses, AccountInfoResult, AccountType, AccountUtxo, + AddressInfo, ComposeAccount, SingleAddressInfoResult, TrezorCoinType, + TrezorPrevTx, TrezorPrevTxInput, TrezorPrevTxOutput, TrezorScriptType, +}; + +// ============================================================================ +// Network conversion helper +// ============================================================================ + +/// Convert TrezorCoinType to BDK's Network type. +fn coin_type_to_bdk_network(coin: TrezorCoinType) -> BdkNetwork { + match coin { + TrezorCoinType::Bitcoin => BdkNetwork::Bitcoin, + TrezorCoinType::Testnet => BdkNetwork::Testnet, + TrezorCoinType::Signet => BdkNetwork::Signet, + TrezorCoinType::Regtest => BdkNetwork::Regtest, + } +} + +// ============================================================================ +// Key/account type detection helpers +// ============================================================================ + +/// Detect the account type from an extended public key prefix. +pub fn detect_account_type(extended_key: &str) -> Result { + if extended_key.len() < 4 { + return Err(AccountInfoError::InvalidExtendedKey { + error_details: "Key too short".to_string(), + }); + } + match &extended_key[..4] { + "xpub" | "tpub" => Ok(AccountType::Legacy), + "ypub" | "upub" => Ok(AccountType::WrappedSegwit), + "zpub" | "vpub" => Ok(AccountType::NativeSegwit), + prefix => Err(AccountInfoError::UnsupportedKeyType { + error_details: format!("Unsupported key prefix: {}", prefix), + }), + } +} + +/// Detect network from an extended public key prefix. +pub fn detect_network_from_key(extended_key: &str) -> Result { + if extended_key.len() < 4 { + return Err(AccountInfoError::InvalidExtendedKey { + error_details: "Key too short".to_string(), + }); + } + match &extended_key[..4] { + "xpub" | "ypub" | "zpub" => Ok(BdkNetwork::Bitcoin), + "tpub" | "upub" | "vpub" => Ok(BdkNetwork::Testnet), + prefix => Err(AccountInfoError::UnsupportedKeyType { + error_details: format!("Cannot determine network from prefix: {}", prefix), + }), + } +} + +/// Convert ypub/zpub/upub/vpub to xpub/tpub by swapping the version bytes. +/// BDK only understands standard xpub/tpub format. +pub fn normalize_extended_key(extended_key: &str) -> Result { + if extended_key.len() < 4 { + return Err(AccountInfoError::InvalidExtendedKey { + error_details: "Key too short".to_string(), + }); + } + + let prefix = &extended_key[..4]; + let target_version: Option<[u8; 4]> = match prefix { + "xpub" | "tpub" => None, // Already standard format + "ypub" | "zpub" => Some([0x04, 0x88, 0xB2, 0x1E]), // Convert to xpub + "upub" | "vpub" => Some([0x04, 0x35, 0x87, 0xCF]), // Convert to tpub + _ => { + return Err(AccountInfoError::UnsupportedKeyType { + error_details: format!("Unknown key prefix: {}", prefix), + }) + } + }; + + match target_version { + None => Ok(extended_key.to_string()), + Some(version) => { + let mut decoded = bdk::bitcoin::base58::decode_check(extended_key).map_err(|e| { + AccountInfoError::InvalidExtendedKey { + error_details: format!("Base58 decode failed: {:?}", e), + } + })?; + + if decoded.len() < 4 { + return Err(AccountInfoError::InvalidExtendedKey { + error_details: "Decoded key too short".to_string(), + }); + } + + decoded[0..4].copy_from_slice(&version); + Ok(bdk::bitcoin::base58::encode_check(&decoded)) + } + } +} + +/// Build BDK descriptor strings for external and internal keychains. +pub fn build_descriptors( + normalized_xpub: &str, + account_type: AccountType, +) -> (String, String) { + let (external, internal) = match account_type { + AccountType::Legacy => ( + format!("pkh({}/0/*)", normalized_xpub), + format!("pkh({}/1/*)", normalized_xpub), + ), + AccountType::WrappedSegwit => ( + format!("sh(wpkh({}/0/*))", normalized_xpub), + format!("sh(wpkh({}/1/*))", normalized_xpub), + ), + AccountType::NativeSegwit => ( + format!("wpkh({}/0/*)", normalized_xpub), + format!("wpkh({}/1/*)", normalized_xpub), + ), + AccountType::Taproot => ( + format!("tr({}/0/*)", normalized_xpub), + format!("tr({}/1/*)", normalized_xpub), + ), + }; + (external, internal) +} + +/// Determine the BIP derivation base path for Trezor. +pub fn derive_base_path(account_type: AccountType, network: BdkNetwork, account_index: u32) -> String { + let purpose = match account_type { + AccountType::Legacy => 44, + AccountType::WrappedSegwit => 49, + AccountType::NativeSegwit => 84, + AccountType::Taproot => 86, + }; + let coin_type = match network { + BdkNetwork::Bitcoin => 0, + _ => 1, // testnet/signet/regtest all use coin_type 1 + }; + format!("m/{}'/{}'/{}'", purpose, coin_type, account_index) +} + +/// Map AccountType to Trezor's ScriptType for transaction inputs. +pub fn account_type_to_script_type(account_type: AccountType) -> TrezorScriptType { + match account_type { + AccountType::Legacy => TrezorScriptType::SpendAddress, + AccountType::WrappedSegwit => TrezorScriptType::SpendP2shWitness, + AccountType::NativeSegwit => TrezorScriptType::SpendWitness, + AccountType::Taproot => TrezorScriptType::SpendTaproot, + } +} + +// ============================================================================ +// Main async functions +// ============================================================================ + +/// Query account information for an extended public key (xpub/ypub/zpub) via Electrum. +/// Returns data formatted for Trezor's composeTransaction in precompose mode. +pub async fn get_account_info( + extended_key: &str, + electrum_url: &str, + network: Option, + gap_limit: Option, +) -> Result { + let account_type = detect_account_type(extended_key)?; + let detected_network = detect_network_from_key(extended_key)?; + + // Verify network matches if caller specified one + if let Some(coin) = network { + let specified_bdk = coin_type_to_bdk_network(coin); + if specified_bdk != detected_network { + return Err(AccountInfoError::NetworkMismatch { + error_details: format!( + "Key prefix suggests {:?} but {:?} was specified", + detected_network, specified_bdk + ), + }); + } + } + + let normalized_key = normalize_extended_key(extended_key)?; + let (external_desc, internal_desc) = build_descriptors(&normalized_key, account_type); + + // Parse xpub to get account index from child_number + let xpub = ExtendedPubKey::from_str(&normalized_key).map_err(|e| { + AccountInfoError::InvalidExtendedKey { + error_details: format!("Failed to parse extended key: {}", e), + } + })?; + + let account_index = match xpub.child_number { + bdk::bitcoin::bip32::ChildNumber::Hardened { index } => index, + bdk::bitcoin::bip32::ChildNumber::Normal { index } => index, + }; + let base_path = derive_base_path(account_type, detected_network, account_index); + let gap = gap_limit.unwrap_or(20); + let bdk_network = detected_network; + + let electrum_url_owned = electrum_url.to_string(); + let base_path_clone = base_path.clone(); + + // All BDK + Electrum operations in a blocking task + let result = tokio::task::spawn_blocking(move || { + let base_path = base_path_clone; + // Create BDK wallet from descriptors + let wallet = Wallet::new( + &external_desc, + Some(&internal_desc), + bdk_network, + bdk::database::MemoryDatabase::new(), + ) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to create wallet: {}", e), + })?; + + // Connect and sync + let client = bdk::electrum_client::Client::new(&electrum_url_owned).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to connect to Electrum: {}", e), + } + })?; + let blockchain = ElectrumBlockchain::from(client); + + wallet + .sync(&blockchain, SyncOptions::default()) + .map_err(|e| AccountInfoError::SyncError { + error_details: format!("Failed to sync wallet: {}", e), + })?; + + // Get block tip height + let electrum_client = + bdk::electrum_client::Client::new(&electrum_url_owned).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to connect to Electrum: {}", e), + } + })?; + let header = electrum_client.block_headers_subscribe().map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to get block height: {}", e), + } + })?; + let tip_height = header.height as u32; + + // Get the next unused external address index + let next_external = wallet + .get_address(BdkAddressIndex::LastUnused) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to get address: {}", e), + })?; + let max_external = next_external.index + gap; + + // Get the next unused change address index + let next_change = wallet + .get_internal_address(BdkAddressIndex::LastUnused) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to get change address: {}", e), + })?; + let max_change = next_change.index + gap; + + // Build address transfer counts via Electrum script_get_history + let mut address_paths: HashMap = HashMap::new(); + + // External addresses + let mut used_addresses: Vec = Vec::new(); + let mut unused_addresses: Vec = Vec::new(); + + for index in 0..max_external { + let addr = wallet + .get_address(BdkAddressIndex::Peek(index)) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to peek address at index {}: {}", index, e), + })?; + + let addr_str = addr.address.to_string(); + let path = format!("{}/0/{}", base_path, index); + + let script = addr.address.script_pubkey(); + let history = electrum_client.script_get_history(&script).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!( + "Failed to get history for address {}: {}", + addr_str, e + ), + } + })?; + + let transfer_count = history.len() as u32; + address_paths.insert(addr_str.clone(), path.clone()); + + let info = AddressInfo { + address: addr_str, + path, + transfers: transfer_count, + }; + + if transfer_count > 0 { + used_addresses.push(info); + } else { + unused_addresses.push(info); + } + } + + // Change addresses + let mut change_addresses: Vec = Vec::new(); + + for index in 0..max_change { + let addr = wallet + .get_internal_address(BdkAddressIndex::Peek(index)) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!( + "Failed to peek change address at index {}: {}", + index, e + ), + })?; + + let addr_str = addr.address.to_string(); + let path = format!("{}/1/{}", base_path, index); + + let script = addr.address.script_pubkey(); + let history = electrum_client.script_get_history(&script).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!( + "Failed to get history for change address {}: {}", + addr_str, e + ), + } + })?; + + let transfer_count = history.len() as u32; + address_paths.insert(addr_str.clone(), path.clone()); + + change_addresses.push(AddressInfo { + address: addr_str, + path, + transfers: transfer_count, + }); + } + + // Extract UTXOs + let utxos = wallet.list_unspent().map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to list UTXOs: {}", e), + })?; + + // Get transaction details for confirmation info + let transactions = + wallet + .list_transactions(false) + .map_err(|e| AccountInfoError::WalletError { + error_details: format!("Failed to list transactions: {}", e), + })?; + + // Map UTXOs to AccountUtxo + let mut account_utxos: Vec = Vec::new(); + for utxo in &utxos { + let addr_str = BdkAddress::from_script(&utxo.txout.script_pubkey, bdk_network) + .map(|a| a.to_string()) + .unwrap_or_default(); + + let utxo_path = address_paths + .get(&addr_str) + .cloned() + .unwrap_or_default(); + + // Get confirmation info from transaction details + let (block_height, confirmations) = transactions + .iter() + .find(|tx| tx.txid == utxo.outpoint.txid) + .and_then(|tx| tx.confirmation_time.as_ref()) + .map(|conf| { + let height = conf.height as u32; + let confs = tip_height.saturating_sub(height) + 1; + (height, confs) + }) + .unwrap_or((0, 0)); + + account_utxos.push(AccountUtxo { + txid: utxo.outpoint.txid.to_string(), + vout: utxo.outpoint.vout, + amount: utxo.txout.value, + block_height, + address: addr_str, + path: utxo_path, + confirmations, + coinbase: false, + own: true, + required: None, + }); + } + + let balance: u64 = utxos.iter().map(|u| u.txout.value).sum(); + + Ok(( + used_addresses, + unused_addresses, + change_addresses, + account_utxos, + balance, + utxos.len() as u32, + tip_height, + )) + }) + .await + .map_err(|e| AccountInfoError::SyncError { + error_details: format!("Task failed: {}", e), + })??; + + let ( + used_addresses, + unused_addresses, + change_addresses, + account_utxos, + balance, + utxo_count, + block_height, + ) = result; + + let account = ComposeAccount { + path: base_path, + addresses: AccountAddresses { + used: used_addresses, + unused: unused_addresses, + change: change_addresses, + }, + utxo: account_utxos, + }; + + Ok(AccountInfoResult { + account, + balance, + utxo_count, + account_type, + block_height, + }) +} + +/// Query balance and UTXOs for a single Bitcoin address via Electrum. +pub async fn get_address_info( + address: &str, + electrum_url: &str, + _network: Option, +) -> Result { + // Validate address parses correctly using the top-level bitcoin crate + let _parsed = Address::from_str(address).map_err(|e| AccountInfoError::InvalidAddress { + error_details: format!("Invalid address: {}", e), + })?; + + // Parse with BDK's bitcoin crate for script_pubkey generation + let bdk_addr = BdkAddress::from_str(address) + .map_err(|e| AccountInfoError::InvalidAddress { + error_details: format!("Invalid address: {}", e), + })? + .assume_checked(); + + let electrum_url_owned = electrum_url.to_string(); + let addr_str = address.to_string(); + + let result = tokio::task::spawn_blocking(move || { + let client = bdk::electrum_client::Client::new(&electrum_url_owned).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to connect to Electrum: {}", e), + } + })?; + + let script = bdk_addr.script_pubkey(); + + // Get block height + let header = client.block_headers_subscribe().map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to get block height: {}", e), + } + })?; + let tip_height = header.height as u32; + + // Get UTXOs for this address + let utxos = client.script_list_unspent(&script).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to list UTXOs: {}", e), + } + })?; + + // Get history for transfer count + let history = client.script_get_history(&script).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to get history: {}", e), + } + })?; + + let account_utxos: Vec = utxos + .iter() + .map(|utxo| { + let height = if utxo.height > 0 { + utxo.height as u32 + } else { + 0 + }; + let confirmations = if utxo.height > 0 { + tip_height.saturating_sub(utxo.height as u32) + 1 + } else { + 0 + }; + + AccountUtxo { + txid: utxo.tx_hash.to_string(), + vout: utxo.tx_pos as u32, + amount: utxo.value, + block_height: height, + address: addr_str.clone(), + path: String::new(), // No derivation path for single address + confirmations, + coinbase: false, + own: true, + required: None, + } + }) + .collect(); + + let balance: u64 = utxos.iter().map(|u| u.value).sum(); + + Ok::<_, AccountInfoError>(SingleAddressInfoResult { + address: addr_str, + balance, + utxos: account_utxos, + transfers: history.len() as u32, + block_height: tip_height, + }) + }) + .await + .map_err(|e| AccountInfoError::SyncError { + error_details: format!("Task failed: {}", e), + })??; + + Ok(result) +} + +// ============================================================================ +// Previous transaction fetching +// ============================================================================ + +/// Fetch previous transactions from Electrum and convert to TrezorPrevTx format. +/// +/// Takes a list of transaction ID hex strings, fetches the raw transactions +/// from an Electrum server, and returns them as `TrezorPrevTx` structures +/// suitable for inclusion in `TrezorSignTxParams.prev_txs`. +/// +/// Duplicate txids are automatically deduplicated. +pub async fn fetch_prev_txs( + txids: Vec, + electrum_url: &str, +) -> Result, AccountInfoError> { + // Deduplicate txids + let unique_txids: Vec = txids + .into_iter() + .collect::>() + .into_iter() + .collect(); + + // Parse all txid strings upfront, fail fast on bad input + let parsed_txids: Vec<(String, Txid)> = unique_txids + .into_iter() + .map(|txid_str| { + let txid = Txid::from_str(&txid_str).map_err(|e| { + AccountInfoError::InvalidTxid { + error_details: format!("Invalid txid '{}': {}", txid_str, e), + } + })?; + Ok((txid_str, txid)) + }) + .collect::, AccountInfoError>>()?; + + let electrum_url_owned = electrum_url.to_string(); + + let result = tokio::task::spawn_blocking(move || { + let client = bdk::electrum_client::Client::new(&electrum_url_owned).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to connect to Electrum: {}", e), + } + })?; + + let mut prev_txs: Vec = Vec::with_capacity(parsed_txids.len()); + + for (txid_hex, txid) in &parsed_txids { + let tx_bytes = client.transaction_get_raw(txid).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to fetch tx {}: {}", txid_hex, e), + } + })?; + + let tx: Transaction = deserialize(&tx_bytes).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to deserialize tx {}: {}", txid_hex, e), + } + })?; + + prev_txs.push(transaction_to_prev_tx(&tx)); + } + + Ok::<_, AccountInfoError>(prev_txs) + }) + .await + .map_err(|e| AccountInfoError::SyncError { + error_details: format!("Task failed: {}", e), + })??; + + Ok(result) +} + +/// Convert a bitcoin::Transaction to TrezorPrevTx. +pub(crate) fn transaction_to_prev_tx(tx: &Transaction) -> TrezorPrevTx { + let inputs = tx + .input + .iter() + .map(|input| TrezorPrevTxInput { + prev_hash: input.previous_output.txid.to_string(), + prev_index: input.previous_output.vout, + script_sig: hex::encode(input.script_sig.as_bytes()), + sequence: input.sequence.0, + }) + .collect(); + + let outputs = tx + .output + .iter() + .map(|output| TrezorPrevTxOutput { + amount: output.value, + script_pubkey: hex::encode(output.script_pubkey.as_bytes()), + }) + .collect(); + + TrezorPrevTx { + hash: tx.txid().to_string(), + version: tx.version as u32, + lock_time: tx.lock_time.to_consensus_u32(), + inputs, + outputs, + } +} + +/// Broadcast a signed raw transaction via Electrum. +/// +/// Takes a hex-encoded serialized transaction and an Electrum server URL. +/// Returns the transaction ID on success. +pub async fn broadcast_raw_tx( + serialized_tx: String, + electrum_url: &str, +) -> Result { + let tx_bytes = hex::decode(&serialized_tx).map_err(|e| AccountInfoError::ElectrumError { + error_details: format!("Invalid transaction hex: {}", e), + })?; + + // Validate that the bytes are a valid transaction + let _: Transaction = deserialize(&tx_bytes).map_err(|e| AccountInfoError::ElectrumError { + error_details: format!("Invalid transaction data: {}", e), + })?; + + let electrum_url_owned = electrum_url.to_string(); + + let txid = tokio::task::spawn_blocking(move || { + let client = bdk::electrum_client::Client::new(&electrum_url_owned).map_err(|e| { + AccountInfoError::ElectrumError { + error_details: format!("Failed to connect to Electrum: {}", e), + } + })?; + + client + .transaction_broadcast_raw(&tx_bytes) + .map_err(|e| AccountInfoError::ElectrumError { + error_details: format!("Broadcast failed: {}", e), + }) + }) + .await + .map_err(|e| AccountInfoError::SyncError { + error_details: format!("Broadcast task failed: {}", e), + })??; + + Ok(txid.to_string()) +} diff --git a/src/modules/trezor/compose.rs b/src/modules/trezor/compose.rs new file mode 100644 index 0000000..792490c --- /dev/null +++ b/src/modules/trezor/compose.rs @@ -0,0 +1,93 @@ +//! Compose transaction functions for Trezor. +//! +//! Provides offline coin selection and fee calculation, bridging +//! bitkit-core's account types to trezor-connect-rs's compose engine. + +use super::types::{ + TrezorCoinType, TrezorPrecomposeParams, TrezorPrecomposedInput, + TrezorPrecomposedOutput, TrezorPrecomposedResult, + TrezorSignTxParams, TrezorTxInput, TrezorTxOutput, +}; + +/// Compose a transaction offline for multiple fee levels. +/// +/// Takes account data (UTXOs, addresses) and desired outputs, runs coin +/// selection and fee calculation for each fee level, and returns results. +/// No device interaction needed — pure computation. +pub fn precompose_transaction(params: TrezorPrecomposeParams) -> Vec { + let tc_params: trezor_connect_rs::api::compose::PrecomposeParams = params.into(); + let results = trezor_connect_rs::api::compose::precompose(tc_params); + results.into_iter().map(|r| r.into()).collect() +} + +/// Convert precomposed inputs and outputs into TrezorSignTxParams for device signing. +/// +/// The returned `TrezorSignTxParams` has empty `prev_txs` — the caller must +/// provide previous transaction data for non-SegWit inputs before calling +/// `trezor_sign_tx()`. +pub fn precomposed_to_sign_params( + inputs: Vec, + outputs: Vec, + coin: Option, +) -> TrezorSignTxParams { + let sign_inputs: Vec = inputs + .into_iter() + .map(|input| TrezorTxInput { + prev_hash: input.txid, + prev_index: input.vout, + path: input.path, + amount: input.amount.parse().unwrap_or(0), + script_type: input.script_type, + sequence: None, + orig_hash: None, + orig_index: None, + }) + .collect(); + + let sign_outputs: Vec = outputs + .into_iter() + .map(|output| match output { + TrezorPrecomposedOutput::Payment { address, amount } => TrezorTxOutput { + address: Some(address), + path: None, + amount: amount.parse().unwrap_or(0), + script_type: None, + op_return_data: None, + orig_hash: None, + orig_index: None, + }, + TrezorPrecomposedOutput::Change { + path, + amount, + script_type, + .. + } => TrezorTxOutput { + address: None, + path: Some(path), + amount: amount.parse().unwrap_or(0), + script_type: Some(script_type), + op_return_data: None, + orig_hash: None, + orig_index: None, + }, + TrezorPrecomposedOutput::OpReturn { data_hex } => TrezorTxOutput { + address: None, + path: None, + amount: 0, + script_type: None, + op_return_data: Some(data_hex), + orig_hash: None, + orig_index: None, + }, + }) + .collect(); + + TrezorSignTxParams { + inputs: sign_inputs, + outputs: sign_outputs, + coin, + lock_time: None, + version: None, + prev_txs: vec![], + } +} diff --git a/src/modules/trezor/errors.rs b/src/modules/trezor/errors.rs index 9b04ac6..f22f7a3 100644 --- a/src/modules/trezor/errors.rs +++ b/src/modules/trezor/errors.rs @@ -283,3 +283,43 @@ impl From for TrezorError { } } } + +/// Errors specific to account info operations (BDK/Electrum-based). +/// +/// These are separate from `TrezorError` because account info operations +/// do not interact with a Trezor device — they only query the blockchain. +#[derive(uniffi::Error, Debug, Error)] +#[non_exhaustive] +pub enum AccountInfoError { + /// The provided extended public key is invalid or cannot be parsed + #[error("Invalid extended public key: {error_details}")] + InvalidExtendedKey { error_details: String }, + + /// The provided address is invalid + #[error("Invalid address: {error_details}")] + InvalidAddress { error_details: String }, + + /// Electrum connection or query failed + #[error("Electrum connection failed: {error_details}")] + ElectrumError { error_details: String }, + + /// BDK wallet creation or operation error + #[error("Wallet error: {error_details}")] + WalletError { error_details: String }, + + /// Wallet sync with Electrum failed + #[error("Sync failed: {error_details}")] + SyncError { error_details: String }, + + /// The key type/prefix is not recognized + #[error("Unsupported key type: {error_details}")] + UnsupportedKeyType { error_details: String }, + + /// Network mismatch between key prefix and specified network + #[error("Network mismatch: {error_details}")] + NetworkMismatch { error_details: String }, + + /// Invalid transaction ID provided + #[error("Invalid transaction ID: {error_details}")] + InvalidTxid { error_details: String }, +} diff --git a/src/modules/trezor/mod.rs b/src/modules/trezor/mod.rs index 80c3786..3dbdb06 100644 --- a/src/modules/trezor/mod.rs +++ b/src/modules/trezor/mod.rs @@ -7,6 +7,8 @@ mod errors; mod types; mod implementation; mod callbacks; +pub mod account_info; +pub mod compose; #[cfg(test)] mod tests; @@ -14,3 +16,5 @@ pub use errors::*; pub use types::*; pub use implementation::*; pub use callbacks::*; +pub use account_info::{get_account_info, get_address_info, account_type_to_script_type, fetch_prev_txs, broadcast_raw_tx}; +pub use compose::{precompose_transaction, precomposed_to_sign_params}; diff --git a/src/modules/trezor/tests.rs b/src/modules/trezor/tests.rs index 6562c62..6a6cb27 100644 --- a/src/modules/trezor/tests.rs +++ b/src/modules/trezor/tests.rs @@ -385,12 +385,14 @@ mod tests { let response = trezor_connect_rs::SignedTxResponse { signatures: vec!["sig1".to_string(), "sig2".to_string()], serialized_tx: "rawtx".to_string(), + txid: None, }; let result: TrezorSignedTx = response.into(); assert_eq!(result.signatures, vec!["sig1", "sig2"]); assert_eq!(result.serialized_tx, "rawtx"); + assert!(result.txid.is_none()); } // ======================================================================== @@ -580,4 +582,790 @@ mod tests { let err = TrezorError::NotConnected; assert_eq!(err.to_string(), "No device connected. Call trezor_connect first."); } + + // ======================================================================== + // Account Info Helper Tests + // ======================================================================== + + const ACCOUNT_INFO_ELECTRUM_URL: &str = "ssl://fulcrum.bitkit.stag0.blocktank.to:18484"; + + // Test mnemonic (for reference): "wet sea trial spice sheriff bronze total swift slide near easily inhale" + // Account extended public keys derived from the above mnemonic (each funded with 100,000 sats) + const TEST_TPUB: &str = "tpubDDWohsp5dx2iMJ9N7iHbgAEDhH4BJB9NWW1fEW3yA3AFNDREmpzteCXNqppMLUmKFY5q5e3PXtS5CuqWCQbYcGhpPqYAgQSYdwknW9J6sQv"; + const TEST_UPUB: &str = "upub5DWPhYKrgLiETEmgLykymFzBK6gXUNvkE67HLSEh5zcWNRdx2Hxd8HypxaDaK1p62a1kXwe9eBcV3pGm7yEpHh4ebrspSoer4x8Ko29egtv"; + const TEST_VPUB: &str = "vpub5ZgC33hDPuhHSDYrGeoi685MKtdAUB3pkS4rarJ5dv3RABneKLCbhJu2FNfcajo1GukBAwEMBXZWvU7fykTeyKEJrgV6E6NC7BZ3jzp3ffp"; + + // Test addresses derived from the above mnemonic (each funded with 100,000 sats) + const TEST_LEGACY_ADDR: &str = "mixttbUXpVWVpx3qHh7KUiVnxWiNxL2uu9"; + const TEST_P2SH_ADDR: &str = "2N7mA1KBJX8iprzzoFjcbkY1Z2WRZ3bjnsK"; + const TEST_REGTEST_BECH32_ADDR: &str = "bcrt1qj2gz3meule5mc4r4knv65vjds3g88rlxs0jlmq"; + + // --- Unit Tests: Helper Functions --- + + #[test] + fn test_detect_account_type() { + use crate::modules::trezor::account_info::detect_account_type; + use crate::modules::trezor::AccountType; + + // Standard prefixes + assert_eq!(detect_account_type("xpub6ABC").unwrap(), AccountType::Legacy); + assert_eq!(detect_account_type("tpub6ABC").unwrap(), AccountType::Legacy); + assert_eq!(detect_account_type("ypub6ABC").unwrap(), AccountType::WrappedSegwit); + assert_eq!(detect_account_type("upub6ABC").unwrap(), AccountType::WrappedSegwit); + assert_eq!(detect_account_type("zpub6ABC").unwrap(), AccountType::NativeSegwit); + assert_eq!(detect_account_type("vpub6ABC").unwrap(), AccountType::NativeSegwit); + + // Actual test keys + assert_eq!(detect_account_type(TEST_TPUB).unwrap(), AccountType::Legacy); + assert_eq!(detect_account_type(TEST_UPUB).unwrap(), AccountType::WrappedSegwit); + assert_eq!(detect_account_type(TEST_VPUB).unwrap(), AccountType::NativeSegwit); + + // Error cases + assert!(detect_account_type("invalid_key").is_err()); + assert!(detect_account_type("ab").is_err()); // too short + } + + #[test] + fn test_detect_network_from_key() { + use crate::modules::trezor::account_info::detect_network_from_key; + use bdk::bitcoin::Network as BdkNetwork; + + // Mainnet prefixes + assert_eq!(detect_network_from_key("xpub6ABC").unwrap(), BdkNetwork::Bitcoin); + assert_eq!(detect_network_from_key("ypub6ABC").unwrap(), BdkNetwork::Bitcoin); + assert_eq!(detect_network_from_key("zpub6ABC").unwrap(), BdkNetwork::Bitcoin); + + // Testnet prefixes + assert_eq!(detect_network_from_key("tpub6ABC").unwrap(), BdkNetwork::Testnet); + assert_eq!(detect_network_from_key("upub6ABC").unwrap(), BdkNetwork::Testnet); + assert_eq!(detect_network_from_key("vpub6ABC").unwrap(), BdkNetwork::Testnet); + + // Actual test keys + assert_eq!(detect_network_from_key(TEST_TPUB).unwrap(), BdkNetwork::Testnet); + assert_eq!(detect_network_from_key(TEST_UPUB).unwrap(), BdkNetwork::Testnet); + assert_eq!(detect_network_from_key(TEST_VPUB).unwrap(), BdkNetwork::Testnet); + + // Error cases + assert!(detect_network_from_key("invalid").is_err()); + assert!(detect_network_from_key("ab").is_err()); + } + + #[test] + fn test_normalize_extended_key() { + use crate::modules::trezor::account_info::normalize_extended_key; + + // tpub should remain unchanged + let normalized_tpub = normalize_extended_key(TEST_TPUB).unwrap(); + assert!(normalized_tpub.starts_with("tpub"), "tpub should remain as tpub"); + assert_eq!(normalized_tpub, TEST_TPUB); + + // upub should be converted to tpub + let normalized_upub = normalize_extended_key(TEST_UPUB).unwrap(); + assert!(normalized_upub.starts_with("tpub"), "upub should be converted to tpub, got: {}", &normalized_upub[..4]); + + // vpub should be converted to tpub + let normalized_vpub = normalize_extended_key(TEST_VPUB).unwrap(); + assert!(normalized_vpub.starts_with("tpub"), "vpub should be converted to tpub, got: {}", &normalized_vpub[..4]); + + // Error cases + assert!(normalize_extended_key("ab").is_err()); + assert!(normalize_extended_key("invalidkey").is_err()); + } + + #[test] + fn test_build_descriptors() { + use crate::modules::trezor::account_info::build_descriptors; + use crate::modules::trezor::AccountType; + + let test_key = "tpub_test_key"; + + let (ext, int) = build_descriptors(test_key, AccountType::Legacy); + assert_eq!(ext, "pkh(tpub_test_key/0/*)"); + assert_eq!(int, "pkh(tpub_test_key/1/*)"); + + let (ext, int) = build_descriptors(test_key, AccountType::WrappedSegwit); + assert_eq!(ext, "sh(wpkh(tpub_test_key/0/*))"); + assert_eq!(int, "sh(wpkh(tpub_test_key/1/*))"); + + let (ext, int) = build_descriptors(test_key, AccountType::NativeSegwit); + assert_eq!(ext, "wpkh(tpub_test_key/0/*)"); + assert_eq!(int, "wpkh(tpub_test_key/1/*)"); + + let (ext, int) = build_descriptors(test_key, AccountType::Taproot); + assert_eq!(ext, "tr(tpub_test_key/0/*)"); + assert_eq!(int, "tr(tpub_test_key/1/*)"); + } + + #[test] + fn test_derive_base_path() { + use crate::modules::trezor::account_info::derive_base_path; + use crate::modules::trezor::AccountType; + use bdk::bitcoin::Network as BdkNetwork; + + assert_eq!(derive_base_path(AccountType::Legacy, BdkNetwork::Bitcoin, 0), "m/44'/0'/0'"); + assert_eq!(derive_base_path(AccountType::WrappedSegwit, BdkNetwork::Bitcoin, 0), "m/49'/0'/0'"); + assert_eq!(derive_base_path(AccountType::NativeSegwit, BdkNetwork::Bitcoin, 0), "m/84'/0'/0'"); + assert_eq!(derive_base_path(AccountType::Taproot, BdkNetwork::Bitcoin, 0), "m/86'/0'/0'"); + + // Testnet uses coin_type 1 + assert_eq!(derive_base_path(AccountType::Legacy, BdkNetwork::Testnet, 0), "m/44'/1'/0'"); + assert_eq!(derive_base_path(AccountType::NativeSegwit, BdkNetwork::Testnet, 0), "m/84'/1'/0'"); + + // Non-zero account index + assert_eq!(derive_base_path(AccountType::WrappedSegwit, BdkNetwork::Bitcoin, 2), "m/49'/0'/2'"); + assert_eq!(derive_base_path(AccountType::NativeSegwit, BdkNetwork::Testnet, 5), "m/84'/1'/5'"); + } + + #[test] + fn test_account_type_to_script_type() { + use crate::modules::trezor::account_info::account_type_to_script_type; + use crate::modules::trezor::AccountType; + + assert!(matches!(account_type_to_script_type(AccountType::Legacy), TrezorScriptType::SpendAddress)); + assert!(matches!(account_type_to_script_type(AccountType::WrappedSegwit), TrezorScriptType::SpendP2shWitness)); + assert!(matches!(account_type_to_script_type(AccountType::NativeSegwit), TrezorScriptType::SpendWitness)); + assert!(matches!(account_type_to_script_type(AccountType::Taproot), TrezorScriptType::SpendTaproot)); + } + + // --- Integration Tests: get_account_info --- + + #[tokio::test] + #[ignore] + async fn test_get_account_info_tpub() { + use crate::modules::trezor::account_info::get_account_info; + use crate::modules::trezor::AccountType; + + let result = get_account_info( + TEST_TPUB, + ACCOUNT_INFO_ELECTRUM_URL, + None, + None, + ) + .await; + + let info = result.expect("get_account_info(tpub) should succeed"); + assert_eq!(info.account_type, AccountType::Legacy); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(info.utxo_count >= 1, "Expected at least 1 UTXO, got {}", info.utxo_count); + assert!(info.block_height > 0, "Expected block_height > 0"); + assert!(info.account.path.starts_with("m/44'/1'/"), "Expected BIP44 testnet path, got {}", info.account.path); + assert!(!info.account.utxo.is_empty(), "Expected non-empty UTXOs"); + + // Verify address structure + assert!(!info.account.addresses.unused.is_empty(), "Expected unused addresses"); + for addr in &info.account.addresses.used { + assert!(!addr.address.is_empty()); + assert!(addr.path.starts_with("m/44'/1'/")); + assert!(addr.transfers > 0); + } + + for utxo in &info.account.utxo { + assert!(!utxo.txid.is_empty(), "UTXO should have non-empty txid"); + let amount: u64 = utxo.amount; + assert!(amount > 0, "UTXO amount should be > 0"); + assert!(!utxo.path.is_empty(), "UTXO should have a derivation path"); + } + + println!("tpub account info: balance={}, utxos={}, path={}, block_height={}", + info.balance, info.utxo_count, info.account.path, info.block_height); + } + + #[tokio::test] + #[ignore] + async fn test_get_account_info_upub() { + use crate::modules::trezor::account_info::get_account_info; + use crate::modules::trezor::AccountType; + + let result = get_account_info( + TEST_UPUB, + ACCOUNT_INFO_ELECTRUM_URL, + None, + None, + ) + .await; + + let info = result.expect("get_account_info(upub) should succeed"); + assert_eq!(info.account_type, AccountType::WrappedSegwit); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(info.utxo_count >= 1, "Expected at least 1 UTXO, got {}", info.utxo_count); + assert!(info.block_height > 0); + assert!(info.account.path.starts_with("m/49'/1'/"), "Expected BIP49 testnet path, got {}", info.account.path); + assert!(!info.account.utxo.is_empty()); + + for utxo in &info.account.utxo { + assert!(!utxo.txid.is_empty()); + let amount: u64 = utxo.amount; + assert!(amount > 0); + } + + println!("upub account info: balance={}, utxos={}, path={}, block_height={}", + info.balance, info.utxo_count, info.account.path, info.block_height); + } + + #[tokio::test] + #[ignore] + async fn test_get_account_info_vpub() { + use crate::modules::trezor::account_info::get_account_info; + use crate::modules::trezor::AccountType; + + let result = get_account_info( + TEST_VPUB, + ACCOUNT_INFO_ELECTRUM_URL, + None, + None, + ) + .await; + + let info = result.expect("get_account_info(vpub) should succeed"); + assert_eq!(info.account_type, AccountType::NativeSegwit); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(info.utxo_count >= 1, "Expected at least 1 UTXO, got {}", info.utxo_count); + assert!(info.block_height > 0); + assert!(info.account.path.starts_with("m/84'/1'/"), "Expected BIP84 testnet path, got {}", info.account.path); + assert!(!info.account.utxo.is_empty()); + + for utxo in &info.account.utxo { + assert!(!utxo.txid.is_empty()); + let amount: u64 = utxo.amount; + assert!(amount > 0); + } + + println!("vpub account info: balance={}, utxos={}, path={}, block_height={}", + info.balance, info.utxo_count, info.account.path, info.block_height); + } + + // --- Integration Tests: get_address_info --- + + #[tokio::test] + #[ignore] + async fn test_get_address_info_legacy() { + use crate::modules::trezor::account_info::get_address_info; + + let result = get_address_info( + TEST_LEGACY_ADDR, + ACCOUNT_INFO_ELECTRUM_URL, + None, + ) + .await; + + let info = result.expect("get_address_info(legacy) should succeed"); + assert_eq!(info.address, TEST_LEGACY_ADDR); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(!info.utxos.is_empty(), "Expected non-empty UTXOs"); + assert!(info.transfers >= 1, "Expected at least 1 transfer, got {}", info.transfers); + assert!(info.block_height > 0); + + for utxo in &info.utxos { + assert_eq!(utxo.address, TEST_LEGACY_ADDR); + assert!(!utxo.txid.is_empty()); + let amount: u64 = utxo.amount; + assert!(amount > 0); + } + + println!("Legacy address info: balance={}, utxos={}, transfers={}, block_height={}", + info.balance, info.utxos.len(), info.transfers, info.block_height); + } + + #[tokio::test] + #[ignore] + async fn test_get_address_info_p2sh() { + use crate::modules::trezor::account_info::get_address_info; + + let result = get_address_info( + TEST_P2SH_ADDR, + ACCOUNT_INFO_ELECTRUM_URL, + None, + ) + .await; + + let info = result.expect("get_address_info(p2sh) should succeed"); + assert_eq!(info.address, TEST_P2SH_ADDR); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(!info.utxos.is_empty()); + assert!(info.transfers >= 1); + assert!(info.block_height > 0); + + for utxo in &info.utxos { + assert_eq!(utxo.address, TEST_P2SH_ADDR); + } + + println!("P2SH address info: balance={}, utxos={}, transfers={}, block_height={}", + info.balance, info.utxos.len(), info.transfers, info.block_height); + } + + #[tokio::test] + #[ignore] + async fn test_get_address_info_regtest_bech32() { + use crate::modules::trezor::account_info::get_address_info; + + let result = get_address_info( + TEST_REGTEST_BECH32_ADDR, + ACCOUNT_INFO_ELECTRUM_URL, + None, + ) + .await; + + let info = result.expect("get_address_info(regtest bech32) should succeed"); + assert_eq!(info.address, TEST_REGTEST_BECH32_ADDR); + let balance: u64 = info.balance; + assert!(balance >= 100_000, "Expected balance >= 100,000 sats, got {}", balance); + assert!(!info.utxos.is_empty()); + assert!(info.transfers >= 1); + assert!(info.block_height > 0); + + for utxo in &info.utxos { + assert_eq!(utxo.address, TEST_REGTEST_BECH32_ADDR); + } + + println!("Regtest bech32 address info: balance={}, utxos={}, transfers={}, block_height={}", + info.balance, info.utxos.len(), info.transfers, info.block_height); + } + + // --- Error / Edge Case Tests --- + + #[test] + fn test_get_account_info_invalid_key() { + use crate::modules::trezor::account_info::get_account_info; + + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(get_account_info( + "not_a_valid_xpub", + ACCOUNT_INFO_ELECTRUM_URL, + None, + None, + )); + + assert!(result.is_err(), "Expected error for invalid key"); + } + + #[test] + fn test_get_account_info_network_mismatch() { + use crate::modules::trezor::account_info::get_account_info; + use crate::modules::trezor::AccountInfoError; + + let rt = tokio::runtime::Runtime::new().unwrap(); + // tpub is testnet, but we specify Bitcoin (mainnet) — should get NetworkMismatch + let result = rt.block_on(get_account_info( + TEST_TPUB, + ACCOUNT_INFO_ELECTRUM_URL, + Some(TrezorCoinType::Bitcoin), + None, + )); + + assert!(result.is_err(), "Expected NetworkMismatch error"); + match result.unwrap_err() { + AccountInfoError::NetworkMismatch { .. } => {} + other => panic!("Expected NetworkMismatch, got: {:?}", other), + } + } + + #[test] + fn test_get_address_info_invalid_address() { + use crate::modules::trezor::account_info::get_address_info; + use crate::modules::trezor::AccountInfoError; + + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(get_address_info( + "not_a_valid_address", + ACCOUNT_INFO_ELECTRUM_URL, + None, + )); + + assert!(result.is_err(), "Expected error for invalid address"); + match result.unwrap_err() { + AccountInfoError::InvalidAddress { .. } => {} + other => panic!("Expected InvalidAddress, got: {:?}", other), + } + } + + #[tokio::test] + #[ignore] + async fn test_get_address_info_invalid_electrum() { + use crate::modules::trezor::account_info::get_address_info; + + let result = get_address_info( + TEST_LEGACY_ADDR, + "invalid://url", + None, + ) + .await; + + assert!(result.is_err(), "Expected error for invalid electrum URL"); + } + + // ======================================================================== + // Compose Integration Tests + // ======================================================================== + + use crate::modules::trezor::{ + TrezorFeeLevel, TrezorSortingStrategy, TrezorPrecomposeOutput, + TrezorPrecomposeParams, TrezorPrecomposedResult, + AccountUtxo, ComposeAccount, AccountAddresses, AddressInfo, + }; + use crate::modules::trezor::compose::{precompose_transaction, precomposed_to_sign_params}; + + fn test_compose_account() -> ComposeAccount { + ComposeAccount { + path: "m/84'/1'/0'".to_string(), + addresses: AccountAddresses { + used: vec![ + AddressInfo { + address: "bcrt1qj2gz3meule5mc4r4knv65vjds3g88rlxs0jlmq".to_string(), + path: "m/84'/1'/0'/0/0".to_string(), + transfers: 2, + }, + ], + unused: vec![ + AddressInfo { + address: "bcrt1qeyn4amkfpuz589f6x7adzclqx98akv6mvzvndp".to_string(), + path: "m/84'/1'/0'/0/1".to_string(), + transfers: 0, + }, + ], + change: vec![ + AddressInfo { + address: "bcrt1q8lahff3lcealxhv2ygde4k08fsy0v5a95020r0".to_string(), + path: "m/84'/1'/0'/1/0".to_string(), + transfers: 0, + }, + ], + }, + utxo: vec![ + AccountUtxo { + txid: "559a6e22b4064c6d1dd3e1ec72a0f65e89093924aba760f7d71d6c4f551e99ba".to_string(), + vout: 1, + amount: 100_000, + block_height: 71692, + address: "bcrt1qj2gz3meule5mc4r4knv65vjds3g88rlxs0jlmq".to_string(), + path: "m/84'/1'/0'/0/0".to_string(), + confirmations: 3684, + coinbase: false, + own: true, + required: None, + }, + ], + } + } + + #[test] + fn test_precompose_basic_payment() { + let params = TrezorPrecomposeParams { + outputs: vec![ + TrezorPrecomposeOutput::Payment { + address: "bcrt1qeyn4amkfpuz589f6x7adzclqx98akv6mvzvndp".to_string(), + amount: "50000".to_string(), + }, + ], + coin: "Regtest".to_string(), + account: test_compose_account(), + fee_levels: vec![ + TrezorFeeLevel { + fee_per_unit: "2".to_string(), + base_fee: None, + floor_base_fee: None, + }, + ], + sequence: None, + sorting_strategy: Some(TrezorSortingStrategy::None), + }; + + let results = precompose_transaction(params); + assert_eq!(results.len(), 1); + + match &results[0] { + TrezorPrecomposedResult::Final { total_spent, fee, inputs, outputs, .. } => { + let total: u64 = total_spent.parse().unwrap(); + let fee_val: u64 = fee.parse().unwrap(); + assert!(fee_val > 0, "Fee should be > 0"); + assert_eq!(total, 50_000 + fee_val, "total_spent = amount + fee"); + assert!(!inputs.is_empty(), "Should have selected inputs"); + assert!(outputs.len() >= 1, "Should have at least one output"); + } + TrezorPrecomposedResult::Error { error } => panic!("Compose failed: {}", error), + TrezorPrecomposedResult::NonFinal { .. } => panic!("Expected Final result"), + } + } + + #[test] + fn test_precompose_to_sign_params_conversion() { + let params = TrezorPrecomposeParams { + outputs: vec![ + TrezorPrecomposeOutput::Payment { + address: "bcrt1qeyn4amkfpuz589f6x7adzclqx98akv6mvzvndp".to_string(), + amount: "50000".to_string(), + }, + ], + coin: "Regtest".to_string(), + account: test_compose_account(), + fee_levels: vec![ + TrezorFeeLevel { + fee_per_unit: "2".to_string(), + base_fee: None, + floor_base_fee: None, + }, + ], + sequence: None, + sorting_strategy: Some(TrezorSortingStrategy::None), + }; + + let results = precompose_transaction(params); + match &results[0] { + TrezorPrecomposedResult::Final { inputs, outputs, .. } => { + let sign_params = precomposed_to_sign_params( + inputs.clone(), + outputs.clone(), + Some(TrezorCoinType::Regtest), + ); + + assert!(!sign_params.inputs.is_empty()); + assert!(!sign_params.outputs.is_empty()); + assert!(sign_params.prev_txs.is_empty(), "prev_txs should be empty (caller provides)"); + + for input in &sign_params.inputs { + assert!(!input.prev_hash.is_empty()); + assert!(input.amount > 0); + assert!(input.path.starts_with("m/84'/1'/0'")); + assert!(matches!(input.script_type, TrezorScriptType::SpendWitness)); + } + + let has_payment = sign_params.outputs.iter().any(|o| o.address.is_some()); + assert!(has_payment, "Should have at least one payment output"); + } + other => panic!("Expected Final, got {:?}", other), + } + } + + #[test] + fn test_precompose_insufficient_funds() { + let params = TrezorPrecomposeParams { + outputs: vec![ + TrezorPrecomposeOutput::Payment { + address: "bcrt1qeyn4amkfpuz589f6x7adzclqx98akv6mvzvndp".to_string(), + amount: "999999999".to_string(), + }, + ], + coin: "Regtest".to_string(), + account: test_compose_account(), + fee_levels: vec![ + TrezorFeeLevel { + fee_per_unit: "2".to_string(), + base_fee: None, + floor_base_fee: None, + }, + ], + sequence: None, + sorting_strategy: None, + }; + + let results = precompose_transaction(params); + assert_eq!(results.len(), 1); + assert!(matches!(&results[0], TrezorPrecomposedResult::Error { .. })); + } + + #[test] + fn test_precompose_multiple_fee_levels() { + let params = TrezorPrecomposeParams { + outputs: vec![ + TrezorPrecomposeOutput::Payment { + address: "bcrt1qeyn4amkfpuz589f6x7adzclqx98akv6mvzvndp".to_string(), + amount: "50000".to_string(), + }, + ], + coin: "Regtest".to_string(), + account: test_compose_account(), + fee_levels: vec![ + TrezorFeeLevel { fee_per_unit: "1".to_string(), base_fee: None, floor_base_fee: None }, + TrezorFeeLevel { fee_per_unit: "5".to_string(), base_fee: None, floor_base_fee: None }, + TrezorFeeLevel { fee_per_unit: "20".to_string(), base_fee: None, floor_base_fee: None }, + ], + sequence: None, + sorting_strategy: Some(TrezorSortingStrategy::None), + }; + + let results = precompose_transaction(params); + assert_eq!(results.len(), 3); + + let mut prev_fee = 0u64; + for (i, result) in results.iter().enumerate() { + match result { + TrezorPrecomposedResult::Final { fee, .. } => { + let fee_val: u64 = fee.parse().unwrap(); + assert!(fee_val > prev_fee, "Fee level {} should be higher than previous", i); + prev_fee = fee_val; + } + TrezorPrecomposedResult::Error { error } => panic!("Fee level {} failed: {}", i, error), + _ => panic!("Expected Final for fee level {}", i), + } + } + } + + #[test] + fn test_sorting_strategy_conversion() { + use trezor_connect_rs::compose::sorting::SortingStrategy; + + let bip69: SortingStrategy = TrezorSortingStrategy::Bip69.into(); + assert_eq!(bip69, SortingStrategy::Bip69); + + let random: SortingStrategy = TrezorSortingStrategy::Random.into(); + assert_eq!(random, SortingStrategy::Random); + + let none: SortingStrategy = TrezorSortingStrategy::None.into(); + assert_eq!(none, SortingStrategy::None); + + // Reverse + let back: TrezorSortingStrategy = SortingStrategy::Bip69.into(); + assert!(matches!(back, TrezorSortingStrategy::Bip69)); + } + + #[test] + fn test_script_type_reverse_conversion() { + use trezor_connect_rs::ScriptType; + + let cases = vec![ + (ScriptType::SpendAddress, TrezorScriptType::SpendAddress), + (ScriptType::SpendP2SHWitness, TrezorScriptType::SpendP2shWitness), + (ScriptType::SpendWitness, TrezorScriptType::SpendWitness), + (ScriptType::SpendTaproot, TrezorScriptType::SpendTaproot), + (ScriptType::SpendMultisig, TrezorScriptType::SpendMultisig), + (ScriptType::External, TrezorScriptType::External), + ]; + + for (tc_type, expected) in cases { + let result: TrezorScriptType = tc_type.into(); + assert_eq!(result, expected); + } + } + + // ======================================================================== + // Previous Transaction Fetch Tests + // ======================================================================== + + #[test] + fn test_transaction_to_prev_tx_conversion() { + use bdk::bitcoin::consensus::deserialize; + use bdk::bitcoin::Transaction; + use crate::modules::trezor::account_info::transaction_to_prev_tx; + + // A minimal valid raw transaction (1 input, 1 output, version 2, locktime 0) + // Decoded: version=2, 1 input (prev_hash=all-ones, vout=0, scriptsig=empty, seq=0xffffffff), + // 1 output (value=50000 sats, scriptpubkey=OP_0 <20-byte-hash>) + let raw_tx_hex = concat!( + "02000000", // version 2 + "01", // 1 input + "0101010101010101010101010101010101010101010101010101010101010101", // prev_hash + "00000000", // prev_index 0 + "00", // empty scriptsig + "ffffffff", // sequence + "01", // 1 output + "50c3000000000000", // value 50000 sats + "160014", // scriptpubkey length + OP_0 PUSH20 + "0000000000000000000000000000000000000000", // 20 zero bytes + "00000000", // locktime 0 + ); + let raw_tx_bytes = hex::decode(raw_tx_hex).unwrap(); + let tx: Transaction = deserialize(&raw_tx_bytes).unwrap(); + + let prev_tx = transaction_to_prev_tx(&tx); + + // Verify hash matches computed txid + assert_eq!(prev_tx.hash, tx.txid().to_string()); + assert_eq!(prev_tx.version, 2); + assert_eq!(prev_tx.lock_time, 0); + + // Verify input mapping + assert_eq!(prev_tx.inputs.len(), 1); + let input = &prev_tx.inputs[0]; + assert_eq!(input.prev_hash, tx.input[0].previous_output.txid.to_string()); + assert_eq!(input.prev_index, 0); + assert_eq!(input.script_sig, ""); // empty scriptsig + assert_eq!(input.sequence, 0xffffffff); + + // Verify output mapping + assert_eq!(prev_tx.outputs.len(), 1); + let output = &prev_tx.outputs[0]; + assert_eq!(output.amount, 50000); + assert_eq!(output.script_pubkey, "00140000000000000000000000000000000000000000"); + } + + #[test] + fn test_fetch_prev_txs_invalid_txid() { + use crate::modules::trezor::account_info::fetch_prev_txs; + use crate::modules::trezor::AccountInfoError; + + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(fetch_prev_txs( + vec!["not_a_valid_txid".to_string()], + "ssl://electrum.blockstream.info:60002", + )); + + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), AccountInfoError::InvalidTxid { .. })); + } + + #[tokio::test] + #[ignore] + async fn test_fetch_prev_txs_from_electrum() { + use crate::modules::trezor::account_info::fetch_prev_txs; + + // Use a known funded testnet address to discover txids to fetch + let result = crate::modules::trezor::account_info::get_address_info( + TEST_LEGACY_ADDR, + ACCOUNT_INFO_ELECTRUM_URL, + None, + ).await; + + let info = result.expect("get_address_info should succeed"); + assert!(!info.utxos.is_empty(), "Need at least one UTXO for test"); + + let txids: Vec = info.utxos.iter().map(|u| u.txid.clone()).collect(); + let prev_txs = fetch_prev_txs(txids.clone(), ACCOUNT_INFO_ELECTRUM_URL) + .await + .expect("fetch_prev_txs should succeed"); + + // Should have fetched at least one prev tx (deduplication may reduce count) + assert!(!prev_txs.is_empty()); + + // Every fetched tx should have non-empty inputs and outputs + for prev_tx in &prev_txs { + assert!(!prev_tx.hash.is_empty()); + assert!(!prev_tx.inputs.is_empty()); + assert!(!prev_tx.outputs.is_empty()); + } + } + + #[test] + fn test_broadcast_raw_tx_invalid_hex() { + use crate::modules::trezor::account_info::broadcast_raw_tx; + use crate::modules::trezor::AccountInfoError; + + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(broadcast_raw_tx( + "not_valid_hex".to_string(), + "ssl://electrum.blockstream.info:60002", + )); + + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), AccountInfoError::ElectrumError { .. })); + } + + #[test] + fn test_broadcast_raw_tx_invalid_tx_data() { + use crate::modules::trezor::account_info::broadcast_raw_tx; + use crate::modules::trezor::AccountInfoError; + + let rt = tokio::runtime::Runtime::new().unwrap(); + // Valid hex but not a valid transaction + let result = rt.block_on(broadcast_raw_tx( + "deadbeef".to_string(), + "ssl://electrum.blockstream.info:60002", + )); + + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), AccountInfoError::ElectrumError { .. })); + } } diff --git a/src/modules/trezor/types.rs b/src/modules/trezor/types.rs index 13e62ef..4ab37d0 100644 --- a/src/modules/trezor/types.rs +++ b/src/modules/trezor/types.rs @@ -127,6 +127,19 @@ impl From for trezor_connect_rs::ScriptType { } } +impl From for TrezorScriptType { + fn from(t: trezor_connect_rs::ScriptType) -> Self { + match t { + trezor_connect_rs::ScriptType::SpendAddress => TrezorScriptType::SpendAddress, + trezor_connect_rs::ScriptType::SpendP2SHWitness => TrezorScriptType::SpendP2shWitness, + trezor_connect_rs::ScriptType::SpendWitness => TrezorScriptType::SpendWitness, + trezor_connect_rs::ScriptType::SpendTaproot => TrezorScriptType::SpendTaproot, + trezor_connect_rs::ScriptType::SpendMultisig => TrezorScriptType::SpendMultisig, + trezor_connect_rs::ScriptType::External => TrezorScriptType::External, + } + } +} + /// Bitcoin network / coin type for Trezor operations. #[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)] pub enum TrezorCoinType { @@ -413,6 +426,8 @@ pub struct TrezorSignedTx { pub signatures: Vec, /// Serialized transaction (hex) pub serialized_tx: String, + /// Broadcast transaction ID (populated when push=true) + pub txid: Option, } impl From for trezor_connect_rs::SignTxInput { @@ -426,6 +441,12 @@ impl From for trezor_connect_rs::SignTxInput { sequence: input.sequence, orig_hash: input.orig_hash, orig_index: input.orig_index, + multisig: None, + script_pubkey: None, + script_sig: None, + witness: None, + ownership_proof: None, + commitment_data: None, } } } @@ -440,6 +461,8 @@ impl From for trezor_connect_rs::SignTxOutput { op_return_data: output.op_return_data, orig_hash: output.orig_hash, orig_index: output.orig_index, + multisig: None, + payment_req_index: None, } } } @@ -472,6 +495,7 @@ impl From for trezor_connect_rs::SignTxPrevTx { lock_time: tx.lock_time, inputs: tx.inputs.into_iter().map(|i| i.into()).collect(), outputs: tx.outputs.into_iter().map(|o| o.into()).collect(), + extra_data: None, } } } @@ -485,6 +509,12 @@ impl From for trezor_connect_rs::SignTxParams { lock_time: params.lock_time, version: params.version, prev_txs: params.prev_txs.into_iter().map(|t| t.into()).collect(), + push: None, + amount_unit: None, + serialize: None, + chunkify: None, + unlock_path: None, + payment_requests: vec![], } } } @@ -494,28 +524,409 @@ impl From for TrezorSignedTx { Self { signatures: response.signatures, serialized_tx: response.serialized_tx, + txid: response.txid, } } } -/// Address information -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, uniffi::Record)] +// ============================================================================ +// Account info types for Trezor compose +// ============================================================================ + +/// Account type classification for extended public keys. +/// +/// Determines the BIP standard, derivation path purpose, and script type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)] +pub enum AccountType { + /// BIP44 legacy (P2PKH) — xpub/tpub prefix + Legacy, + /// BIP49 wrapped segwit (P2SH-P2WPKH) — ypub/upub prefix + WrappedSegwit, + /// BIP84 native segwit (P2WPKH) — zpub/vpub prefix + NativeSegwit, + /// BIP86 taproot (P2TR) + Taproot, +} + +/// A UTXO in the format expected by Trezor compose. +#[derive(Debug, Clone, uniffi::Record)] +pub struct AccountUtxo { + /// Transaction ID (hex) + pub txid: String, + /// Output index + pub vout: u32, + /// Amount in satoshis + pub amount: u64, + /// Block height where the UTXO was confirmed (0 if unconfirmed) + pub block_height: u32, + /// Address holding this UTXO + pub address: String, + /// BIP32 derivation path (e.g., "m/84'/0'/0'/0/0") + pub path: String, + /// Number of confirmations (0 if unconfirmed) + pub confirmations: u32, + /// Whether this is a coinbase output + pub coinbase: bool, + /// Whether this UTXO is owned by the account + pub own: bool, + /// Whether this UTXO must be included in the transaction + pub required: Option, +} + +/// Information about a single address in an account. +#[derive(Debug, Clone, uniffi::Record)] pub struct AddressInfo { - /// Address string + /// The Bitcoin address pub address: String, - /// Derivation path + /// BIP32 derivation path pub path: String, - /// Number of transfers + /// Number of transactions involving this address pub transfers: u32, } -/// Account addresses -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, uniffi::Record)] +/// Grouped address lists for an account. +#[derive(Debug, Clone, uniffi::Record)] pub struct AccountAddresses { - /// Used addresses + /// Used receive addresses (have at least one transaction) pub used: Vec, - /// Unused addresses + /// Unused receive addresses (no transactions yet) pub unused: Vec, /// Change addresses pub change: Vec, } + +/// Full account structure for Trezor compose. +/// +/// This is the `account` object expected by `composeTransaction` in +/// precompose mode. +#[derive(Debug, Clone, uniffi::Record)] +pub struct ComposeAccount { + /// Account derivation path (e.g., "m/84'/0'/0'") + pub path: String, + /// Categorized addresses + pub addresses: AccountAddresses, + /// Unspent transaction outputs + pub utxo: Vec, +} + +/// Result from querying an extended public key — ready for Trezor compose. +#[derive(Debug, Clone, uniffi::Record)] +pub struct AccountInfoResult { + /// The compose-compatible account structure + pub account: ComposeAccount, + /// Total confirmed balance in satoshis + pub balance: u64, + /// Number of UTXOs + pub utxo_count: u32, + /// The detected or specified account type + pub account_type: AccountType, + /// The current blockchain tip height + pub block_height: u32, +} + +// ============================================================================ +// From impls: bitkit-core account types → trezor-connect-rs compose types +// ============================================================================ + +impl From for trezor_connect_rs::api::compose::AccountAddress { + fn from(a: AddressInfo) -> Self { + Self { + address: a.address, + path: a.path, + transfers: a.transfers, + } + } +} + +impl From for trezor_connect_rs::api::compose::AccountAddresses { + fn from(a: AccountAddresses) -> Self { + Self { + used: a.used.into_iter().map(|x| x.into()).collect(), + unused: a.unused.into_iter().map(|x| x.into()).collect(), + change: a.change.into_iter().map(|x| x.into()).collect(), + } + } +} + +impl From for trezor_connect_rs::api::compose::ComposeUtxo { + fn from(u: AccountUtxo) -> Self { + Self { + txid: u.txid, + vout: u.vout, + amount: u.amount, + address: u.address, + path: u.path, + confirmations: u.confirmations, + coinbase: u.coinbase, + own: u.own, + required: u.required, + } + } +} + +impl From for trezor_connect_rs::api::compose::ComposeAccount { + fn from(a: ComposeAccount) -> Self { + Self { + path: a.path, + addresses: a.addresses.into(), + utxo: a.utxo.into_iter().map(|u| u.into()).collect(), + } + } +} + +/// Result from querying a single Bitcoin address. +#[derive(Debug, Clone, uniffi::Record)] +pub struct SingleAddressInfoResult { + /// The queried address + pub address: String, + /// Total confirmed balance in satoshis + pub balance: u64, + /// UTXOs for this address + pub utxos: Vec, + /// Number of transactions involving this address + pub transfers: u32, + /// Current blockchain tip height + pub block_height: u32, +} + +// ============================================================================ +// Compose FFI types +// ============================================================================ + +/// Fee level for transaction composition. +#[derive(Debug, Clone, uniffi::Record)] +pub struct TrezorFeeLevel { + /// Fee rate in sat/vB + pub fee_per_unit: String, + /// Base fee in satoshis (optional, added to calculated fee) + pub base_fee: Option, + /// Whether to use floor for base fee calculation + pub floor_base_fee: Option, +} + +impl From for trezor_connect_rs::api::compose::FeeLevel { + fn from(f: TrezorFeeLevel) -> Self { + Self { + fee_per_unit: f.fee_per_unit, + base_fee: f.base_fee, + floor_base_fee: f.floor_base_fee, + } + } +} + +/// Sorting strategy for transaction inputs and outputs. +#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)] +pub enum TrezorSortingStrategy { + /// BIP-69: deterministic lexicographic sorting + Bip69, + /// Random shuffle (better privacy) + Random, + /// Keep original order + None, +} + +impl From for trezor_connect_rs::compose::sorting::SortingStrategy { + fn from(s: TrezorSortingStrategy) -> Self { + match s { + TrezorSortingStrategy::Bip69 => trezor_connect_rs::compose::sorting::SortingStrategy::Bip69, + TrezorSortingStrategy::Random => trezor_connect_rs::compose::sorting::SortingStrategy::Random, + TrezorSortingStrategy::None => trezor_connect_rs::compose::sorting::SortingStrategy::None, + } + } +} + +impl From for TrezorSortingStrategy { + fn from(s: trezor_connect_rs::compose::sorting::SortingStrategy) -> Self { + match s { + trezor_connect_rs::compose::sorting::SortingStrategy::Bip69 => TrezorSortingStrategy::Bip69, + trezor_connect_rs::compose::sorting::SortingStrategy::Random => TrezorSortingStrategy::Random, + trezor_connect_rs::compose::sorting::SortingStrategy::None => TrezorSortingStrategy::None, + } + } +} + +/// Output specification for precompose. +#[derive(Debug, Clone, uniffi::Enum)] +pub enum TrezorPrecomposeOutput { + /// Payment to a specific address + Payment { address: String, amount: String }, + /// Payment without address (estimation only) + PaymentNoAddress { amount: String }, + /// Send all remaining funds to an address + SendMax { address: String }, + /// Send all remaining funds (no address) + SendMaxNoAddress, + /// OP_RETURN data output + OpReturn { data_hex: String }, +} + +impl From for trezor_connect_rs::api::compose::PrecomposeOutput { + fn from(o: TrezorPrecomposeOutput) -> Self { + match o { + TrezorPrecomposeOutput::Payment { address, amount } => { + trezor_connect_rs::api::compose::PrecomposeOutput::Payment { address, amount } + } + TrezorPrecomposeOutput::PaymentNoAddress { amount } => { + trezor_connect_rs::api::compose::PrecomposeOutput::PaymentNoAddress { amount } + } + TrezorPrecomposeOutput::SendMax { address } => { + trezor_connect_rs::api::compose::PrecomposeOutput::SendMax { address } + } + TrezorPrecomposeOutput::SendMaxNoAddress => { + trezor_connect_rs::api::compose::PrecomposeOutput::SendMaxNoAddress + } + TrezorPrecomposeOutput::OpReturn { data_hex } => { + trezor_connect_rs::api::compose::PrecomposeOutput::OpReturn { data_hex } + } + } + } +} + +/// Parameters for precompose transaction. +#[derive(Debug, Clone, uniffi::Record)] +pub struct TrezorPrecomposeParams { + /// Desired outputs + pub outputs: Vec, + /// Coin name (e.g., "Bitcoin", "Regtest") + pub coin: String, + /// Account with UTXOs and addresses + pub account: ComposeAccount, + /// Fee levels to evaluate + pub fee_levels: Vec, + /// Default sequence number + pub sequence: Option, + /// Sorting strategy for inputs/outputs + pub sorting_strategy: Option, +} + +impl From for trezor_connect_rs::api::compose::PrecomposeParams { + fn from(p: TrezorPrecomposeParams) -> Self { + Self { + outputs: p.outputs.into_iter().map(|o| o.into()).collect(), + coin: p.coin, + account: p.account.into(), + fee_levels: p.fee_levels.into_iter().map(|f| f.into()).collect(), + sequence: p.sequence, + sorting_strategy: p.sorting_strategy.map(|s| s.into()), + } + } +} + +/// Input in a precomposed result. +#[derive(Debug, Clone, uniffi::Record)] +pub struct TrezorPrecomposedInput { + /// Transaction ID (hex) + pub txid: String, + /// Output index + pub vout: u32, + /// Amount in satoshis (as string) + pub amount: String, + /// Address + pub address: String, + /// BIP32 derivation path + pub path: String, + /// Script type + pub script_type: TrezorScriptType, +} + +impl From for TrezorPrecomposedInput { + fn from(i: trezor_connect_rs::api::compose::PrecomposedInput) -> Self { + Self { + txid: i.txid, + vout: i.vout, + amount: i.amount, + address: i.address, + path: i.path, + script_type: i.script_type.into(), + } + } +} + +/// Output in a precomposed result. +#[derive(Debug, Clone, uniffi::Enum)] +pub enum TrezorPrecomposedOutput { + /// Payment to an address + Payment { address: String, amount: String }, + /// Change output + Change { address: String, path: String, amount: String, script_type: TrezorScriptType }, + /// OP_RETURN data output + OpReturn { data_hex: String }, +} + +impl From for TrezorPrecomposedOutput { + fn from(o: trezor_connect_rs::api::compose::PrecomposedOutput) -> Self { + match o { + trezor_connect_rs::api::compose::PrecomposedOutput::Payment { address, amount } => { + TrezorPrecomposedOutput::Payment { address, amount } + } + trezor_connect_rs::api::compose::PrecomposedOutput::Change { address, path, amount, script_type } => { + TrezorPrecomposedOutput::Change { + address, + path, + amount, + script_type: script_type.into(), + } + } + trezor_connect_rs::api::compose::PrecomposedOutput::OpReturn { data_hex } => { + TrezorPrecomposedOutput::OpReturn { data_hex } + } + } + } +} + +/// Precomposed transaction result (one per fee level). +#[derive(Debug, Clone, uniffi::Enum)] +pub enum TrezorPrecomposedResult { + /// Successfully composed a sendable transaction + Final { + total_spent: String, + fee: String, + fee_per_byte: String, + bytes: u32, + inputs: Vec, + outputs: Vec, + outputs_permutation: Vec, + }, + /// Non-final result (e.g., send-max estimation) + NonFinal { + max: Option, + total_spent: String, + fee: String, + fee_per_byte: String, + bytes: u32, + }, + /// Composition failed + Error { + error: String, + }, +} + +impl From for TrezorPrecomposedResult { + fn from(r: trezor_connect_rs::api::compose::PrecomposedResult) -> Self { + match r { + trezor_connect_rs::api::compose::PrecomposedResult::Final { + total_spent, fee, fee_per_byte, bytes, inputs, outputs, outputs_permutation, + } => TrezorPrecomposedResult::Final { + total_spent, + fee, + fee_per_byte, + bytes: bytes as u32, + inputs: inputs.into_iter().map(|i| i.into()).collect(), + outputs: outputs.into_iter().map(|o| o.into()).collect(), + outputs_permutation: outputs_permutation.into_iter().map(|i| i as u32).collect(), + }, + trezor_connect_rs::api::compose::PrecomposedResult::NonFinal { + max, total_spent, fee, fee_per_byte, bytes, + } => TrezorPrecomposedResult::NonFinal { + max, + total_spent, + fee, + fee_per_byte, + bytes: bytes as u32, + }, + trezor_connect_rs::api::compose::PrecomposedResult::Error { error } => { + TrezorPrecomposedResult::Error { error } + } + } + } +} \ No newline at end of file