diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..dfde875d24 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..5c30ace034 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "monero-native/monero_c"] + path = monero-native/monero_c + url = https://github.com/MrCyjaneK/monero_c.git + branch = rust-develop diff --git a/Cargo.lock b/Cargo.lock index 8b2d28168d..d12f878afd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,9 +225,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arbitrary" @@ -292,7 +292,7 @@ dependencies = [ "rand 0.8.5", "safelog", "serde", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-chanmgr", @@ -376,7 +376,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "synstructure 0.13.1", ] @@ -399,7 +399,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", @@ -560,7 +560,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -589,13 +589,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -641,9 +641,9 @@ dependencies = [ [[package]] name = "atk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", "glib", @@ -652,9 +652,9 @@ dependencies = [ [[package]] name = "atk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ "glib-sys", "gobject-sys", @@ -887,20 +887,40 @@ dependencies = [ "virtue", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.95", +] + [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcoin" @@ -1003,7 +1023,7 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -1092,7 +1112,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -1154,9 +1174,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -1199,9 +1219,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -1296,16 +1316,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.18.1" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.9", ] [[package]] @@ -1329,9 +1349,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.2" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "jobserver", "libc", @@ -1344,6 +1364,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfb" version = "0.7.3" @@ -1403,9 +1432,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1427,6 +1456,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.6", +] + [[package]] name = "clap" version = "2.34.0" @@ -1444,18 +1484,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -1465,9 +1505,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clipboard-win" @@ -1480,9 +1520,9 @@ dependencies = [ [[package]] name = "coarsetime" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b3839cf01bb7960114be3ccf2340f541b6d0c81f8690b007b2b39f750f7e5d" +checksum = "4252bf230cb600c19826a575b31c8c9c84c6f11acfab6dfcad2e941b10b6f8e2" dependencies = [ "libc", "wasix", @@ -1527,12 +1567,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1595,15 +1635,15 @@ checksum = "e763eef8846b13b380f37dfecda401770b0ca4e56e95170237bd7c25c7db3582" [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width 0.1.14", - "windows-sys 0.52.0", + "once_cell", + "unicode-width 0.2.0", + "windows-sys 0.59.0", ] [[package]] @@ -1764,18 +1804,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1792,18 +1832,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -1880,7 +1920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -1890,7 +1930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -1939,7 +1979,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2025,7 +2065,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2058,7 +2098,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2161,7 +2201,7 @@ dependencies = [ "quote", "sha3", "strum", - "syn 2.0.90", + "syn 2.0.95", "void", ] @@ -2173,7 +2213,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2217,7 +2257,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2238,7 +2278,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "unicode-xid", ] @@ -2341,7 +2381,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2364,7 +2404,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2373,6 +2413,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "downcast-rs" version = "1.2.1" @@ -2570,9 +2616,9 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" @@ -2598,7 +2644,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2611,7 +2657,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2632,7 +2678,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2719,15 +2765,15 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] @@ -2830,9 +2876,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -2852,7 +2898,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -2870,6 +2916,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fs-mistrust" version = "0.8.2" @@ -2882,7 +2934,7 @@ dependencies = [ "once_cell", "pwd-grp", "serde", - "thiserror 2.0.4", + "thiserror 2.0.9", "walkdir", ] @@ -2923,7 +2975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f261f25f1e94963fe8f72863f4da841b280fa3b5a573990b425a26b585a54578" dependencies = [ "fslock-arti-fork", - "thiserror 2.0.4", + "thiserror 2.0.9", "winapi", ] @@ -3034,7 +3086,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -3054,7 +3106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", ] @@ -3116,9 +3168,9 @@ dependencies = [ [[package]] name = "gdk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -3157,9 +3209,9 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -3174,9 +3226,9 @@ dependencies = [ [[package]] name = "gdkwayland-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", "glib-sys", @@ -3188,9 +3240,9 @@ dependencies = [ [[package]] name = "gdkx11" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" dependencies = [ "gdk", "gdkx11-sys", @@ -3202,9 +3254,9 @@ dependencies = [ [[package]] name = "gdkx11-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ "gdk-sys", "glib-sys", @@ -3360,7 +3412,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -3375,9 +3427,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "glob-match" @@ -3434,9 +3486,9 @@ dependencies = [ [[package]] name = "gtk" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" dependencies = [ "atk", "cairo-rs", @@ -3455,9 +3507,9 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -3473,15 +3525,15 @@ dependencies = [ [[package]] name = "gtk3-macros" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -3514,7 +3566,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http 1.2.0", "indexmap 2.7.0", "slab", "tokio", @@ -3544,7 +3596,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", - "allocator-api2", ] [[package]] @@ -3567,6 +3618,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -3645,9 +3705,9 @@ checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" [[package]] name = "hickory-proto" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" dependencies = [ "async-trait", "cfg-if", @@ -3656,7 +3716,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.4.0", + "idna", "ipnet", "once_cell", "rand 0.8.5", @@ -3670,9 +3730,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ "cfg-if", "futures-util", @@ -3709,11 +3769,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3760,9 +3820,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -3787,7 +3847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -3798,7 +3858,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -3839,9 +3899,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -3863,15 +3923,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -3884,18 +3944,18 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.5.1", + "http 1.2.0", + "hyper 1.5.2", "hyper-util", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tower-service", "webpki-roots 0.26.7", ] @@ -3909,9 +3969,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.1", + "hyper 1.5.2", "pin-project-lite", "socket2", "tokio", @@ -4067,7 +4127,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -4076,16 +4136,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.0.3" @@ -4151,7 +4201,7 @@ dependencies = [ "bytes", "futures", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "log", "rand 0.8.5", "tokio", @@ -4243,9 +4293,12 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" +checksum = "e5d80fade88dd420ce0d9ab6f7c58ef2272dde38db874657950f827d4982c817" +dependencies = [ + "rustversion", +] [[package]] name = "ipconfig" @@ -4382,9 +4435,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -4493,7 +4546,7 @@ dependencies = [ "futures-timer", "futures-util", "globset", - "hyper 0.14.31", + "hyper 0.14.32", "jsonrpsee-types", "parking_lot 0.12.3", "rand 0.8.5", @@ -4515,7 +4568,7 @@ dependencies = [ "futures-channel", "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "jsonrpsee-core", "jsonrpsee-types", "serde", @@ -4524,7 +4577,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tower", + "tower 0.4.13", "tracing", ] @@ -4656,15 +4709,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] [[package]] name = "libc" -version = "0.2.167" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libgit2-sys" @@ -4688,6 +4741,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libm" version = "0.2.11" @@ -5025,7 +5088,7 @@ dependencies = [ "quinn", "rand 0.8.5", "ring 0.17.8", - "rustls 0.23.19", + "rustls 0.23.20", "socket2", "thiserror 1.0.69", "tokio", @@ -5112,7 +5175,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -5163,7 +5226,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.17.8", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-webpki 0.101.7", "thiserror 1.0.69", "x509-parser 0.16.0", @@ -5209,7 +5272,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", ] [[package]] @@ -5417,15 +5480,15 @@ dependencies = [ [[package]] name = "minisign-verify" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a05b5d0594e0cb1ad8cee3373018d2b84e25905dc75b2468114cc9a8e86cfc20" +checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", "simd-adler32", @@ -5443,6 +5506,32 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "mockito" version = "1.6.1" @@ -5453,10 +5542,10 @@ dependencies = [ "bytes", "colored", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "log", "rand 0.8.5", @@ -5507,6 +5596,19 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "monero-native" +version = "0.0.1" +dependencies = [ + "bindgen", + "mockall", + "monero", + "rust_decimal", + "serde", + "tempfile", + "thiserror 2.0.9", +] + [[package]] name = "monero-rpc" version = "0.1.0" @@ -5594,9 +5696,9 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", "serde", @@ -5701,9 +5803,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ "bytes", "futures", @@ -5784,9 +5886,9 @@ dependencies = [ [[package]] name = "notify-types" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7393c226621f817964ffb3dc5704f9509e107a8b024b489cc2c1b217378785df" +checksum = "585d3cb5e12e01aed9e8a1f70d5c6b5e86fe2a6e48fc8cd0b3e0b8df6f6eb174" dependencies = [ "instant", ] @@ -5901,7 +6003,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -6142,9 +6244,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -6190,10 +6292,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open" -version = "5.3.1" +version = "5.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" +checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" dependencies = [ + "dunce", "is-wsl", "libc", "pathdiff", @@ -6367,7 +6470,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "smallvec", "windows-targets 0.52.6", ] @@ -6411,20 +6514,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror 2.0.9", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" dependencies = [ "pest", "pest_generator", @@ -6432,22 +6535,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "pest_meta" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" dependencies = [ "once_cell", "pest", @@ -6476,12 +6579,12 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", + "phf_macros 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -6526,11 +6629,11 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared 0.11.2", + "phf_shared 0.11.3", "rand 0.8.5", ] @@ -6550,15 +6653,15 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -6567,7 +6670,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -6576,43 +6679,43 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", + "siphasher 1.0.1", ] [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -6673,9 +6776,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.14" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -6758,6 +6861,42 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483f8c21f64f3ea09fe0f30f5d48c3e8eefe5dac9129f0075f76593b4c1da705" +dependencies = [ + "proc-macro2", + "syn 2.0.95", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -6875,14 +7014,14 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "proptest" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", @@ -7001,9 +7140,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.0", - "rustls 0.23.19", + "rustls 0.23.20", "socket2", - "thiserror 2.0.4", + "thiserror 2.0.9", "tokio", "tracing", ] @@ -7019,10 +7158,10 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.1.0", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "slab", - "thiserror 2.0.4", + "thiserror 2.0.9", "tinyvec", "tracing", "web-time", @@ -7030,9 +7169,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ "cfg_aliases", "libc", @@ -7044,9 +7183,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -7205,9 +7344,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -7278,19 +7417,19 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-rustls", "hyper-util", "ipnet", @@ -7301,7 +7440,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -7309,9 +7448,10 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tokio-socks", "tokio-util", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -7455,7 +7595,7 @@ dependencies = [ "bitflags 2.6.0", "fallible-iterator", "fallible-streaming-iterator", - "hashlink", + "hashlink 0.9.1", "libsqlite3-sys", "smallvec", "time 0.3.37", @@ -7531,15 +7671,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7581,9 +7721,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "log", "once_cell", @@ -7638,9 +7778,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" dependencies = [ "web-time", ] @@ -7668,9 +7808,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "rusty-fork" @@ -7711,7 +7851,7 @@ dependencies = [ "educe", "either", "fluid-let", - "thiserror 2.0.4", + "thiserror 2.0.9", ] [[package]] @@ -7734,9 +7874,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.2.5" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" +checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640" dependencies = [ "sdd", ] @@ -7774,7 +7914,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -7805,9 +7945,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49c1eeaf4b6a87c7479688c6d52b9f1153cedd3c489300564f932b065c6eab95" +checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" [[package]] name = "seahash" @@ -7929,9 +8069,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ "core-foundation-sys", "libc", @@ -7959,18 +8099,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -8026,13 +8166,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8043,7 +8183,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8057,9 +8197,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa 1.0.14", "memchr", @@ -8075,7 +8215,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8111,9 +8251,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", @@ -8123,7 +8263,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.11.0", + "serde_with_macros 3.12.0", "time 0.3.37", ] @@ -8141,14 +8281,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8173,7 +8313,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8371,6 +8511,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -8415,7 +8561,7 @@ dependencies = [ "paste", "serde", "slotmap", - "thiserror 2.0.4", + "thiserror 2.0.9", "void", ] @@ -8471,7 +8617,7 @@ dependencies = [ "objc2-foundation", "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "wasm-bindgen", "web-sys", "windows-sys 0.59.0", @@ -8544,21 +8690,11 @@ dependencies = [ "der", ] -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - [[package]] name = "sqlx" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" +checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" dependencies = [ "sqlx-core", "sqlx-macros", @@ -8569,39 +8705,33 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" +checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" dependencies = [ - "atoi", - "byteorder", "bytes", "crc", "crossbeam-queue", "either", "event-listener 5.3.1", - "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.14.5", - "hashlink", - "hex", + "hashbrown 0.15.2", + "hashlink 0.10.0", "indexmap 2.7.0", "log", "memchr", "once_cell", - "paste", "percent-encoding", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pemfile 2.2.0", "serde", "serde_json", "sha2 0.10.8", "smallvec", - "sqlformat", - "thiserror 1.0.69", + "thiserror 2.0.9", "tokio", "tokio-stream", "tracing", @@ -8611,22 +8741,22 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" +checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "sqlx-macros-core" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" +checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" dependencies = [ "dotenvy", "either", @@ -8642,7 +8772,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.90", + "syn 2.0.95", "tempfile", "tokio", "url", @@ -8650,9 +8780,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" +checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" dependencies = [ "atoi", "base64 0.22.1", @@ -8685,16 +8815,16 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror 2.0.9", "tracing", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" +checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" dependencies = [ "atoi", "base64 0.22.1", @@ -8705,7 +8835,6 @@ dependencies = [ "etcetera", "futures-channel", "futures-core", - "futures-io", "futures-util", "hex", "hkdf", @@ -8723,16 +8852,16 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror 2.0.9", "tracing", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" +checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" dependencies = [ "atoi", "flume", @@ -8902,7 +9031,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -8953,6 +9082,7 @@ dependencies = [ "mockito", "monero", "monero-harness", + "monero-native", "monero-rpc", "once_cell", "pem", @@ -8985,7 +9115,7 @@ dependencies = [ "tokio-util", "toml 0.8.19", "tor-rtcompat", - "tower", + "tower 0.4.13", "tower-http", "tracing", "tracing-appender", @@ -9023,9 +9153,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -9061,7 +9191,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -9114,9 +9244,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.30.8" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6682a07cf5bab0b8a2bd20d0a542917ab928b5edb75ebd4eda6b05cbaab872da" +checksum = "3731d04d4ac210cd5f344087733943b9bfb1a32654387dad4d1c70de21aee2c9" dependencies = [ "bitflags 2.6.0", "cocoa", @@ -9129,7 +9259,6 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "instant", "jni", "lazy_static", "libc", @@ -9159,7 +9288,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -9187,9 +9316,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e545de0a2dfe296fa67db208266cd397c5a55ae782da77973ef4c4fac90e9f2c" +checksum = "2e2e3349fbb2be7af9fad1b43d61ac83ba55ab48d47fbe1b2732f0c8211610a9" dependencies = [ "anyhow", "bytes", @@ -9201,7 +9330,7 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http 1.1.0", + "http 1.2.0", "jni", "libc", "log", @@ -9224,7 +9353,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.4", + "thiserror 2.0.9", "tokio", "tray-icon", "url", @@ -9237,9 +9366,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd2a4bcfaf5fb9f4be72520eefcb61ae565038f8ccba2a497d8c28f463b8c01" +checksum = "b274ec7239ada504deb615f1c8abd7ba99631e879709e6f10e5d17217058d976" dependencies = [ "anyhow", "cargo_toml", @@ -9259,9 +9388,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf79faeecf301d3e969b1fae977039edb77a4c1f25cc0a961be298b54bff97cf" +checksum = "f77894f9ddb5cb6c04fcfe8c8869ebe0aded4dabf19917118d48be4a95599ab5" dependencies = [ "base64 0.22.1", "brotli 7.0.0", @@ -9275,9 +9404,9 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "syn 2.0.90", + "syn 2.0.95", "tauri-utils", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "url", "uuid", @@ -9286,23 +9415,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c52027c8c5afb83166dacddc092ee8fff50772f9646d461d8c33ee887e447a03" +checksum = "3240a5caed760a532e8f687be6f05b2c7d11a1d791fb53ccc08cfeb3e5308736" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e753f2a30933a9bbf0a202fa47d7cc4a3401f06e8d6dcc53b79aa62954828c79" +checksum = "5841b9a0200e954ef7457f8d327091424328891e267a97b641dc246cc54d0dec" dependencies = [ "anyhow", "glob", @@ -9317,24 +9446,24 @@ dependencies = [ [[package]] name = "tauri-plugin-cli" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bccd4692b56822a60874542c7655546c8e7aed3c2e2926166e1498e595bd2a2" +checksum = "e5458ae16eac81bdbe8d9da2a9f3e01e8cdedbc381cc1727c01127542c8a61c5" dependencies = [ - "clap 4.5.21", + "clap 4.5.23", "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.69", + "thiserror 2.0.9", ] [[package]] name = "tauri-plugin-clipboard-manager" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a66feaa0fb7fce8e5073323d11ca381c9da7ac06f458e42b9ff77364b76a360" +checksum = "5be2c6f5d82396c1a86d5b16052cc97976a82e92244bf074dd6e2f6272d8619d" dependencies = [ "arboard", "log", @@ -9342,14 +9471,14 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.69", + "thiserror 2.0.9", ] [[package]] name = "tauri-plugin-process" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae06a00087c148962a52814a2d7265b1a0505bced5ffb74f8c284a5f96a4d03d" +checksum = "40cc553ab29581c8c43dfa5fb0c9d5aee8ba962ad3b42908eea26c79610441b7" dependencies = [ "tauri", "tauri-plugin", @@ -9357,9 +9486,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad7880c5586b6b2104be451e3d7fc0f3800c84bda69e9ba81c828f87cb34267" +checksum = "bb2c50a63e60fb8925956cc5b7569f4b750ac197a4d39f13b8dd46ea8e2bad79" dependencies = [ "encoding_rs", "log", @@ -9372,20 +9501,20 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 1.0.69", + "thiserror 2.0.9", "tokio", ] [[package]] name = "tauri-plugin-single-instance" -version = "2.0.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494d348f82cfa766df4d2ebd96fc38b9cada6d120f13a36fd11395180213ec74" +checksum = "0f36019ee9832dc99e4450bb55a21cfad8633b19c2c18bd17c7741939b070ede" dependencies = [ "serde", "serde_json", "tauri", - "thiserror 2.0.4", + "thiserror 2.0.9", "tracing", "windows-sys 0.59.0", "zbus", @@ -9393,31 +9522,31 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a580be53f04bb62422d239aa798e88522877f58a0d4a0e745f030055a51bb4" +checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505" dependencies = [ "dunce", - "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 1.0.69", + "thiserror 2.0.9", "tokio", + "tracing", ] [[package]] name = "tauri-plugin-updater" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ba9adaede60b0df5e0764692c6ac176eb133aade95d326bddeb968ad793320" +checksum = "ce2d39224390c41ba544f02b4f1721f42256320b3fb8c371e9425cbddeb4a68c" dependencies = [ "base64 0.22.1", "dirs", "flate2", "futures-util", - "http 1.1.0", + "http 1.2.0", "infer", "minisign-verify", "percent-encoding", @@ -9429,41 +9558,41 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "tokio", "url", "windows-sys 0.59.0", - "zip 2.2.1", + "zip 2.2.2", ] [[package]] name = "tauri-runtime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce18d43f80d4aba3aa8a0c953bbe835f3d0f2370aca75e8dbb14bd4bab27958" +checksum = "2274ef891ccc0a8d318deffa9d70053f947664d12d58b9c0d1ae5e89237e01f7" dependencies = [ "dpi", "gtk", - "http 1.1.0", + "http 1.2.0", "jni", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror 2.0.4", + "thiserror 2.0.9", "url", "windows 0.58.0", ] [[package]] name = "tauri-runtime-wry" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f442a38863e10129ffe2cec7bd09c2dcf8a098a3a27801a476a304d5bb991d2" +checksum = "3707b40711d3b9f6519150869e358ffbde7c57567fb9b5a8b51150606939b2a0" dependencies = [ "gtk", - "http 1.1.0", + "http 1.2.0", "jni", "log", "objc2", @@ -9484,9 +9613,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9271a88f99b4adea0dc71d0baca4505475a0bbd139fb135f62958721aaa8fe54" +checksum = "96fb10e7cc97456b2d5b9c03e335b5de5da982039a303a20d10006885e4523a0" dependencies = [ "brotli 7.0.0", "cargo_metadata", @@ -9494,14 +9623,14 @@ dependencies = [ "dunce", "glob", "html5ever", - "http 1.1.0", + "http 1.2.0", "infer", "json-patch", "json5", "kuchikiki", "log", "memchr", - "phf 0.11.2", + "phf 0.11.3", "proc-macro2", "quote", "regex", @@ -9510,9 +9639,9 @@ dependencies = [ "serde", "serde-untagged", "serde_json", - "serde_with 3.11.0", + "serde_with 3.12.0", "swift-rs", - "thiserror 2.0.4", + "thiserror 2.0.9", "toml 0.8.19", "url", "urlpattern", @@ -9532,12 +9661,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", @@ -9554,6 +9684,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + [[package]] name = "testcontainers" version = "0.15.0" @@ -9597,11 +9733,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "thiserror-impl 2.0.4", + "thiserror-impl 2.0.9", ] [[package]] @@ -9612,18 +9748,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -9721,9 +9857,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -9760,7 +9896,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -9786,12 +9922,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.19", - "rustls-pki-types", + "rustls 0.23.20", "tokio", ] @@ -9809,9 +9944,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -9852,9 +9987,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -9931,7 +10066,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow 0.6.22", ] [[package]] @@ -9946,7 +10081,7 @@ dependencies = [ "oneshot-fused-workaround", "pin-project", "postage", - "thiserror 2.0.4", + "thiserror 2.0.9", "void", ] @@ -9966,7 +10101,7 @@ dependencies = [ "serde", "slab", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.9", ] [[package]] @@ -9981,7 +10116,7 @@ dependencies = [ "educe", "getrandom 0.2.15", "safelog", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-error", "tor-llcrypto", "zeroize", @@ -10003,7 +10138,7 @@ dependencies = [ "paste", "rand 0.8.5", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-basic-utils", "tor-bytes", "tor-cert", @@ -10026,7 +10161,7 @@ dependencies = [ "derive_builder_fork_arti", "derive_more 1.0.0", "digest 0.10.7", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-bytes", "tor-checkable", "tor-llcrypto", @@ -10048,7 +10183,7 @@ dependencies = [ "rand 0.8.5", "safelog", "serde", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -10074,7 +10209,7 @@ checksum = "614009c7733b955630686aa15d072024a6e82a6c3101749b7c30cd37af79a8de" dependencies = [ "humantime", "signature 2.2.0", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-llcrypto", ] @@ -10104,7 +10239,7 @@ dependencies = [ "safelog", "serde", "static_assertions", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-chanmgr", @@ -10150,7 +10285,7 @@ dependencies = [ "serde-value", "serde_ignored", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "toml 0.8.19", "tor-basic-utils", "tor-error", @@ -10169,7 +10304,7 @@ dependencies = [ "once_cell", "serde", "shellexpand", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-error", "tor-general-addr", ] @@ -10182,7 +10317,7 @@ checksum = "1e9ce0f35f46f4edcb2495ec71d4607c291bc9b9da0386e0a3cc9ab64bbe41f1" dependencies = [ "digest 0.10.7", "hex", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-llcrypto", ] @@ -10197,12 +10332,12 @@ dependencies = [ "derive_more 1.0.0", "futures", "hex", - "http 1.1.0", + "http 1.2.0", "httparse", "httpdate", "itertools", "memchr", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-circmgr", "tor-error", "tor-hscrypto", @@ -10246,7 +10381,7 @@ dependencies = [ "serde", "signature 2.2.0", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "tor-async-utils", "tor-basic-utils", @@ -10279,7 +10414,7 @@ dependencies = [ "retry-error", "static_assertions", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tracing", "void", ] @@ -10291,7 +10426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60b135845a8c4546cdb4da673123e5ae3daf4597d9857fd7d720350efac173c" dependencies = [ "derive_more 1.0.0", - "thiserror 2.0.4", + "thiserror 2.0.9", "void", ] @@ -10320,7 +10455,7 @@ dependencies = [ "safelog", "serde", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -10357,7 +10492,7 @@ dependencies = [ "safelog", "slotmap-careful", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -10397,7 +10532,7 @@ dependencies = [ "safelog", "signature 2.2.0", "subtle", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-basic-utils", "tor-bytes", "tor-error", @@ -10438,9 +10573,9 @@ dependencies = [ "retry-error", "safelog", "serde", - "serde_with 3.11.0", + "serde_with 3.12.0", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -10479,7 +10614,7 @@ dependencies = [ "rand 0.8.5", "signature 2.2.0", "ssh-key", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-error", "tor-hscrypto", "tor-llcrypto", @@ -10508,7 +10643,7 @@ dependencies = [ "serde", "signature 2.2.0", "ssh-key", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-basic-utils", "tor-config", "tor-config-path", @@ -10538,9 +10673,9 @@ dependencies = [ "itertools", "safelog", "serde", - "serde_with 3.11.0", + "serde_with 3.12.0", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-basic-utils", "tor-bytes", "tor-config", @@ -10576,7 +10711,7 @@ dependencies = [ "sha3", "signature 2.2.0", "subtle", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-memquota", "visibility", "x25519-dalek", @@ -10592,7 +10727,7 @@ dependencies = [ "futures", "humantime", "once_cell", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-error", "tor-rtcompat", "tracing", @@ -10616,7 +10751,7 @@ dependencies = [ "serde", "slotmap-careful", "static_assertions", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -10646,7 +10781,7 @@ dependencies = [ "serde", "static_assertions", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "tor-basic-utils", "tor-error", @@ -10678,14 +10813,14 @@ dependencies = [ "humantime", "itertools", "once_cell", - "phf 0.11.2", + "phf 0.11.3", "rand 0.8.5", "serde", - "serde_with 3.11.0", + "serde_with 3.12.0", "signature 2.2.0", "smallvec", "subtle", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "tinystr 0.8.0", "tor-basic-utils", @@ -10724,7 +10859,7 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.9", "time 0.3.37", "tor-async-utils", "tor-basic-utils", @@ -10758,7 +10893,7 @@ dependencies = [ "rand_core 0.6.4", "safelog", "subtle", - "thiserror 2.0.4", + "thiserror 2.0.9", "tokio", "tokio-util", "tor-async-utils", @@ -10791,7 +10926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a95780782ff7c5a7c942da6a375d1150acfab445d8f3b840e4244a8267d9a3d" dependencies = [ "caret", - "thiserror 2.0.4", + "thiserror 2.0.9", ] [[package]] @@ -10825,7 +10960,7 @@ dependencies = [ "paste", "pin-project", "rustls-pki-types", - "thiserror 2.0.4", + "thiserror 2.0.9", "tokio", "tokio-util", "tor-error", @@ -10854,7 +10989,7 @@ dependencies = [ "priority-queue", "slotmap-careful", "strum", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-error", "tor-general-addr", "tor-rtcompat", @@ -10875,7 +11010,7 @@ dependencies = [ "educe", "safelog", "subtle", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-bytes", "tor-error", ] @@ -10888,7 +11023,7 @@ checksum = "6bdeb3e823e4d194227eab21dff65c738c6ce1755a41395538e4e48e04f37c7f" dependencies = [ "derive-deftly", "derive_more 1.0.0", - "thiserror 2.0.4", + "thiserror 2.0.9", "tor-memquota", ] @@ -10913,6 +11048,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.3.5" @@ -10936,7 +11086,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -10987,7 +11137,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11062,7 +11212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11151,7 +11301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11241,15 +11391,15 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" @@ -11296,12 +11446,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "universal-hash" version = "0.5.1" @@ -11373,7 +11517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", "serde", ] @@ -11481,7 +11625,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11573,9 +11717,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -11584,24 +11728,23 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.47" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", @@ -11612,9 +11755,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11622,22 +11765,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-streams" @@ -11660,9 +11803,9 @@ checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" [[package]] name = "web-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -11777,9 +11920,9 @@ dependencies = [ [[package]] name = "webview2-com" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" +checksum = "823e7ebcfaea51e78f72c87fc3b65a1e602c321f407a0b36dbb327d7bb7cd921" dependencies = [ "webview2-com-macros", "webview2-com-sys", @@ -11797,14 +11940,14 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] name = "webview2-com-sys" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" +checksum = "7a82bce72db6e5ee83c68b5de1e2cd6ea195b9fbff91cb37df5884cbe3222df4" dependencies = [ "thiserror 1.0.69", "windows 0.58.0", @@ -11823,7 +11966,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "wasite", ] @@ -11960,7 +12103,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11971,7 +12114,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11982,7 +12125,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -11993,7 +12136,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -12269,9 +12412,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -12310,9 +12453,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wry" -version = "0.47.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ce51277d65170f6379d8cda935c80e3c2d1f0ff712a123c8bddb11b31a4b73" +checksum = "1e644bf458e27b11b0ecafc9e5633d1304fdae82baca1d42185669752fe6ca4f" dependencies = [ "base64 0.22.1", "block2", @@ -12323,7 +12466,7 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http 1.1.0", + "http 1.2.0", "javascriptcore-rs", "jni", "kuchikiki", @@ -12340,7 +12483,7 @@ dependencies = [ "sha2 0.10.8", "soup3", "tao-macros", - "thiserror 1.0.69", + "thiserror 2.0.9", "url", "webkit2gtk", "webkit2gtk-sys", @@ -12456,9 +12599,9 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" dependencies = [ "libc", "linux-raw-sys", @@ -12492,9 +12635,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "yamux" @@ -12556,7 +12699,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "synstructure 0.13.1", ] @@ -12607,7 +12750,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "zvariant_utils", ] @@ -12640,7 +12783,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -12660,7 +12803,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "synstructure 0.13.1", ] @@ -12681,7 +12824,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -12703,7 +12846,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] [[package]] @@ -12722,9 +12865,9 @@ dependencies = [ [[package]] name = "zip" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d52293fc86ea7cf13971b3bb81eb21683636e7ae24c729cdaf1b7c4157a352" +checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" dependencies = [ "arbitrary", "crc32fast", @@ -12732,7 +12875,7 @@ dependencies = [ "displaydoc", "indexmap 2.7.0", "memchr", - "thiserror 2.0.4", + "thiserror 2.0.9", ] [[package]] @@ -12757,7 +12900,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", "zvariant_utils", ] @@ -12769,5 +12912,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.95", ] diff --git a/Cargo.toml b/Cargo.toml index d46abd08d7..ea9f09488b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "monero-harness", "monero-rpc", "swap", "monero-wallet", "src-tauri" ] +members = [ "monero-harness", "monero-rpc", "monero-native", "swap", "monero-wallet", "src-tauri" ] [patch.crates-io] # patch until new release https://github.com/thomaseizinger/rust-jsonrpc-client/pull/51 diff --git a/monero-native/.gitignore b/monero-native/.gitignore new file mode 100644 index 0000000000..2f7896d1d1 --- /dev/null +++ b/monero-native/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/monero-native/Cargo.lock b/monero-native/Cargo.lock new file mode 100644 index 0000000000..9991a4507d --- /dev/null +++ b/monero-native/Cargo.lock @@ -0,0 +1,436 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mockall" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "monero_c_rust" +version = "0.0.1" +dependencies = [ + "bindgen", + "mockall", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "predicates" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" + +[[package]] +name = "predicates-tree" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/monero-native/Cargo.toml b/monero-native/Cargo.toml new file mode 100644 index 0000000000..61d61a1b9c --- /dev/null +++ b/monero-native/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "monero-native" +version = "0.0.1" +edition = "2021" +description = "monero_c Rust bindings." +repository = "https://github.com/MrCyjaneK/monero_c" +license = "MIT" +build = "build.rs" + +[lib] +name = "monero_c_rust" +path = "src/lib.rs" +crate-type = ["lib", "cdylib"] + +[dependencies] +mockall = "0.13.0" +rust_decimal = "1.36.0" +serde = "1.0.217" +tempfile = "3.13.0" +thiserror = "2.0.9" +monero = { version = "0.12", features = [ "serde_support" ] } + +[build-dependencies] +bindgen = "0.70.1" + diff --git a/monero-native/README.md b/monero-native/README.md new file mode 100644 index 0000000000..cd4f72ed03 --- /dev/null +++ b/monero-native/README.md @@ -0,0 +1,47 @@ +# `monero_rust` +Proof of concept `monero_c` bindings for Rust. + +## Getting started + +### Build the `monero_c` library + +#### Pull the `monero_c` library sub-module +```bash +# Execute this from the monero-native directory +git submodule update --init --recursive +``` + +#### Build the `monero_c` library +```bash +cd monero_c # Navigate to the monero_c directory + +# Update the submodule for the monero source code +git submodule update --init --recursive --force + +# Apply patches to the monero_c library +for coin in monero wownero zano; do ./apply_patches.sh $coin; done + +# Build the monero_c library for the current architecture +./build_single.sh monero aarch64-apple-darwin -j14 # Adjust the architecture as needed +``` + +#### Run the extraction script +```bash +cd .. # Navigate back to the monero-native directory +./scripts/extract_from_build_from_source.sh +``` + +### Run demo +With the library in a supported location: +``` +cargo run --example basic +``` + +## Using `monero_rust` in your own crate +Refer to the `example` folder. Library placement is the same as for the demo. \ No newline at end of file diff --git a/monero-native/build.rs b/monero-native/build.rs new file mode 100644 index 0000000000..0a2d53daf2 --- /dev/null +++ b/monero-native/build.rs @@ -0,0 +1,145 @@ +use bindgen::EnumVariation; +use std::env; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::path::PathBuf; + +#[cfg(unix)] +use std::os::unix::fs as unix_fs; + +#[cfg(target_os = "windows")] +use std::fs::copy; + +fn main() { + let header_path = "./monero_c/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h"; + let lib_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("./libs"); + + // Set library names based on target OS. + // + // This rigamarole is currently required because the "monero_libwallet2_api_c" library is also + // required under the names "wallet2_api_c" and "libmonero_libwallet2_api_c" by various parts of + // the stack. This is a temporary workaround until the library is refactored to use a single + // name consistently. + let original_lib = if cfg!(target_os = "windows") { + lib_path.join("libwallet2_api_c.dll") + } else if cfg!(target_os = "macos") { + lib_path.join("libwallet2_api_c.dylib") + } else { + lib_path.join("libwallet2_api_c.so") + }; + + let symlink_1 = if cfg!(target_os = "windows") { + lib_path.join("wallet2_api_c.dll") + } else if cfg!(target_os = "macos") { + lib_path.join("libwallet2_api_c.dylib") + } else { + lib_path.join("libwallet2_api_c.so") + }; + + let symlink_2 = if cfg!(target_os = "windows") { + lib_path.join("monero_wallet2_api_c.dll") + } else if cfg!(target_os = "macos") { + lib_path.join("libmonero_libwallet2_api_c.dylib") + } else { + lib_path.join("libmonero_libwallet2_api_c.so") + }; + + // On Unix-like systems, create symlinks. + #[cfg(unix)] + { + if original_lib.exists() && !symlink_1.exists() { + unix_fs::symlink(&original_lib, &symlink_1) + .expect("Failed to create symbolic link for libwallet2_api_c.so"); + } + + if original_lib.exists() && !symlink_2.exists() { + unix_fs::symlink(&original_lib, &symlink_2) + .expect("Failed to create symbolic link for libmonero_libwallet2_api_c.so"); + } + } + + // On Windows, copy the files instead of symlinking. + #[cfg(target_os = "windows")] + { + if original_lib.exists() && !symlink_1.exists() { + copy(&original_lib, &symlink_1).expect("Failed to copy DLL file to wallet2_api_c.dll"); + } + + if original_lib.exists() && !symlink_2.exists() { + copy(&original_lib, &symlink_2) + .expect("Failed to copy DLL file to monero_wallet2_api_c.dll"); + } + } + + println!("cargo:rerun-if-changed={}", header_path); + println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo:rustc-link-search=native={}", lib_path.display()); + println!("cargo:rustc-link-lib=dylib=monero_libwallet2_api_c"); + + // Use c++ instead of stdc++ on macOS + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-lib=c++"); + } else { + println!("cargo:rustc-link-lib=dylib=stdc++"); + } + + println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_path.display()); + + // Generate bindings using bindgen. + let bindings = bindgen::Builder::default() + .header(header_path) + .allowlist_function("MONERO_.*") + .allowlist_var("MONERO_.*") + .allowlist_var("NetworkType_.*") + .allowlist_var("PendingTransactionStatus_.*") + .allowlist_var("Priority_.*") + .allowlist_var("UnsignedTransactionStatus_.*") + .allowlist_var("TransactionInfoDirection_.*") + .allowlist_var("AddressBookErrorCode.*") + .allowlist_var("WalletDevice_.*") + .allowlist_var("WalletStatus_.*") + .allowlist_var("WalletConnectionStatus_.*") + .allowlist_var("WalletBackgroundSync_.*") + .allowlist_var("BackgroundSync_.*") + .allowlist_var("LogLevel_.*") + .blocklist_type("__.*") + .blocklist_type("_.*") + .blocklist_function("__.*") + .layout_tests(false) + .default_enum_style(EnumVariation::Rust { + non_exhaustive: false, + }) + .derive_default(false) + .conservative_inline_namespaces() + .generate_comments(false) + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("src") + .join("bindings.rs"); + bindings + .write_to_file(out_path.clone()) + .expect("Couldn't write bindings!"); + + // Annotate the generated bindings to ignore certain warnings. + if out_path.exists() { + let contents = fs::read_to_string(out_path.clone()).expect("Failed to read bindings.rs"); + + let prepend_content = "#![allow(non_upper_case_globals)]\n#![allow(dead_code)]\n"; + + if !contents.contains("#![allow(non_upper_case_globals)]") { + let new_contents = format!("{}{}", prepend_content, contents); + + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .open(out_path.clone()) + .expect("Failed to open bindings.rs"); + + file.write_all(new_contents.as_bytes()) + .expect("Failed to write to bindings.rs"); + } + } +} diff --git a/monero-native/examples/basic.rs b/monero-native/examples/basic.rs new file mode 100644 index 0000000000..8d307ab4c3 --- /dev/null +++ b/monero-native/examples/basic.rs @@ -0,0 +1,78 @@ +use monero_c_rust::{NetworklletConfig, WalletError, WalletManager}; +use tempfile::TempDir; + +fn main() -> Result<(), WalletError> { + let manager = WalletManager::new()?; + + let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path.to_str().unwrap(); + + let wallet = manager.restore_polyseed( + wallet_str.to_string(), + "password".to_string(), + "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(), + Network::Stagenet, + 0, // Restore from the beginning of the blockchain. + 1, // Default KDF rounds. + "".to_string(), // No seed offset. + true, // Create a new wallet. + )?; + + println!("Wallet created successfully."); + + // Print the primary address. + println!("Primary address: {}", wallet.get_address(0, 0)?); + + // Initialize the wallet. + let config = WalletConfig { + daemon_address: "http://localhost:38081".to_string(), + upper_transaction_size_limit: 10000, // TODO: use sane value. + daemon_username: "".to_string(), + daemon_password: "".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + }; + + // Set WalletManager's daemon address + manager.set_daemon_address(&config.daemon_address); + + // Perform the initialization. + wallet.init(config)?; + wallet.throw_if_error()?; + + let target_block = manager.get_height_target()?; + println!("Target block: {}", target_block); + + // Refresh the wallet. + wallet.refresh()?; + // wallet.refresh_async()?; + wallet.throw_if_error()?; + + // Wait for the refresh to complete. + loop { + let height = wallet + .get_blockchain_height() + .expect("Failed to get blockchain height"); + println!("Current blockchain height: {}", height); + if height > 1768865 { + // After this height we can get_balance. + break (); + } + // Wait one second. + std::thread::sleep(std::time::Duration::from_secs(1)); + } + + // Get the balance. + let balance_result = wallet.get_balance(0); // Account index 0. + let balance = balance_result.unwrap(); + println!("Balance: {:?}", balance); + + // Clean up the wallet. + std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + std::fs::remove_file(format!("{}.keys", wallet_str)) + .expect("Failed to delete test wallet keys"); + + Ok(()) +} diff --git a/monero-native/libs/libmonero_libwallet2_api_c.dylib b/monero-native/libs/libmonero_libwallet2_api_c.dylib new file mode 120000 index 0000000000..0d05c37cfc --- /dev/null +++ b/monero-native/libs/libmonero_libwallet2_api_c.dylib @@ -0,0 +1 @@ +/Users/mohan/Development/core/monero-native/./libs/libwallet2_api_c.dylib \ No newline at end of file diff --git a/monero-native/libs/libwallet2_api_c.dylib b/monero-native/libs/libwallet2_api_c.dylib new file mode 100755 index 0000000000..f87882c10f Binary files /dev/null and b/monero-native/libs/libwallet2_api_c.dylib differ diff --git a/monero-native/monero_c b/monero-native/monero_c new file mode 160000 index 0000000000..bbb28c741f --- /dev/null +++ b/monero-native/monero_c @@ -0,0 +1 @@ +Subproject commit bbb28c741f902fb585d2c13b786e029018ebfde8 diff --git a/monero-native/moneroc b/monero-native/moneroc new file mode 100644 index 0000000000..584b75fd8b --- /dev/null +++ b/monero-native/moneroc @@ -0,0 +1,3 @@ +2025-01-06 11:07:13.364 0x2027d3ac0 INFO logging contrib/epee/src/mlog.cpp:274 New log categories: *:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,daemon.rpc:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO +2025-01-06 11:08:45.477 0x2027d3ac0 INFO logging contrib/epee/src/mlog.cpp:274 New log categories: *:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,daemon.rpc:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO +2025-01-06 17:05:38.262 0x2027d3ac0 INFO logging contrib/epee/src/mlog.cpp:274 New log categories: *:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,daemon.rpc:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO diff --git a/monero-native/scripts/extract_from_build_from_source.sh b/monero-native/scripts/extract_from_build_from_source.sh new file mode 100755 index 0000000000..2c12ca8fad --- /dev/null +++ b/monero-native/scripts/extract_from_build_from_source.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# This script is used to extract the built monero_c library from the build directory of the monero_c repository +# extracts it and copies it to the monero-native directory such that it can be used by the monero-native crate. +# Execute this script from the monero-native directory + +set -x -e + +# See https://github.com/MrCyjaneK/monero_c for the most up-to-date build docs, +# this is an example and a starting point for building monero_c for use in Rust +# but it should be automated either using CMake or Cargo (preferred). + +# Detect architecture. +ARCH=$(uname -m) +OS=$(uname -s) + +# Ensure we are in the monero-native directory, fail if not. +if [ ! -d "./monero_c" ]; then + echo "Error: monero_c directory not found. Please run this script from the monero-native directory." + exit 1 +fi + +case $ARCH-$OS in + x86_64-Linux) + TARGET_ARCH="x86_64-linux-gnu" + ;; + i686-Linux) + TARGET_ARCH="i686-linux-gnu" + ;; + aarch64-Linux) + TARGET_ARCH="aarch64-linux-gnu" + ;; + x86_64-Android) + TARGET_ARCH="x86_64-linux-android" + ;; + i686-Android) + TARGET_ARCH="i686-linux-android" + ;; + aarch64-Android) + TARGET_ARCH="aarch64-linux-android" + ;; + armv7l-Android) + TARGET_ARCH="arm-linux-androideabi" + ;; + i686-Windows) + TARGET_ARCH="i686-w64-mingw32" + ;; + x86_64-Windows) + TARGET_ARCH="x86_64-w64-mingw32" + ;; + x86_64-Darwin) + TARGET_ARCH="host-apple-darwin" + ;; + arm64-Darwin) + TARGET_ARCH="aarch64-apple-darwin" + ;; + *) + echo "Unsupported architecture: $ARCH on OS: $OS" + exit 1 + ;; +esac + + +# TOOD: Use .so or .dylib depending on the architecture + +# Unzip the archive but keep it +unxz -f -k monero_c/release/monero/${TARGET_ARCH}_libwallet2_api_c.dylib.xz + +# Create target directories if they don't exist +mkdir -p "./target/debug/deps" +mkdir -p "./target/release/deps" + +# Copy the built .so file to a generic name. +SO_FILE="./monero_c/release/monero/${TARGET_ARCH}_libwallet2_api_c.dylib" +if [[ -f "$SO_FILE" ]]; then + cp "$SO_FILE" "./libs/libwallet2_api_c.dylib" + echo "Copied $SO_FILE to libwallet2_api_c.dylib" +else + echo "Error: $SO_FILE not found." + exit 1 +fi diff --git a/monero-native/src/bindings.rs b/monero-native/src/bindings.rs new file mode 100644 index 0000000000..1d0aa5b618 --- /dev/null +++ b/monero-native/src/bindings.rs @@ -0,0 +1,1621 @@ +#![allow(non_upper_case_globals)] +#![allow(dead_code)] +/* automatically generated by rust-bindgen 0.70.1 */ + +pub const MONERO_wallet2_api_c_h_sha256: &[u8; 65] = + b"6c1ba9b57cb185c6dad030b15bcffe8a4772f33930e7f1d62d23b33514ba6f62\0"; +pub const MONERO_wallet2_api_c_cpp_sha256 : & [u8 ; 106] = b"1d1deff340408541f5755b4838d06345f63dcdfffe26b14dbdce32a5de839c55-b089f9ee69924882c5d14dd1a6991deb05d9d1cd\0" ; +pub const MONERO_wallet2_api_c_exp_sha256: &[u8; 65] = + b"d0f95f1f3bc49f1f59fe4eb0b61826128d7d3bb75405d5a01a252d02db03097d\0"; +pub const NetworkType_MAINNET: ::std::os::raw::c_int = 0; +pub const NetworkType_TESTNET: ::std::os::raw::c_int = 1; +pub const NetworkType_STAGENET: ::std::os::raw::c_int = 2; +pub const PendingTransactionStatus_Ok: ::std::os::raw::c_int = 0; +pub const PendingTransactionStatus_Error: ::std::os::raw::c_int = 1; +pub const PendingTransactionStatus_Critical: ::std::os::raw::c_int = 2; +pub const Priority_Default: ::std::os::raw::c_int = 0; +pub const Priority_Low: ::std::os::raw::c_int = 1; +pub const Priority_Medium: ::std::os::raw::c_int = 2; +pub const Priority_High: ::std::os::raw::c_int = 3; +pub const Priority_Last: ::std::os::raw::c_int = 4; +extern "C" { + pub fn MONERO_PendingTransaction_status( + pendingTx_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_PendingTransaction_errorString( + pendingTx_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_commit( + pendingTx_ptr: *mut ::std::os::raw::c_void, + filename: *const ::std::os::raw::c_char, + overwrite: bool, + ) -> bool; +} +extern "C" { + pub fn MONERO_PendingTransaction_commitUR( + pendingTx_ptr: *mut ::std::os::raw::c_void, + max_fragment_length: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_amount(pendingTx_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_PendingTransaction_dust(pendingTx_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_PendingTransaction_fee(pendingTx_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_PendingTransaction_txid( + pendingTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_txCount(pendingTx_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_PendingTransaction_subaddrAccount( + pendingTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_subaddrIndices( + pendingTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_multisigSignData( + pendingTx_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_signMultisigTx(pendingTx_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_PendingTransaction_signersKeys( + pendingTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_PendingTransaction_hex( + pendingTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +pub const UnsignedTransactionStatus_Ok: ::std::os::raw::c_int = 0; +pub const UnsignedTransactionStatus_Error: ::std::os::raw::c_int = 1; +pub const UnsignedTransactionStatus_Critical: ::std::os::raw::c_int = 2; +extern "C" { + pub fn MONERO_UnsignedTransaction_status( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_errorString( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_amount( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_fee( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_mixin( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_confirmationMessage( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_paymentId( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_recipientAddress( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_minMixinCount( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + ) -> u64; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_txCount(unsignedTx_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_sign( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + signedFileName: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_UnsignedTransaction_signUR( + unsignedTx_ptr: *mut ::std::os::raw::c_void, + max_fragment_length: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +pub const TransactionInfoDirection_In: ::std::os::raw::c_int = 0; +pub const TransactionInfoDirection_Out: ::std::os::raw::c_int = 1; +extern "C" { + pub fn MONERO_TransactionInfo_direction( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_TransactionInfo_isPending(txInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_TransactionInfo_isFailed(txInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_TransactionInfo_isCoinbase(txInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_TransactionInfo_amount(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_fee(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_blockHeight(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_description( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionInfo_subaddrIndex( + txInfo_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionInfo_subaddrAccount(txInfo_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_TransactionInfo_label( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionInfo_confirmations(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_unlockTime(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_hash( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionInfo_timestamp(txInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_paymentId( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionInfo_transfers_count( + txInfo_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_TransactionInfo_transfers_amount( + txInfo_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> u64; +} +extern "C" { + pub fn MONERO_TransactionInfo_transfers_address( + txInfo_ptr: *mut ::std::os::raw::c_void, + address: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_TransactionHistory_count( + txHistory_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_TransactionHistory_transaction( + txHistory_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_TransactionHistory_transactionById( + txHistory_ptr: *mut ::std::os::raw::c_void, + id: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_TransactionHistory_refresh(txHistory_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_TransactionHistory_setTxNote( + txHistory_ptr: *mut ::std::os::raw::c_void, + txid: *const ::std::os::raw::c_char, + note: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_AddressBookRow_extra( + addressBookRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_AddressBookRow_getAddress( + addressBookRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_AddressBookRow_getDescription( + addressBookRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_AddressBookRow_getPaymentId( + addressBookRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_AddressBookRow_getRowId(addressBookRow_ptr: *mut ::std::os::raw::c_void) + -> usize; +} +pub const AddressBookErrorCodeStatus_Ok: ::std::os::raw::c_int = 0; +pub const AddressBookErrorCodeGeneral_Error: ::std::os::raw::c_int = 1; +pub const AddressBookErrorCodeInvalid_Address: ::std::os::raw::c_int = 2; +pub const AddressBookErrorCodeInvalidPaymentId: ::std::os::raw::c_int = 3; +extern "C" { + pub fn MONERO_AddressBook_getAll_size( + addressBook_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_AddressBook_getAll_byIndex( + addressBook_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_AddressBook_addRow( + addressBook_ptr: *mut ::std::os::raw::c_void, + dst_addr: *const ::std::os::raw::c_char, + payment_id: *const ::std::os::raw::c_char, + description: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_AddressBook_deleteRow( + addressBook_ptr: *mut ::std::os::raw::c_void, + rowId: usize, + ) -> bool; +} +extern "C" { + pub fn MONERO_AddressBook_setDescription( + addressBook_ptr: *mut ::std::os::raw::c_void, + rowId: usize, + description: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_AddressBook_refresh(addressBook_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_AddressBook_errorString( + addressBook_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_AddressBook_errorCode( + addressBook_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_AddressBook_lookupPaymentID( + addressBook_ptr: *mut ::std::os::raw::c_void, + payment_id: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_CoinsInfo_blockHeight(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_CoinsInfo_hash( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_CoinsInfo_internalOutputIndex( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> usize; +} +extern "C" { + pub fn MONERO_CoinsInfo_globalOutputIndex(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_CoinsInfo_spent(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_frozen(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_spentHeight(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_CoinsInfo_amount(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_CoinsInfo_rct(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_keyImageKnown(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_pkIndex(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> usize; +} +extern "C" { + pub fn MONERO_CoinsInfo_subaddrIndex(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_CoinsInfo_subaddrAccount(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_CoinsInfo_address( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_CoinsInfo_addressLabel( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_CoinsInfo_keyImage( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_CoinsInfo_unlockTime(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_CoinsInfo_unlocked(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_pubKey( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_CoinsInfo_coinbase(coinsInfo_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_CoinsInfo_description( + coinsInfo_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Coins_count(coins_ptr: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Coins_coin( + coins_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Coins_getAll_size( + coins_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Coins_getAll_byIndex( + coins_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Coins_refresh(coins_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Coins_setFrozenByPublicKey( + coins_ptr: *mut ::std::os::raw::c_void, + public_key: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Coins_setFrozen( + coins_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ); +} +extern "C" { + pub fn MONERO_Coins_thaw(coins_ptr: *mut ::std::os::raw::c_void, index: ::std::os::raw::c_int); +} +extern "C" { + pub fn MONERO_Coins_thawByPublicKey( + coins_ptr: *mut ::std::os::raw::c_void, + public_key: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Coins_isTransferUnlocked( + coins_ptr: *mut ::std::os::raw::c_void, + unlockTime: u64, + blockHeight: u64, + ) -> bool; +} +extern "C" { + pub fn MONERO_Coins_setDescription( + coins_ptr: *mut ::std::os::raw::c_void, + public_key: *const ::std::os::raw::c_char, + description: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_SubaddressRow_extra( + subaddressRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressRow_getAddress( + subaddressRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressRow_getLabel( + subaddressRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressRow_getRowId(subaddressRow_ptr: *mut ::std::os::raw::c_void) -> usize; +} +extern "C" { + pub fn MONERO_Subaddress_getAll_size( + subaddress_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Subaddress_getAll_byIndex( + subaddress_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Subaddress_addRow( + subaddress_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Subaddress_setLabel( + subaddress_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + addressIndex: u32, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Subaddress_refresh( + subaddress_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + ); +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_extra( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_getAddress( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_getLabel( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_getBalance( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_getUnlockedBalance( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_SubaddressAccountRow_getRowId( + subaddressAccountRow_ptr: *mut ::std::os::raw::c_void, + ) -> usize; +} +extern "C" { + pub fn MONERO_SubaddressAccount_getAll_size( + subaddressAccount_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_SubaddressAccount_getAll_byIndex( + subaddressAccount_ptr: *mut ::std::os::raw::c_void, + index: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_SubaddressAccount_addRow( + subaddressAccount_ptr: *mut ::std::os::raw::c_void, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_SubaddressAccount_setLabel( + subaddressAccount_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_SubaddressAccount_refresh(subaddressAccount_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_MultisigState_isMultisig(multisigState_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_MultisigState_isReady(multisigState_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_MultisigState_threshold(multisigState_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_MultisigState_total(multisigState_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_DeviceProgress_progress(deviceProgress_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_DeviceProgress_indeterminate( + deviceProgress_ptr: *mut ::std::os::raw::c_void, + ) -> bool; +} +pub const WalletDevice_Software: ::std::os::raw::c_int = 0; +pub const WalletDevice_Ledger: ::std::os::raw::c_int = 1; +pub const WalletDevice_Trezor: ::std::os::raw::c_int = 2; +pub const WalletStatus_Ok: ::std::os::raw::c_int = 0; +pub const WalletStatus_Error: ::std::os::raw::c_int = 1; +pub const WalletStatus_Critical: ::std::os::raw::c_int = 2; +pub const WalletConnectionStatus_Disconnected: ::std::os::raw::c_int = 0; +pub const WalletConnectionStatus_Connected: ::std::os::raw::c_int = 1; +pub const WalletConnectionStatus_WrongVersion: ::std::os::raw::c_int = 2; +pub const WalletBackgroundSync_Off: ::std::os::raw::c_int = 0; +pub const WalletBackgroundSync_ReusePassword: ::std::os::raw::c_int = 1; +pub const BackgroundSync_CustomPassword: ::std::os::raw::c_int = 2; +extern "C" { + pub fn MONERO_Wallet_seed( + wallet_ptr: *mut ::std::os::raw::c_void, + seed_offset: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_getSeedLanguage( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_setSeedLanguage( + wallet_ptr: *mut ::std::os::raw::c_void, + arg: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Wallet_status(wallet_ptr: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_errorString( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_setPassword( + wallet_ptr: *mut ::std::os::raw::c_void, + password: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getPassword( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_setDevicePin( + wallet_ptr: *mut ::std::os::raw::c_void, + pin: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setDevicePassphrase( + wallet_ptr: *mut ::std::os::raw::c_void, + passphrase: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_address( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u64, + addressIndex: u64, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_path( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_nettype(wallet_ptr: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_useForkRules( + wallet_ptr: *mut ::std::os::raw::c_void, + version: u8, + early_blocks: i64, + ) -> u8; +} +extern "C" { + pub fn MONERO_Wallet_integratedAddress( + wallet_ptr: *mut ::std::os::raw::c_void, + payment_id: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_secretViewKey( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_publicViewKey( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_secretSpendKey( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_publicSpendKey( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_publicMultisigSignerKey( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_stop(wallet_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Wallet_store( + wallet_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_filename( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_keysFilename( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_init( + wallet_ptr: *mut ::std::os::raw::c_void, + daemon_address: *const ::std::os::raw::c_char, + upper_transaction_size_limit: u64, + daemon_username: *const ::std::os::raw::c_char, + daemon_password: *const ::std::os::raw::c_char, + use_ssl: bool, + lightWallet: bool, + proxy_address: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_createWatchOnly( + wallet_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + language: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setRefreshFromBlockHeight( + wallet_ptr: *mut ::std::os::raw::c_void, + refresh_from_block_height: u64, + ); +} +extern "C" { + pub fn MONERO_Wallet_getRefreshFromBlockHeight(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_setRecoveringFromSeed( + wallet_ptr: *mut ::std::os::raw::c_void, + recoveringFromSeed: bool, + ); +} +extern "C" { + pub fn MONERO_Wallet_setRecoveringFromDevice( + wallet_ptr: *mut ::std::os::raw::c_void, + recoveringFromDevice: bool, + ); +} +extern "C" { + pub fn MONERO_Wallet_setSubaddressLookahead( + wallet_ptr: *mut ::std::os::raw::c_void, + major: u32, + minor: u32, + ); +} +extern "C" { + pub fn MONERO_Wallet_connectToDaemon(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_connected( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_setTrustedDaemon(wallet_ptr: *mut ::std::os::raw::c_void, arg: bool); +} +extern "C" { + pub fn MONERO_Wallet_trustedDaemon(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setProxy( + wallet_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_balance(wallet_ptr: *mut ::std::os::raw::c_void, accountIndex: u32) + -> u64; +} +extern "C" { + pub fn MONERO_Wallet_unlockedBalance( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + ) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_viewOnlyBalance( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + ) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_watchOnly(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_isDeterministic(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_blockChainHeight(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_approximateBlockChainHeight( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_estimateBlockChainHeight(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_daemonBlockChainHeight(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_daemonBlockChainTargetHeight( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_synchronized(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_displayAmount(amount: u64) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_amountFromString(amount: *const ::std::os::raw::c_char) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_amountFromDouble(amount: f64) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_genPaymentId() -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_paymentIdValid(paiment_id: *const ::std::os::raw::c_char) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_addressValid( + str_: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_keyValid( + secret_key_string: *const ::std::os::raw::c_char, + address_string: *const ::std::os::raw::c_char, + isViewKey: bool, + nettype: ::std::os::raw::c_int, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_keyValid_error( + secret_key_string: *const ::std::os::raw::c_char, + address_string: *const ::std::os::raw::c_char, + isViewKey: bool, + nettype: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_paymentIdFromAddress( + strarg: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_maximumAllowedAmount() -> u64; +} +extern "C" { + pub fn MONERO_Wallet_init3( + wallet_ptr: *mut ::std::os::raw::c_void, + argv0: *const ::std::os::raw::c_char, + default_log_base_name: *const ::std::os::raw::c_char, + log_path: *const ::std::os::raw::c_char, + console: bool, + ); +} +extern "C" { + pub fn MONERO_Wallet_getPolyseed( + wallet_ptr: *mut ::std::os::raw::c_void, + passphrase: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_createPolyseed( + language: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_startRefresh(wallet_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Wallet_pauseRefresh(wallet_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Wallet_refresh(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_refreshAsync(wallet_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Wallet_rescanBlockchain(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_rescanBlockchainAsync(wallet_ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_Wallet_setAutoRefreshInterval( + wallet_ptr: *mut ::std::os::raw::c_void, + millis: ::std::os::raw::c_int, + ); +} +extern "C" { + pub fn MONERO_Wallet_autoRefreshInterval( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_addSubaddressAccount( + wallet_ptr: *mut ::std::os::raw::c_void, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Wallet_numSubaddressAccounts(wallet_ptr: *mut ::std::os::raw::c_void) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_numSubaddresses( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + ) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_addSubaddress( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Wallet_getSubaddressLabel( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + addressIndex: u32, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_setSubaddressLabel( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + addressIndex: u32, + label: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_Wallet_multisig( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_getMultisigInfo( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_makeMultisig( + wallet_ptr: *mut ::std::os::raw::c_void, + info: *const ::std::os::raw::c_char, + info_separator: *const ::std::os::raw::c_char, + threshold: u32, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_exchangeMultisigKeys( + wallet_ptr: *mut ::std::os::raw::c_void, + info: *const ::std::os::raw::c_char, + info_separator: *const ::std::os::raw::c_char, + force_update_use_with_caution: bool, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_exportMultisigImages( + wallet_ptr: *mut ::std::os::raw::c_void, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_importMultisigImages( + wallet_ptr: *mut ::std::os::raw::c_void, + info: *const ::std::os::raw::c_char, + info_separator: *const ::std::os::raw::c_char, + ) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_hasMultisigPartialKeyImages( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_restoreMultisigTransaction( + wallet_ptr: *mut ::std::os::raw::c_void, + signData: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_createTransactionMultDest( + wallet_ptr: *mut ::std::os::raw::c_void, + dst_addr_list: *const ::std::os::raw::c_char, + dst_addr_list_separator: *const ::std::os::raw::c_char, + payment_id: *const ::std::os::raw::c_char, + amount_sweep_all: bool, + amount_list: *const ::std::os::raw::c_char, + amount_list_separator: *const ::std::os::raw::c_char, + mixin_count: u32, + pendingTransactionPriority: ::std::os::raw::c_int, + subaddr_account: u32, + preferredInputs: *const ::std::os::raw::c_char, + preferredInputs_separator: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_createTransaction( + wallet_ptr: *mut ::std::os::raw::c_void, + dst_addr: *const ::std::os::raw::c_char, + payment_id: *const ::std::os::raw::c_char, + amount: u64, + mixin_count: u32, + pendingTransactionPriority: ::std::os::raw::c_int, + subaddr_account: u32, + preferredInputs: *const ::std::os::raw::c_char, + separator: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_loadUnsignedTx( + wallet_ptr: *mut ::std::os::raw::c_void, + unsigned_filename: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_loadUnsignedTxUR( + wallet_ptr: *mut ::std::os::raw::c_void, + input: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_submitTransaction( + wallet_ptr: *mut ::std::os::raw::c_void, + fileName: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_submitTransactionUR( + wallet_ptr: *mut ::std::os::raw::c_void, + input: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_hasUnknownKeyImages(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_exportKeyImages( + wallet_ptr: *mut ::std::os::raw::c_void, + filename: *const ::std::os::raw::c_char, + all: bool, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_exportKeyImagesUR( + wallet_ptr: *mut ::std::os::raw::c_void, + max_fragment_length: usize, + all: bool, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_importKeyImages( + wallet_ptr: *mut ::std::os::raw::c_void, + filename: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_importKeyImagesUR( + wallet_ptr: *mut ::std::os::raw::c_void, + input: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_exportOutputs( + wallet_ptr: *mut ::std::os::raw::c_void, + filename: *const ::std::os::raw::c_char, + all: bool, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_exportOutputsUR( + wallet_ptr: *mut ::std::os::raw::c_void, + max_fragment_length: usize, + all: bool, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_importOutputs( + wallet_ptr: *mut ::std::os::raw::c_void, + filename: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_importOutputsUR( + wallet_ptr: *mut ::std::os::raw::c_void, + input: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setupBackgroundSync( + wallet_ptr: *mut ::std::os::raw::c_void, + background_sync_type: ::std::os::raw::c_int, + wallet_password: *const ::std::os::raw::c_char, + background_cache_password: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getBackgroundSyncType( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_startBackgroundSync(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_stopBackgroundSync( + wallet_ptr: *mut ::std::os::raw::c_void, + wallet_password: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_isBackgroundSyncing(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_isBackgroundWallet(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_history( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_addressBook( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_coins( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_subaddress( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_subaddressAccount( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_Wallet_defaultMixin(wallet_ptr: *mut ::std::os::raw::c_void) -> u32; +} +extern "C" { + pub fn MONERO_Wallet_setDefaultMixin(wallet_ptr: *mut ::std::os::raw::c_void, arg: u32); +} +extern "C" { + pub fn MONERO_Wallet_setCacheAttribute( + wallet_ptr: *mut ::std::os::raw::c_void, + key: *const ::std::os::raw::c_char, + val: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getCacheAttribute( + wallet_ptr: *mut ::std::os::raw::c_void, + key: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_setUserNote( + wallet_ptr: *mut ::std::os::raw::c_void, + txid: *const ::std::os::raw::c_char, + note: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getUserNote( + wallet_ptr: *mut ::std::os::raw::c_void, + txid: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_getTxKey( + wallet_ptr: *mut ::std::os::raw::c_void, + txid: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_checkTxKey( + wallet_ptr: *mut ::std::os::raw::c_void, + txid: *const ::std::os::raw::c_char, + tx_key: *const ::std::os::raw::c_char, + address: *const ::std::os::raw::c_char, + received: *mut u64, + in_pool: *mut bool, + confirmations: *mut u64, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_signMessage( + wallet_ptr: *mut ::std::os::raw::c_void, + message: *const ::std::os::raw::c_char, + address: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_verifySignedMessage( + wallet_ptr: *mut ::std::os::raw::c_void, + message: *const ::std::os::raw::c_char, + address: *const ::std::os::raw::c_char, + signature: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_rescanSpent(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setOffline(wallet_ptr: *mut ::std::os::raw::c_void, offline: bool); +} +extern "C" { + pub fn MONERO_Wallet_isOffline(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_segregatePreForkOutputs( + wallet_ptr: *mut ::std::os::raw::c_void, + segregate: bool, + ); +} +extern "C" { + pub fn MONERO_Wallet_segregationHeight(wallet_ptr: *mut ::std::os::raw::c_void, height: u64); +} +extern "C" { + pub fn MONERO_Wallet_keyReuseMitigation2( + wallet_ptr: *mut ::std::os::raw::c_void, + mitigation: bool, + ); +} +extern "C" { + pub fn MONERO_Wallet_lockKeysFile(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_unlockKeysFile(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_isKeysFileLocked(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getDeviceType( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_Wallet_coldKeyImageSync( + wallet_ptr: *mut ::std::os::raw::c_void, + spent: u64, + unspent: u64, + ) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_deviceShowAddress( + wallet_ptr: *mut ::std::os::raw::c_void, + accountIndex: u32, + addressIndex: u32, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_Wallet_reconnectDevice(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getBytesReceived(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_getBytesSent(wallet_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_Wallet_getStateIsConnected(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getSendToDevice( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_uchar; +} +extern "C" { + pub fn MONERO_Wallet_getSendToDeviceLength(wallet_ptr: *mut ::std::os::raw::c_void) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_getReceivedFromDevice( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_uchar; +} +extern "C" { + pub fn MONERO_Wallet_getReceivedFromDeviceLength( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> usize; +} +extern "C" { + pub fn MONERO_Wallet_getWaitsForDeviceSend(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_getWaitsForDeviceReceive(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_Wallet_setDeviceReceivedData( + wallet_ptr: *mut ::std::os::raw::c_void, + data: *mut ::std::os::raw::c_uchar, + len: usize, + ); +} +extern "C" { + pub fn MONERO_Wallet_setDeviceSendData( + wallet_ptr: *mut ::std::os::raw::c_void, + data: *mut ::std::os::raw::c_uchar, + len: usize, + ); +} +extern "C" { + pub fn MONERO_WalletManager_createWallet( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + language: *const ::std::os::raw::c_char, + networkType: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_openWallet( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + networkType: ::std::os::raw::c_int, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_recoveryWallet( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + mnemonic: *const ::std::os::raw::c_char, + networkType: ::std::os::raw::c_int, + restoreHeight: u64, + kdfRounds: u64, + seedOffset: *const ::std::os::raw::c_char, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_createWalletFromKeys( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + language: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + restoreHeight: u64, + addressString: *const ::std::os::raw::c_char, + viewKeyString: *const ::std::os::raw::c_char, + spendKeyString: *const ::std::os::raw::c_char, + kdf_rounds: u64, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_createDeterministicWalletFromSpendKey( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + language: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + restoreHeight: u64, + spendKeyString: *const ::std::os::raw::c_char, + kdf_rounds: u64, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_createWalletFromDevice( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + deviceName: *const ::std::os::raw::c_char, + restoreHeight: u64, + subaddressLookahead: *const ::std::os::raw::c_char, + viewKeyString: *const ::std::os::raw::c_char, + spendKeyString: *const ::std::os::raw::c_char, + kdf_rounds: u64, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_createWalletFromPolyseed( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + nettype: ::std::os::raw::c_int, + mnemonic: *const ::std::os::raw::c_char, + passphrase: *const ::std::os::raw::c_char, + newWallet: bool, + restore_height: u64, + kdf_rounds: u64, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManager_closeWallet( + wm_ptr: *mut ::std::os::raw::c_void, + wallet_ptr: *mut ::std::os::raw::c_void, + store: bool, + ) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_walletExists( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_verifyWalletPassword( + wm_ptr: *mut ::std::os::raw::c_void, + keys_file_name: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + no_spend_key: bool, + kdf_rounds: u64, + ) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_queryWalletDevice( + wm_ptr: *mut ::std::os::raw::c_void, + keys_file_name: *const ::std::os::raw::c_char, + password: *const ::std::os::raw::c_char, + kdf_rounds: u64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_WalletManager_findWallets( + wm_ptr: *mut ::std::os::raw::c_void, + path: *const ::std::os::raw::c_char, + separator: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_WalletManager_errorString( + wm_ptr: *mut ::std::os::raw::c_void, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_WalletManager_setDaemonAddress( + wm_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + ); +} +extern "C" { + pub fn MONERO_WalletManager_blockchainHeight(wm_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_WalletManager_blockchainTargetHeight(wm_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_WalletManager_networkDifficulty(wm_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_WalletManager_miningHashRate(wm_ptr: *mut ::std::os::raw::c_void) -> f64; +} +extern "C" { + pub fn MONERO_WalletManager_blockTarget(wm_ptr: *mut ::std::os::raw::c_void) -> u64; +} +extern "C" { + pub fn MONERO_WalletManager_isMining(wm_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_startMining( + wm_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + threads: u32, + backgroundMining: bool, + ignoreBattery: bool, + ) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_stopMining( + wm_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + pub fn MONERO_WalletManager_resolveOpenAlias( + wm_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + dnssec_valid: bool, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_WalletManager_setProxy( + wm_ptr: *mut ::std::os::raw::c_void, + address: *const ::std::os::raw::c_char, + ) -> bool; +} +pub const LogLevel_Silent: ::std::os::raw::c_int = -1; +pub const LogLevel_0: ::std::os::raw::c_int = 0; +pub const LogLevel_1: ::std::os::raw::c_int = 1; +pub const LogLevel_2: ::std::os::raw::c_int = 2; +pub const LogLevel_3: ::std::os::raw::c_int = 3; +pub const LogLevel_4: ::std::os::raw::c_int = 4; +pub const LogLevel_Min: ::std::os::raw::c_int = -1; +pub const LogLevel_Max: ::std::os::raw::c_int = 4; +extern "C" { + pub fn MONERO_WalletManagerFactory_getWalletManager() -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_WalletManagerFactory_setLogLevel(level: ::std::os::raw::c_int); +} +extern "C" { + pub fn MONERO_WalletManagerFactory_setLogCategories(categories: *const ::std::os::raw::c_char); +} +extern "C" { + pub fn MONERO_DEBUG_test0(); +} +extern "C" { + pub fn MONERO_DEBUG_test1(x: bool) -> bool; +} +extern "C" { + pub fn MONERO_DEBUG_test2(x: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn MONERO_DEBUG_test3(x: u64) -> u64; +} +extern "C" { + pub fn MONERO_DEBUG_test4(x: u64) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_DEBUG_test5() -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_DEBUG_test5_std() -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_DEBUG_isPointerNull(wallet_ptr: *mut ::std::os::raw::c_void) -> bool; +} +extern "C" { + pub fn MONERO_cw_getWalletListener( + wallet_ptr: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn MONERO_cw_WalletListener_resetNeedToRefresh( + cw_walletListener_ptr: *mut ::std::os::raw::c_void, + ); +} +extern "C" { + pub fn MONERO_cw_WalletListener_isNeedToRefresh( + cw_walletListener_ptr: *mut ::std::os::raw::c_void, + ) -> bool; +} +extern "C" { + pub fn MONERO_cw_WalletListener_isNewTransactionExist( + cw_walletListener_ptr: *mut ::std::os::raw::c_void, + ) -> bool; +} +extern "C" { + pub fn MONERO_cw_WalletListener_resetIsNewTransactionExist( + cw_walletListener_ptr: *mut ::std::os::raw::c_void, + ); +} +extern "C" { + pub fn MONERO_cw_WalletListener_height( + cw_walletListener_ptr: *mut ::std::os::raw::c_void, + ) -> u64; +} +extern "C" { + pub fn MONERO_free(ptr: *mut ::std::os::raw::c_void); +} +extern "C" { + pub fn MONERO_checksum_wallet2_api_c_h() -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_checksum_wallet2_api_c_cpp() -> *const ::std::os::raw::c_char; +} +extern "C" { + pub fn MONERO_checksum_wallet2_api_c_exp() -> *const ::std::os::raw::c_char; +} diff --git a/monero-native/src/lib.rs b/monero-native/src/lib.rs new file mode 100644 index 0000000000..9d9e0f7dc2 --- /dev/null +++ b/monero-native/src/lib.rs @@ -0,0 +1,2400 @@ +use std::ffi::{CStr, CString}; +use std::fmt; +use std::os::raw::{c_int, c_void}; +use std::path::PathBuf; +use std::ptr::NonNull; +use std::str::FromStr; +use std::sync::Arc; + +pub mod bindings; +pub use bindings::WalletStatus_Critical; +pub use bindings::WalletStatus_Error; +pub use bindings::WalletStatus_Ok; +use monero::{Address, Block, Network}; +use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; + +trait NetworkToFromCInt: Sized { + fn from_c_int(value: c_int) -> Option; + fn to_c_int(self) -> c_int; +} + +impl NetworkToFromCInt for Network { + fn from_c_int(value: c_int) -> Option { + match value { + bindings::NetworkType_MAINNET => Some(Network::Mainnet), + bindings::NetworkType_TESTNET => Some(Network::Testnet), + bindings::NetworkType_STAGENET => Some(Network::Stagenet), + _ => None, + } + } + + fn to_c_int(self) -> c_int { + match self { + Network::Mainnet => bindings::NetworkType_MAINNET, + Network::Testnet => bindings::NetworkType_TESTNET, + Network::Stagenet => bindings::NetworkType_STAGENET, + } + } +} + +#[derive(Debug, thiserror::Error)] +pub enum WalletError { + #[error("Null pointer encountered")] + NullPointer, + #[error("FFI error: {0}")] + FfiError(String), + #[error("Wallet error (code {0}): {1}")] + WalletErrorCode(c_int, String), +} + +pub type WalletResult = Result; + +#[derive(Debug)] +pub struct Account { + pub index: u32, + pub label: String, + pub balance: u64, + pub unlocked_balance: u64, +} + +#[derive(Debug)] +pub struct GetAccounts { + pub accounts: Vec, +} + +pub struct Wallet { + pub ptr: NonNull, + pub manager: Arc, + pub is_closed: bool, +} + +pub struct WalletManager { + ptr: NonNull, +} + +/// Configuration parameters for initializing a wallet. +#[derive(Debug, Clone)] +pub struct WalletConfig { + pub daemon_address: String, + pub upper_transaction_size_limit: u64, + pub daemon_username: String, + pub daemon_password: String, + pub use_ssl: bool, + pub light_wallet: bool, + pub proxy_address: String, +} + +impl Default for WalletConfig { + fn default() -> Self { + WalletConfig { + daemon_address: "localhost:18081".to_string(), + upper_transaction_size_limit: 10000, // TODO: set sane value. + daemon_username: "".to_string(), + daemon_password: "".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Ord, Eq)] +pub struct BlockHeight { + pub height: u64, +} + +impl fmt::Display for BlockHeight { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.height) + } +} + +#[derive(Debug)] +pub struct Refreshed; + +/// Represents a destination address and the amount to send. +#[derive(Debug, Clone)] +pub struct Destination { + /// The recipient's address. + pub address: String, + /// The amount to send to the recipient (in atomic units). + pub amount: u64, +} + +/// Represents the result of a transfer operation. +#[derive(Debug)] +pub struct Transfer { + /// The transaction ID of the transfer. + pub txid: String, + /// The transaction key, if requested. + pub tx_key: Option, + /// The total amount sent in the transfer. + pub amount: u64, + /// The fee associated with the transfer. + pub fee: u64, +} + +/// Represents the result of checking a transaction key against a transaction ID and address. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CheckTxKey { + /// The amount received in the transaction. + pub received: u64, + /// Indicates whether the transaction is in the pool. + pub in_pool: bool, + /// The number of confirmations for the transaction. + pub confirmations: u64, +} + +impl WalletManager { + /// Creates a new `WalletManager`. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::WalletManager; + /// let manager = WalletManager::new(); + /// assert!(manager.is_ok()); + /// ``` + pub fn new() -> WalletResult> { + unsafe { + bindings::MONERO_WalletManagerFactory_setLogLevel(4); + let ptr = bindings::MONERO_WalletManagerFactory_getWalletManager(); + let ptr = NonNull::new(ptr).ok_or(WalletError::NullPointer)?; + Ok(Arc::new(WalletManager { ptr })) + } + } + + /// Check the status of a wallet to ensure it's in a valid state. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// + /// // Check the status of the wallet, expecting OK + /// let status_result = manager.get_status(wallet.ptr.as_ptr()); + /// assert!(status_result.is_ok(), "Failed to get status: {:?}", status_result.err()); + /// assert_eq!(status_result.unwrap(), (), "Expected status to be OK"); + /// + /// // Clean up wallet files. + /// std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// std::fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn get_status(&self, wallet_ptr: *mut c_void) -> WalletResult<()> { + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); // Ensure NullPointer is returned for null wallet + } + + unsafe { + let status = bindings::MONERO_Wallet_status(wallet_ptr); + + if status == bindings::WalletStatus_Ok { + Ok(()) + } else { + let error_ptr = bindings::MONERO_Wallet_errorString(wallet_ptr); + let error_msg = if error_ptr.is_null() { + "Unknown error".to_string() + } else { + CStr::from_ptr(error_ptr).to_string_lossy().into_owned() + }; + Err(WalletError::WalletErrorCode(status, error_msg)) + } + } + } + + /// Check the status of a wallet and throw an error if an issue is found. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// + /// // Check the status of the wallet, expecting OK + /// let status_result = manager.throw_if_error(wallet.ptr.as_ptr()); + /// assert!(status_result.is_ok(), "Failed to get status: {:?}", status_result.err()); + /// + /// // Clean up wallet files. + /// std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// std::fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn throw_if_error(&self, wallet_ptr: *mut c_void) -> WalletResult<()> { + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + unsafe { + let status = bindings::MONERO_Wallet_status(wallet_ptr); + if status == bindings::WalletStatus_Ok { + Ok(()) + } else { + let error_ptr = bindings::MONERO_Wallet_errorString(wallet_ptr); + let error_msg = if error_ptr.is_null() { + "Unknown error".to_string() + } else { + CStr::from_ptr(error_ptr).to_string_lossy().into_owned() + }; + Err(WalletError::WalletErrorCode(status, error_msg)) + } + } + } + + /// Sets the daemon address of WalletManager + pub fn set_daemon_address(&self, daemon_address: &str) -> WalletResult<()> { + let c_daemon_address = CString::new(daemon_address) + .map_err(|_| WalletError::FfiError("Invalid daemon address".to_string()))?; + + unsafe { + bindings::MONERO_WalletManager_setDaemonAddress( + self.ptr.as_ptr(), + c_daemon_address.as_ptr(), + ); + Ok(()) + } + } + + /// Create a new wallet. + /// + /// Generates a new wallet with the provided path, password, language, and network type, with a + /// new mnemonic seed generated in the specified language. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network}; + /// use std::fs; + /// use std::path::Path; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet.is_ok()); + /// + /// // Clean up wallet files. + /// std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// std::fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn create_wallet( + self: &Arc, + path: PathBuf, + password: &str, + language: &str, + network_type: Network, + ) -> WalletResult { + let c_path = CString::new(path.to_str().unwrap()) + .map_err(|_| WalletError::FfiError("Invalid path".to_string()))?; + let c_password = CString::new(password) + .map_err(|_| WalletError::FfiError("Invalid password".to_string()))?; + let c_language = CString::new(language) + .map_err(|_| WalletError::FfiError("Invalid language".to_string()))?; + + unsafe { + let wallet_ptr = bindings::MONERO_WalletManager_createWallet( + self.ptr.as_ptr(), + c_path.as_ptr(), + c_password.as_ptr(), + c_language.as_ptr(), + network_type.to_c_int(), + ); + + self.throw_if_error(wallet_ptr)?; + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + Ok(Wallet { + ptr: NonNull::new(wallet_ptr).unwrap(), + manager: Arc::clone(self), + is_closed: false, + }) + } + } + + /// Restores a wallet from a mnemonic seed. + /// + /// This method restores a Monero wallet using the provided mnemonic seed, network type, and other + /// configuration parameters. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("restored_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap().to_string(); + /// + /// let manager = WalletManager::new().expect("Failed to create WalletManager"); + /// + /// let mnemonic = "hemlock jubilee eden hacksaw boil superior inroads epoxy exhale orders cavernous second brunt saved richly lower upgrade hitched launching deepest mostly playful layout lower eden".to_string(); + /// let wallet = manager.restore_mnemonic( + /// wallet_str, + /// "strong_password".to_string(), + /// mnemonic, + /// Network::Mainnet, + /// 0, // Restore from the beginning of the blockchain. + /// 1, // Default KDF rounds. + /// "".to_string(), // No seed offset. + /// ).expect("Failed to restore wallet"); + /// + /// // Use the wallet as needed... + /// + /// // Clean up wallet files. + /// fs::remove_file(&wallet_path).expect("Failed to delete restored wallet"); + /// fs::remove_file(format!("{}.keys", wallet_path.display())).expect("Failed to delete restored wallet keys"); + /// ``` + pub fn restore_mnemonic( + self: &Arc, + path: String, + password: String, + seed: String, + network_type: Network, + restore_height: u64, + kdf_rounds: u64, + seed_offset: String, // TODO: Make an Option. + ) -> WalletResult { + // Convert Rust strings to C-compatible strings. + let c_path = CString::new(path) + .map_err(|_| WalletError::FfiError("Invalid path string".to_string()))?; + let c_password = CString::new(password) + .map_err(|_| WalletError::FfiError("Invalid password string".to_string()))?; + let c_seed = CString::new(seed) + .map_err(|_| WalletError::FfiError("Invalid seed string".to_string()))?; + let c_seed_offset = CString::new(seed_offset) + .map_err(|_| WalletError::FfiError("Invalid seed_offset string".to_string()))?; + + unsafe { + let wallet_ptr = bindings::MONERO_WalletManager_recoveryWallet( + self.ptr.as_ptr(), + c_path.as_ptr(), + c_password.as_ptr(), + c_seed.as_ptr(), + network_type.to_c_int(), + restore_height, + kdf_rounds, + c_seed_offset.as_ptr(), + ); + + // Check for errors using the returned wallet pointer. + self.throw_if_error(wallet_ptr)?; + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + Ok(Wallet { + ptr: NonNull::new(wallet_ptr).unwrap(), + manager: Arc::clone(self), + is_closed: false, + }) + } + } + + /// Restores a wallet from a polyseed. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap().to_string(); + /// + /// let manager = WalletManager::new().expect("Failed to create WalletManager"); + /// + /// let polyseed = "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(); + /// let restored_wallet = manager.restore_polyseed( + /// wallet_str.clone(), + /// "password".to_string(), + /// polyseed, + /// Network::Mainnet, + /// 0, // Restore from the beginning of the blockchain. + /// 1, // Default KDF rounds. + /// "".to_string(), // No seed offset. + /// true, // Create a new wallet. + /// ).expect("Failed to restore wallet from polyseed"); + /// + /// // Use the restored_wallet as needed... + /// + /// // Clean up wallet files. + /// fs::remove_file(&wallet_path).expect("Failed to delete restored wallet"); + /// fs::remove_file(format!("{}.keys", wallet_path.display())).expect("Failed to delete restored wallet keys"); + /// ``` + pub fn restore_polyseed( + self: &Arc, + path: String, + password: String, + polyseed: String, + network_type: Network, + restore_height: u64, + kdf_rounds: u64, + seed_offset: String, + new_wallet: bool, + ) -> WalletResult { + // Convert Rust strings to C-compatible strings. + let c_path = CString::new(path) + .map_err(|_| WalletError::FfiError("Invalid path string".to_string()))?; + let c_password = CString::new(password) + .map_err(|_| WalletError::FfiError("Invalid password string".to_string()))?; + let c_polyseed = CString::new(polyseed) + .map_err(|_| WalletError::FfiError("Invalid mnemonic string".to_string()))?; + let c_seed_offset = CString::new(seed_offset) + .map_err(|_| WalletError::FfiError("Invalid seed offset string".to_string()))?; + + unsafe { + let wallet_ptr = bindings::MONERO_WalletManager_createWalletFromPolyseed( + self.ptr.as_ptr(), + c_path.as_ptr(), + c_password.as_ptr(), + network_type.to_c_int(), + c_polyseed.as_ptr(), + c_seed_offset.as_ptr(), + new_wallet, + restore_height, + kdf_rounds, + ); + + // Check for errors using the returned wallet pointer. + self.throw_if_error(wallet_ptr)?; + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + Ok(Wallet { + ptr: NonNull::new(wallet_ptr).unwrap(), + manager: Arc::clone(self), + is_closed: false, + }) + } + } + + /// Checks if a given wallet exists + pub fn wallet_exists(&self, path: PathBuf) -> WalletResult { + let c_path = CString::new(path.to_str().unwrap()) + .map_err(|_| WalletError::FfiError("Invalid name".to_string()))?; + + unsafe { + let exists = + bindings::MONERO_WalletManager_walletExists(self.ptr.as_ptr(), c_path.as_ptr()); + Ok(exists) + } + } + + /// Generates a wallet from provided keys. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use std::fs; + /// use std::path::Path; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.generate_from_keys( + /// wallet_str.to_string(), + /// "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi".to_string(), + /// "".to_string(), // Spend key optional: you can pass either the spend key or the view key. + /// "3bc0b202cde92fe5719c3cc0a16aa94f88a5d19f8c515d4e35fae361f6f2120e".to_string(), + /// 0, // Restore from the beginning of the blockchain. + /// "password".to_string(), + /// "English".to_string(), + /// Network::Mainnet, + /// 1, // Default KDF rounds. + /// ); + /// assert!(wallet.is_ok(), "Failed to generate wallet from keys: {:?}", wallet.err()); + /// + /// // Clean up wallet files. + /// std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// std::fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn generate_from_keys( + self: &Arc, + filename: String, + address: String, + spendkey: String, + viewkey: String, + restore_height: u64, + password: String, + language: String, + network_type: Network, + kdf_rounds: u64, + ) -> WalletResult { + let c_filename = CString::new(filename) + .map_err(|_| WalletError::FfiError("Invalid filename".to_string()))?; + let c_password = CString::new(password) + .map_err(|_| WalletError::FfiError("Invalid password".to_string()))?; + let c_language = CString::new(language) + .map_err(|_| WalletError::FfiError("Invalid language".to_string()))?; + let c_address = CString::new(address) + .map_err(|_| WalletError::FfiError("Invalid address".to_string()))?; + let c_spendkey = CString::new(spendkey) + .map_err(|_| WalletError::FfiError("Invalid spendkey".to_string()))?; + let c_viewkey = CString::new(viewkey) + .map_err(|_| WalletError::FfiError("Invalid viewkey".to_string()))?; + + unsafe { + let wallet_ptr = bindings::MONERO_WalletManager_createWalletFromKeys( + self.ptr.as_ptr(), + c_filename.as_ptr(), + c_password.as_ptr(), + c_language.as_ptr(), + network_type.to_c_int(), + restore_height, + c_address.as_ptr(), + c_viewkey.as_ptr(), + c_spendkey.as_ptr(), + kdf_rounds, + ); + + if wallet_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + self.throw_if_error(wallet_ptr)?; + + Ok(Wallet { + ptr: NonNull::new(wallet_ptr).unwrap(), + manager: Arc::clone(self), + is_closed: false, + }) + } + } + + /// Opens an existing wallet with the provided path, password, and network type. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// + /// // First, create a wallet to open later. + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// + /// // Close the wallet by dropping it. + /// drop(wallet); + /// + /// // Now try to open the existing wallet. + /// let open_result = manager.open_wallet(wallet_str, "password", Network::Mainnet); + /// assert!(open_result.is_ok(), "Failed to open wallet: {:?}", open_result.err()); + /// let opened_wallet = open_result.unwrap(); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn open_wallet( + self: &Arc, + path: PathBuf, + password: &str, + network_type: Network, + ) -> WalletResult { + let c_path = CString::new(path.into_os_string().into_string().unwrap()) + .map_err(|_| WalletError::FfiError("Invalid path".to_string()))?; + let c_password = CString::new(password) + .map_err(|_| WalletError::FfiError("Invalid password".to_string()))?; + + unsafe { + let wallet_ptr = bindings::MONERO_WalletManager_openWallet( + self.ptr.as_ptr(), + c_path.as_ptr(), + c_password.as_ptr(), + network_type.to_c_int(), + ); + + self.throw_if_error(wallet_ptr)?; + if wallet_ptr.is_null() { + Err(self.get_status(wallet_ptr).unwrap_err()) + } else { + // Ensuring that we properly close the wallet when it's no longer needed + let wallet = Wallet { + ptr: NonNull::new(wallet_ptr).unwrap(), + manager: Arc::clone(self), + is_closed: false, + }; + Ok(wallet) + } + } + } + + /// Retrieves the current blockchain height. + /// + /// This method communicates with the connected daemon to obtain the latest + /// blockchain height. It returns a `BlockHeight` on success or a `WalletError` on failure. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// + /// let manager = WalletManager::new().unwrap(); + /// let height = manager.get_height().unwrap(); + /// println!("Current blockchain height: {}", height); + /// ``` + pub fn get_height(&self) -> WalletResult { + unsafe { + let height = bindings::MONERO_WalletManager_blockchainHeight(self.ptr.as_ptr()); + // Assuming the FFI call does not set an error, directly return the height. + // If error handling is required, additional checks should be implemented here. + Ok(BlockHeight { height }) + } + } + + pub fn get_height_target(&self) -> WalletResult { + unsafe { + let target_height = bindings::MONERO_WalletManager_blockTarget(self.ptr.as_ptr()); + Ok(BlockHeight { + height: target_height, + }) + } + } +} + +impl Wallet { + /// Retrieves the wallet's seed with an optional offset. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// + /// // Get seed with no offset + /// let seed = wallet.get_seed(None); + /// assert!(seed.is_ok(), "Failed to get seed: {:?}", seed.err()); + /// let seed = seed.unwrap(); + /// assert!(!seed.is_empty(), "Seed should not be empty"); + /// + /// // Get seed with an offset + /// let seed_with_offset = wallet.get_seed(Some("offset")); + /// assert!(seed_with_offset.is_ok(), "Failed to get seed with offset: {:?}", seed_with_offset.err()); + /// let seed_with_offset = seed_with_offset.unwrap(); + /// assert!(!seed_with_offset.is_empty(), "Seed with offset should not be empty"); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn get_seed(&self, seed_offset: Option<&str>) -> WalletResult { + let c_seed_offset = CString::new(seed_offset.unwrap_or("")) + .map_err(|_| WalletError::FfiError("Invalid seed_offset".to_string()))?; + + unsafe { + let seed_ptr = bindings::MONERO_Wallet_seed(self.ptr.as_ptr(), c_seed_offset.as_ptr()); + + self.throw_if_error()?; + if seed_ptr.is_null() { + return Err(self.get_last_error()); + } + + let seed = CStr::from_ptr(seed_ptr).to_string_lossy().into_owned(); + if seed.is_empty() { + return Err(WalletError::FfiError("Received empty seed".to_string())); + } + + Ok(seed) + } + } + + /// Retrieves the wallet's address for the given account and address index. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet).unwrap(); + /// let address = wallet.get_address(0, 0); + /// assert!(address.is_ok(), "Failed to get address: {:?}", address.err()); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn get_address(&self, account_index: u64, address_index: u64) -> WalletResult { + unsafe { + let address_ptr = + bindings::MONERO_Wallet_address(self.ptr.as_ptr(), account_index, address_index); + + self.throw_if_error()?; + if address_ptr.is_null() { + Err(self.get_last_error()) + } else { + let address = CStr::from_ptr(address_ptr).to_string_lossy().into_owned(); + Ok(address) + } + } + } + + /// Checks if the wallet is deterministic. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// let is_deterministic = wallet.is_deterministic(); + /// assert!(is_deterministic.is_ok(), "Failed to check if wallet is deterministic: {:?}", is_deterministic.err()); + /// assert!(is_deterministic.unwrap(), "Wallet should be deterministic"); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn is_deterministic(&self) -> WalletResult { + unsafe { + let result = bindings::MONERO_Wallet_isDeterministic(self.ptr.as_ptr()); + + self.throw_if_error()?; + Ok(result) + } + } + + /// Retrieves the last error from the wallet. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network, WalletError}; + /// let manager = WalletManager::new().unwrap(); + /// // Intentionally pass an invalid wallet to force an error. + /// let invalid_wallet = manager.create_wallet("", "", "", Network::Mainnet); + /// if let Err(err) = invalid_wallet { + /// if let WalletError::WalletErrorCode(_, error_msg) = err { + /// // Check that an error message was produced + /// assert!(!error_msg.is_empty(), "Error message should not be empty"); + /// } + /// } + /// ``` + pub fn get_last_error(&self) -> WalletError { + unsafe { + let error_ptr = bindings::MONERO_Wallet_errorString(self.ptr.as_ptr()); + let status = bindings::MONERO_Wallet_status(self.ptr.as_ptr()); + + let error_msg = if error_ptr.is_null() { + "Unknown error".to_string() + } else { + CStr::from_ptr(error_ptr).to_string_lossy().into_owned() + }; + + WalletError::WalletErrorCode(status, error_msg) + } + } + + /// Checks for any errors by inspecting the wallet status and throws an error if found. + /// + /// # Returns + /// - `Ok(())` if no error is found. + /// - `Err(WalletError)` if an error is encountered. + pub fn throw_if_error(&self) -> WalletResult<()> { + let status_result = self.manager.get_status(self.ptr.as_ptr()); + if status_result.is_err() { + return status_result; // Return the error if the status is not OK. + } + Ok(()) + } + + /// Retrieves the balance and unlocked balance for the given account index. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network, WalletResult}; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let _wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet).unwrap(); + /// + /// let balance = _wallet.get_balance(0); + /// assert!(balance.is_ok(), "Failed to get balance: {:?}", balance.err()); + /// + /// // Clean up wallet files. + /// std::fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// std::fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn get_balance(&self, account_index: u32) -> WalletResult { + unsafe { + let balance = bindings::MONERO_Wallet_balance(self.ptr.as_ptr(), account_index); + + self.throw_if_error()?; + let unlocked_balance = + bindings::MONERO_Wallet_unlockedBalance(self.ptr.as_ptr(), account_index); + + self.throw_if_error()?; + Ok(GetBalance { + balance, + unlocked_balance, + }) + } + } + + /// Creates a new subaddress account with the given label. + /// + /// # Example + /// + /// ``` + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// // Set up the test environment. + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// // Initialize the wallet manager and create a wallet. + /// let manager = WalletManager::new().unwrap(); + /// let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + /// assert!(wallet_result.is_ok(), "Failed to create wallet: {:?}", wallet_result.err()); + /// let wallet = wallet_result.unwrap(); + /// + /// // Create a new account with a label. + /// let result = wallet.create_account("New Account"); + /// assert!(result.is_ok(), "Failed to create account: {:?}", result.err()); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn create_account(&self, label: &str) -> WalletResult<()> { + let c_label = + CString::new(label).map_err(|_| WalletError::FfiError("Invalid label".to_string()))?; + + unsafe { + bindings::MONERO_Wallet_addSubaddressAccount(self.ptr.as_ptr(), c_label.as_ptr()); + self.throw_if_error() + } + } + + /// Retrieves all accounts associated with the wallet. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet).expect("Failed to create wallet"); + /// + /// // Initially, there should be one account (the primary account). + /// let initial_accounts = wallet.get_accounts().expect("Failed to retrieve accounts"); + /// assert_eq!(initial_accounts.accounts.len(), 1, "Initial account count mismatch"); + /// assert_eq!(initial_accounts.accounts[0].label, "Primary account", "Expected primary account label"); + /// + /// // Create additional accounts. + /// wallet.create_account("Account 1").expect("Failed to create account 1"); + /// wallet.create_account("Account 2").expect("Failed to create account 2"); + /// + /// // Retrieve all accounts again; we should have three now. + /// let all_accounts = wallet.get_accounts().expect("Failed to retrieve all accounts"); + /// assert_eq!(all_accounts.accounts.len(), 3, "Expected 3 accounts after creation"); + /// + /// // Verify the labels of the accounts. + /// assert_eq!(all_accounts.accounts[0].label, "Primary account", "First account should be the primary account"); + /// assert_eq!(all_accounts.accounts[1].label, "Account 1", "Second account should be 'Account 1'"); + /// assert_eq!(all_accounts.accounts[2].label, "Account 2", "Third account should be 'Account 2'"); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn get_accounts(&self) -> WalletResult { + unsafe { + let accounts_size = bindings::MONERO_Wallet_numSubaddressAccounts(self.ptr.as_ptr()); + self.throw_if_error()?; + + let mut accounts = Vec::new(); + + for i in 0..accounts_size as u32 { + let label_ptr = bindings::MONERO_Wallet_getSubaddressLabel(self.ptr.as_ptr(), i, 0); + let label = if label_ptr.is_null() { + "Unnamed".to_string() + } else { + CStr::from_ptr(label_ptr).to_string_lossy().into_owned() + }; + + let balance = bindings::MONERO_Wallet_balance(self.ptr.as_ptr(), i); + let unlocked_balance = + bindings::MONERO_Wallet_unlockedBalance(self.ptr.as_ptr(), i); + + accounts.push(Account { + index: i, + label, + balance, + unlocked_balance, + }); + } + + Ok(GetAccounts { accounts }) + } + } + + /// Closes the wallet, releasing any resources associated with it. + /// + /// After calling this method, the `Wallet` instance should no longer be used. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network, WalletResult}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let mut wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet).unwrap(); + /// + /// // Use the wallet for operations... + /// + /// // Now close the wallet + /// let close_result = wallet.close_wallet(); + /// assert!(close_result.is_ok(), "Failed to close wallet: {:?}", close_result.err()); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn close_wallet(&mut self) -> WalletResult<()> { + if self.is_closed { + return Ok(()); + } + unsafe { + let result = bindings::MONERO_WalletManager_closeWallet( + self.manager.ptr.as_ptr(), + self.ptr.as_ptr(), + false, // Don't save the wallet by default. + ); + if result { + self.is_closed = true; + Ok(()) + } else { + Err(WalletError::FfiError("Failed to close wallet".to_string())) + } + } + } + + /// Initializes the wallet with the provided daemon settings. + /// + /// This method must be called after creating or opening a wallet to synchronize it + /// with the daemon and prepare it for operations like refreshing. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network, WalletConfig}; + /// use tempfile::TempDir; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet) + /// .expect("Failed to create wallet"); + /// + /// let config = WalletConfig { + /// daemon_address: "http://localhost:18081".to_string(), + /// upper_transaction_size_limit: 10000, + /// daemon_username: "user".to_string(), + /// daemon_password: "pass".to_string(), + /// use_ssl: false, + /// light_wallet: false, + /// proxy_address: "".to_string(), + /// }; + /// + /// let init_result = wallet.init(config); + /// assert!(init_result.is_ok(), "Failed to initialize wallet: {:?}", init_result.err()); + /// ``` + pub fn init(&self, config: WalletConfig) -> WalletResult<()> { + // Store original address for debugging + let original_address = config.daemon_address.clone(); + + let c_daemon_address = CString::new(config.daemon_address) + .map_err(|_| WalletError::FfiError("Invalid daemon address".to_string()))?; + let c_daemon_username = CString::new(config.daemon_username) + .map_err(|_| WalletError::FfiError("Invalid daemon username".to_string()))?; + let c_daemon_password = CString::new(config.daemon_password) + .map_err(|_| WalletError::FfiError("Invalid daemon password".to_string()))?; + let c_proxy_address = CString::new(config.proxy_address) + .map_err(|_| WalletError::FfiError("Invalid proxy address".to_string()))?; + + unsafe { + // Debug print the daemon address before conversion + println!("Original daemon address: {}", original_address); + + // Print the CString pointer and contents + let daemon_addr_ptr = c_daemon_address.as_ptr(); + println!("Daemon address CString pointer: {:p}", daemon_addr_ptr); + println!( + "Daemon address contents: {}", + CStr::from_ptr(daemon_addr_ptr).to_string_lossy() + ); + + let c_empty = CString::new("").unwrap(); + let c_log_tag = CString::new("moneroc").unwrap(); + + // Debug print empty and log tag pointers + println!("Empty string pointer: {:p}", c_empty.as_ptr()); + println!("Log tag pointer: {:p}", c_log_tag.as_ptr()); + + // Store raw pointers for debugging after FFI calls + let raw_daemon_addr = c_daemon_address.into_raw(); + println!("Raw daemon address pointer: {:p}", raw_daemon_addr); + + // Verify contents right before FFI call + println!( + "Raw daemon address contents: {}", + CStr::from_ptr(raw_daemon_addr).to_string_lossy() + ); + + bindings::MONERO_Wallet_init3( + self.ptr.as_ptr(), + c_empty.clone().into_raw(), // Will be freed by C code + c_log_tag.into_raw(), // Will be freed by C code + c_empty.into_raw(), // Will be freed by C code + true, + ); + + let result = bindings::MONERO_Wallet_init( + self.ptr.as_ptr(), + raw_daemon_addr, // Using our stored raw pointer + config.upper_transaction_size_limit, + c_daemon_username.into_raw(), // Will be freed by C code + c_daemon_password.into_raw(), // Will be freed by C code + config.use_ssl, + config.light_wallet, + c_proxy_address.into_raw(), // Will be freed by C code + ); + + // Try to peek at the contents after FFI call (this is unsafe and just for debugging) + println!( + "Attempting to read daemon address after FFI call: {}", + CStr::from_ptr(raw_daemon_addr).to_string_lossy() + ); + + if result { + Ok(()) + } else { + // Print the error if initialization fails + let error = self.get_last_error(); + println!("Initialization failed with error: {:?}", error); + Err(error) + } + } + } + + /// Refreshes the wallet's state by synchronizing it with the blockchain. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network, WalletConfig}; + /// use std::fs; + /// use tempfile::TempDir; + /// + /// fn main() { + /// // Create a temporary directory for testing purposes. + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string"); + /// + /// // Initialize the WalletManager. + /// let manager = WalletManager::new().expect("Failed to create WalletManager"); + /// + /// // Create a new wallet. + /// let wallet = manager + /// .create_wallet(wallet_str, "password", "English", Network::Mainnet) + /// .expect("Failed to create wallet"); + /// + /// // Define the wallet initialization configuration. + /// let config = WalletConfig { + /// daemon_address: "http://localhost:18081".to_string(), + /// upper_transaction_size_limit: 10000, + /// daemon_username: "user".to_string(), + /// daemon_password: "pass".to_string(), + /// use_ssl: false, + /// light_wallet: false, + /// proxy_address: "".to_string(), + /// }; + /// + /// // Initialize the wallet with the specified configuration. + /// let init_result = wallet.init(config); + /// assert!(init_result.is_ok(), "Failed to initialize wallet: {:?}", init_result.err()); + /// + /// // Perform a refresh operation after initialization. + /// let refresh_result = wallet.refresh(); + /// assert!(refresh_result.is_ok(), "Failed to refresh wallet: {:?}", refresh_result.err()); + /// + /// // Optionally, you can verify the refresh by checking the blockchain height or other metrics. + /// // For example: + /// let height = manager.get_height().expect("Failed to get blockchain height"); + /// println!("Current blockchain height: {}", height); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// } + /// ``` + pub fn refresh(&self) -> WalletResult { + unsafe { + let result = bindings::MONERO_Wallet_refresh(self.ptr.as_ptr()); + + if result { + Ok(Refreshed) + } else { + // Retrieve the last error from the wallet + Err(self.get_last_error()) + } + } + } + + pub fn refresh_async(&self) -> WalletResult { + unsafe { + bindings::MONERO_Wallet_refreshAsync(self.ptr.as_ptr()); + return Ok(Refreshed); + } + } + + pub fn get_blockchain_height(&self) -> WalletResult { + unsafe { + let height = bindings::MONERO_Wallet_blockChainHeight(self.ptr.as_ptr()); + Ok(BlockHeight { height }) + } + } + + /// Initiates a transfer from the wallet to the specified destinations. + /// + /// # Returns + /// + /// * `WalletResult` - On success, returns a `Transfer` struct containing transaction details. + /// On failure, returns a `WalletError`. + pub fn transfer( + &self, + account_index: u32, + destinations: Vec, + get_tx_key: bool, + sweep_all: bool, + ) -> WalletResult { + // Define separators + let separator = ";"; + let separator_c = CString::new(separator) + .map_err(|_| WalletError::FfiError("Invalid separator".to_string()))?; + + // Concatenate destination addresses and amounts. + let addresses: Vec = destinations.iter().map(|d| d.address.clone()).collect(); + let address_list = addresses.join(separator); + let c_address_list = CString::new(address_list) + .map_err(|_| WalletError::FfiError("Invalid address list".to_string()))?; + + let amounts: Vec = destinations.iter().map(|d| d.amount.to_string()).collect(); + let amount_list = amounts.join(separator); + let c_amount_list = CString::new(amount_list) + .map_err(|_| WalletError::FfiError("Invalid amount list".to_string()))?; + + // TODO: Payment IDs. + let payment_id = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid payment_id".to_string()))?; + let mixin_count = 16; + + // Pending transaction priority - default to 0 (Default) + let pending_tx_priority = bindings::Priority_Default; + + // Subaddress account + let subaddr_account = account_index; + + // TODO: Preferred inputs. + let c_preferred_inputs = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid preferred inputs".to_string()))?; + + // Separator for preferred inputs + let preferred_inputs_separator = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid preferred inputs separator".to_string()))?; + + unsafe { + // Create the transaction with multiple destinations. + let tx_ptr = bindings::MONERO_Wallet_createTransactionMultDest( + self.ptr.as_ptr(), + c_address_list.as_ptr(), + separator_c.as_ptr(), + payment_id.as_ptr(), + sweep_all, + c_amount_list.as_ptr(), + separator_c.as_ptr(), + mixin_count, + pending_tx_priority, + subaddr_account, + c_preferred_inputs.as_ptr(), + preferred_inputs_separator.as_ptr(), + ); + + // Check for errors. + let ptr_as_mut_c_void = self.manager.ptr.as_ptr() as *mut c_void; + self.manager.throw_if_error(ptr_as_mut_c_void)?; + if tx_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + // Get the transaction ID. + let txid_ptr = bindings::MONERO_PendingTransaction_txid(tx_ptr, separator_c.as_ptr()); + if txid_ptr.is_null() { + return Err(WalletError::FfiError( + "Failed to get transaction ID".to_string(), + )); + } + let txid = CStr::from_ptr(txid_ptr).to_string_lossy().into_owned(); + + // Get the fee. + let fee = bindings::MONERO_PendingTransaction_fee(tx_ptr); + + // Optionally get the transaction key. + let tx_key = if get_tx_key { + let c_txid = CString::new(txid.clone()) + .map_err(|_| WalletError::FfiError("Invalid txid".to_string()))?; + let tx_key_ptr = + bindings::MONERO_Wallet_getTxKey(self.ptr.as_ptr(), c_txid.as_ptr()); + + if tx_key_ptr.is_null() { + None + } else { + let tx_key = CStr::from_ptr(tx_key_ptr).to_string_lossy().into_owned(); + let tx_key = monero::PrivateKey::from_str(tx_key.as_str()).unwrap(); + Some(tx_key) + } + } else { + None + }; + + // Submit the transaction. + // + // TODO: Make submission optional. + let tx_ptr_as_i8 = tx_ptr as *const i8; + let submit_result = + bindings::MONERO_Wallet_submitTransaction(self.ptr.as_ptr(), tx_ptr_as_i8); + if !submit_result { + return Err(WalletError::FfiError( + "Failed to submit transaction".to_string(), + )); + } + + Ok(Transfer { + txid, + tx_key, + amount: destinations.iter().map(|d| d.amount).sum(), + fee, + }) + } + } + + /// Transfers `amount` monero from `account_index` to `address`. + pub async fn transfer_single( + &self, + account_index: u32, + amount: u64, + address: &str, + ) -> WalletResult { + let dest = vec![Destination { + amount, + address: address.to_owned(), + }]; + + Ok(self.transfer(account_index, dest, true, false)?) + } + + /// Sweep all funds from the specific account to the specified destination. + /// + /// TODO: Example / docs-tests. + pub fn sweep_all( + &self, + account_index: u32, + destination: monero::Address, + get_tx_key: bool, + ) -> WalletResult { + // Convert the destination address to a CString. + let c_address = CString::new(destination.to_string()) + .map_err(|_| WalletError::FfiError("Invalid address".to_string()))?; + + // Placeholder values for fields not needed in sweep_all. + let empty_separator = + CString::new("").map_err(|_| WalletError::FfiError("Invalid separator".to_string()))?; + let payment_id = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid payment_id".to_string()))?; + let mixin_count = 16; + let pending_tx_priority = bindings::Priority_Default; + let c_preferred_inputs = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid preferred inputs".to_string()))?; + let preferred_inputs_separator = CString::new("") + .map_err(|_| WalletError::FfiError("Invalid preferred inputs separator".to_string()))?; + + unsafe { + // Create the sweep transaction. + let tx_ptr = bindings::MONERO_Wallet_createTransactionMultDest( + self.ptr.as_ptr(), + c_address.as_ptr(), + empty_separator.as_ptr(), + payment_id.as_ptr(), + true, // Sweep all funds. + empty_separator.as_ptr(), + empty_separator.as_ptr(), + mixin_count, + pending_tx_priority, + account_index, + c_preferred_inputs.as_ptr(), + preferred_inputs_separator.as_ptr(), + ); + + // Check for errors. + let ptr_as_mut_c_void = self.manager.ptr.as_ptr() as *mut c_void; + self.manager.throw_if_error(ptr_as_mut_c_void)?; + if tx_ptr.is_null() { + return Err(WalletError::NullPointer); + } + + // Get the transaction ID. + let txid_ptr = + bindings::MONERO_PendingTransaction_txid(tx_ptr, empty_separator.as_ptr()); + if txid_ptr.is_null() { + return Err(WalletError::FfiError( + "Failed to get transaction ID".to_string(), + )); + } + let txid = CStr::from_ptr(txid_ptr).to_string_lossy().into_owned(); + + // Get the fee. + let fee = bindings::MONERO_PendingTransaction_fee(tx_ptr); + + // Optionally get the transaction key. + let tx_key = if get_tx_key { + let c_txid = CString::new(txid.clone()) + .map_err(|_| WalletError::FfiError("Invalid txid".to_string()))?; + let tx_key_ptr = + bindings::MONERO_Wallet_getTxKey(self.ptr.as_ptr(), c_txid.as_ptr()); + if tx_key_ptr.is_null() { + None + } else { + let tx_key = CStr::from_ptr(tx_key_ptr).to_string_lossy().into_owned(); + let tx_key = monero::PrivateKey::from_str(tx_key.as_str()).unwrap(); + Some(tx_key) + } + } else { + None + }; + + // Submit the transaction. + // + // TODO: Make submission optional. + let tx_ptr_as_i8 = tx_ptr as *const i8; + let submit_result = + bindings::MONERO_Wallet_submitTransaction(self.ptr.as_ptr(), tx_ptr_as_i8); + if !submit_result { + return Err(WalletError::FfiError( + "Failed to submit sweep transaction".to_string(), + )); + } + + Ok(Transfer { + txid, + tx_key, + amount: 0, // Since it's sweeping all, amount is not predefined. + fee, + }) + } + } + + /// Sets the seed language for the wallet. + /// + /// # Example + /// + /// ```rust + /// use monero_c_rust::{WalletManager, Network}; + /// use tempfile::TempDir; + /// use std::fs; + /// + /// let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + /// let wallet_path = temp_dir.path().join("test_wallet"); + /// let wallet_str = wallet_path.to_str().unwrap(); + /// + /// let manager = WalletManager::new().unwrap(); + /// let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet).unwrap(); + /// + /// // Change the seed language to Spanish + /// let result = wallet.set_seed_language("Spanish"); + /// assert!(result.is_ok(), "Failed to set seed language: {:?}", result.err()); + /// + /// // Clean up wallet files. + /// fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + /// fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + /// ``` + pub fn set_seed_language(&self, language: &str) -> WalletResult<()> { + let c_language = CString::new(language) + .map_err(|_| WalletError::FfiError("Invalid language string".to_string()))?; + + unsafe { + bindings::MONERO_Wallet_setSeedLanguage(self.ptr.as_ptr(), c_language.as_ptr()); + self.throw_if_error() + } + } + + /// Checks the validity of a transaction key for a given transaction ID and address. + /// + /// This method verifies whether the provided transaction key (`tx_key`) is valid for the + /// specified transaction ID (`txid`) and address (`address`). If valid, it returns the + /// amount received, whether the transaction is in the pool, and the number of confirmations. + /// + /// TODO: Example / docs-tests. + pub fn check_tx_key( + &self, + txid: String, + tx_key: String, + address: String, + ) -> WalletResult { + // Convert Rust strings to C-compatible strings. + let c_txid = CString::new(txid) + .map_err(|_| WalletError::FfiError("Invalid txid string".to_string()))?; + let c_tx_key = CString::new(tx_key) + .map_err(|_| WalletError::FfiError("Invalid tx_key string".to_string()))?; + let c_address = CString::new(address) + .map_err(|_| WalletError::FfiError("Invalid address string".to_string()))?; + + // Assign default values if optional parameters are not provided. + let mut received_val = 0; + let mut in_pool_val = false; + let mut confirmations_val = 0; + + // Call the C function. + let result = unsafe { + bindings::MONERO_Wallet_checkTxKey( + self.ptr.as_ptr(), + c_txid.as_ptr(), + c_tx_key.as_ptr(), + c_address.as_ptr(), + &mut received_val, + &mut in_pool_val, + &mut confirmations_val, + ) + }; + + if result { + Ok(CheckTxKey { + received: received_val, + in_pool: in_pool_val, + confirmations: confirmations_val, + }) + } else { + // Retrieve the last error. + Err(WalletError::FfiError( + "Transaction key is invalid.".to_string(), + )) + } + } +} + +#[derive(Debug)] +pub struct GetBalance { + pub balance: u64, + pub unlocked_balance: u64, +} + +impl fmt::Display for GetBalance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut total = Decimal::from(self.balance); + total + .set_scale(12) + .expect("12 is smaller than max precision of 28"); + + let mut unlocked = Decimal::from(self.unlocked_balance); + unlocked + .set_scale(12) + .expect("12 is smaller than max precision of 28"); + + write!( + f, + "total balance: {}, unlocked balance: {}", + total, unlocked + ) + } +} + +impl Drop for Wallet { + fn drop(&mut self) { + if !self.is_closed { + let _ = self.close_wallet(); + } + } +} + +#[cfg(test)] +use std::fs; +#[cfg(test)] +use tempfile::TempDir; + +#[cfg(test)] +fn check_and_delete_existing_wallets(temp_dir: &TempDir) -> std::io::Result<()> { + let test_wallet_names = &[ + "test_wallet", + "mainnet_wallet", + "testnet_wallet", + "stagenet_wallet", + ]; + + for name in test_wallet_names { + let wallet_file = temp_dir.path().join(name); + let keys_file = temp_dir.path().join(format!("{}.keys", name)); + + if wallet_file.exists() { + fs::remove_file(&wallet_file)?; + } + if keys_file.exists() { + fs::remove_file(&keys_file)?; + } + } + Ok(()) +} + +#[cfg(test)] +fn setup() -> WalletResult<(Arc, TempDir)> { + let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + check_and_delete_existing_wallets(&temp_dir).expect("Failed to clean up existing wallets"); + + let manager = WalletManager::new()?; + Ok((manager, temp_dir)) +} + +#[cfg(test)] +fn teardown(temp_dir: &TempDir) -> std::io::Result<()> { + check_and_delete_existing_wallets(temp_dir) +} + +#[test] +fn test_wallet_manager_creation() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + assert!(wallet_result.is_ok(), "WalletManager creation failed"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_creation() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + assert!(wallet.is_ok(), "Failed to create wallet"); + + let wallet = wallet.unwrap(); + + assert!( + wallet.is_deterministic().is_ok(), + "Wallet creation seems to have failed" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_seed() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a new wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Test getting seed with no offset (None). + let result = wallet.get_seed(None); + assert!( + result.is_ok(), + "Failed to get seed without offset: {:?}", + result.err() + ); + assert!(!result.unwrap().is_empty(), "Seed without offset is empty"); + + // Test getting seed with a specific offset (Some("offset")). + let result_with_offset = wallet.get_seed(Some("offset")); + assert!( + result_with_offset.is_ok(), + "Failed to get seed with offset: {:?}", + result_with_offset.err() + ); + assert!( + !result_with_offset.unwrap().is_empty(), + "Seed with offset is empty" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_address() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + let result = wallet.get_address(0, 0); + assert!(result.is_ok(), "Failed to get address: {:?}", result.err()); + assert!(!result.unwrap().is_empty(), "Address is empty"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_is_deterministic() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + let result = wallet.is_deterministic(); + assert!( + result.is_ok(), + "Failed to check if wallet is deterministic: {:?}", + result.err() + ); + assert!(result.unwrap(), "Wallet should be deterministic"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_creation_with_different_networks() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallets = vec![ + ("mainnet_wallet", Network::Mainnet), + ("testnet_wallet", Network::Testnet), + ("stagenet_wallet", Network::Stagenet), + ]; + + for (name, net_type) in wallets { + let wallet_path = temp_dir.path().join(name); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.create_wallet(wallet_str, "password", "English", net_type); + assert!(wallet.is_ok(), "Failed to create wallet: {}", name); + } + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_restore_mnemonic_success() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + + // Example mnemonic seed (ensure this is a valid seed for your context). + let mnemonic_seed = "hemlock jubilee eden hacksaw boil superior inroads epoxy exhale orders cavernous second brunt saved richly lower upgrade hitched launching deepest mostly playful layout lower eden".to_string(); + + let wallet = manager.restore_mnemonic( + wallet_str.clone(), + "password".to_string(), + mnemonic_seed, + Network::Mainnet, + 0, // Restore from the beginning of the blockchain. + 1, // Default KDF rounds. + "".to_string(), // No seed offset. + ); + assert!( + wallet.is_ok(), + "Failed to restore wallet: {:?}", + wallet.err() + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} +// TODO: Test with offset. + +#[test] +fn test_restore_polyseed_success() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + let polyseed = "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(); + + let restored_wallet = manager.restore_polyseed( + wallet_str.clone(), + "password".to_string(), + polyseed.clone(), + Network::Mainnet, + 0, // Restore from the beginning of the blockchain. + 1, // Default KDF rounds. + "".to_string(), // No seed offset. + true, // Create a new wallet. + ); + assert!( + restored_wallet.is_ok(), + "Failed to restore wallet from polyseed: {:?}", + restored_wallet.err() + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_generate_from_keys_unit() { + println!("Running unit test: test_generate_from_keys_unit"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("generated_wallet_unit"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Test parameters. + // + // TODO add functions to get spend and view keys. + let address = "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi"; + let spendkey = "29adefc8f67515b4b4bf48031780ab9d071d24f8a674b879ce7f245c37523807"; + let viewkey = "3bc0b202cde92fe5719c3cc0a16aa94f88a5d19f8c515d4e35fae361f6f2120e"; + let restore_height = 0; + let password = "password"; + let language = "English"; + let network_type = Network::Mainnet; + let kdf_rounds = 1; + + let result = manager.generate_from_keys( + wallet_str.to_string(), + address.to_string(), + spendkey.to_string(), + viewkey.to_string(), + restore_height, + password.to_string(), + language.to_string(), + network_type, + kdf_rounds, + ); + assert!( + result.is_ok(), + "Failed to generate wallet from keys: {:?}", + result.err() + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_multiple_address_generation() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + for i in 0..5 { + let result = wallet.get_address(0, i); + assert!( + result.is_ok(), + "Failed to get address {}: {:?}", + i, + result.err() + ); + assert!(!result.unwrap().is_empty(), "Address {} is empty", i); + } + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_error_display() { + // Test WalletError::FfiError variant. + let error = WalletError::FfiError("Test error".to_string()); + match error { + WalletError::FfiError(msg) => assert_eq!(msg, "Test error"), + _ => panic!("Expected FfiError variant"), + } + + // Test WalletError::NullPointer variant. + let error = WalletError::NullPointer; + match error { + WalletError::NullPointer => assert!(true), + _ => panic!("Expected NullPointer variant"), + } + + // Test WalletError::WalletErrorCode variant. + let error = WalletError::WalletErrorCode(2, "Sample wallet error".to_string()); + match error { + WalletError::WalletErrorCode(code, msg) => { + assert_eq!(code, 2); + assert_eq!(msg, "Sample wallet error"); + } + _ => panic!("Expected WalletErrorCode variant"), + } +} + +#[test] +fn test_wallet_status() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet to use for status checking + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Check the status of the wallet, expecting it to be OK + let status_result = manager.get_status(wallet.ptr.as_ptr()); + assert!( + status_result.is_ok(), + "Failed to get status: {:?}", + status_result.err() + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_open_wallet() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet to be opened later + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Drop the wallet so it can be opened later + drop(wallet); + + // Try to open the wallet + let open_result = manager.open_wallet(wallet_str, "password", Network::Mainnet); + assert!( + open_result.is_ok(), + "Failed to open wallet: {:?}", + open_result.err() + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_balance() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .unwrap(); + + let balance_result = wallet.get_balance(0); + assert!( + balance_result.is_ok(), + "Failed to get balance: {:?}", + balance_result.err() + ); + + let _balance = balance_result.unwrap(); + // assert!(_balance.balance >= 0, "Balance should be non-negative"); + // assert!(_balance.unlocked_balance >= 0, "Unlocked balance should be non-negative"); + // These assertions are meaningless with the constraints of the type. + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_create_account() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Create a new account. + let result = wallet.create_account("Test Account"); + assert!( + result.is_ok(), + "Failed to create account: {:?}", + result.err() + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_accounts() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Add two accounts for testing + wallet + .create_account("Test Account 1") + .expect("Failed to create account 1"); + wallet + .create_account("Test Account 2") + .expect("Failed to create account 2"); + + // Retrieve all accounts + let accounts = wallet.get_accounts().expect("Failed to retrieve accounts"); + assert_eq!(accounts.accounts.len(), 3); // Including the primary account + + // Check account names + assert_eq!(accounts.accounts[0].label, "Primary account"); + assert_eq!(accounts.accounts[1].label, "Test Account 1"); + assert_eq!(accounts.accounts[2].label, "Test Account 2"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_close_wallet() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet. + let mut wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Close the wallet. + let close_result = wallet.close_wallet(); + assert!( + close_result.is_ok(), + "Failed to close wallet: {:?}", + close_result.err() + ); + + // Attempt to close the wallet again. + let close_again_result = wallet.close_wallet(); + assert!( + close_again_result.is_ok(), + "Failed to close wallet a second time: {:?}", + close_again_result.err() + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_height_success() { + let manager = WalletManager::new().unwrap(); + let height = manager.get_height().unwrap(); + // assert!(height > 0, "Blockchain height should be greater than 0"); + // The test should not assume network connectivity/any syncing progress, so: + assert!(height == 0, "Blockchain height should be equal to 0"); + } +} + +#[test] +fn test_init_success() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Define initialization configuration. + let config = WalletConfig { + daemon_address: "http://localhost:18081".to_string(), + upper_transaction_size_limit: 10000, + daemon_username: "user".to_string(), + daemon_password: "pass".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + }; + + // Initialize the wallet. + let init_result = wallet.init(config); + assert!( + init_result.is_ok(), + "Failed to initialize wallet: {:?}", + init_result.err() + ); + + // Clean up wallet files. + fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_refresh_success() { + println!("Running test_refresh_success"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Wallet created successfully."); + + // Define initialization configuration. + let config = WalletConfig { + daemon_address: "http://localhost:18081".to_string(), + upper_transaction_size_limit: 10000, + daemon_username: "user".to_string(), + daemon_password: "pass".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + }; + + // Perform the initialization. + println!("Initializing the wallet..."); + let init_result = wallet.init(config); + + assert!( + init_result.is_ok(), + "Failed to initialize wallet: {:?}", + init_result.err() + ); + + // Perform a refresh operation after initialization. + println!("Refreshing the wallet..."); + let refresh_result = wallet.refresh(); + assert!( + refresh_result.is_ok(), + "Failed to refresh wallet: {:?}", + refresh_result.err() + ); + + // Clean up wallet files. + fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_set_seed_language() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet_set_seed_language"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a new wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Set the seed language to Spanish. + let result = wallet.set_seed_language("Spanish"); + assert!( + result.is_ok(), + "Failed to set seed language: {:?}", + result.err() + ); + + // Optionally, retrieve the seed language to verify it was set correctly. + // This requires implementing a corresponding `get_seed_language` method. + // For now, we'll assume that if no error was returned, the operation was successful. + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_check_tx_key() { + let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + + let mnemonic_seed = "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(); + let passphrase = "".to_string(); + + // Restore the wallet using polyseed. + let wallet = WalletManager::new() + .expect("Failed to create WalletManager") + .restore_polyseed( + wallet_str.clone(), + "password".to_string(), + mnemonic_seed.clone(), + Network::Mainnet, + 0, + 1, + passphrase.clone(), + true, + ) + .expect("Failed to restore wallet from polyseed"); + + // Print the primary address. + println!( + "Primary address: {}", + wallet.get_address(0, 0).expect("Failed to get address") + ); + + // Valid transaction details. + let valid_txid = "b3f1b71f5127f9d655e58f7a2b324a64bfbc5a3ea1ce8846a0f4c51cbcb87ea6".to_string(); + let valid_tx_key = + "48ef9d8b772c4f5097e29a4ba413605497d978c74e879fda67545dddff312b0a".to_string(); + let valid_address = "465cUW8wTMSCV8oVVh7CuWWHs7yeB1oxhNPrsEM5FKSqadTXmobLqsNEtRnyGsbN1rbDuBtWdtxtXhTJda1Lm9vcH2ZdrD1".to_string(); + + // Check the transaction key. + let valid_check = wallet.check_tx_key( + valid_txid.clone(), + valid_tx_key.clone(), + valid_address.clone(), + Some(1), + Some(false), + Some(10), + ); + + match valid_check { + Ok(check) => { + assert!(check.valid, "Valid transaction key should be valid."); + assert!( + check.error.is_none(), + "There should be no error for valid transaction key." + ); + println!("Valid transaction key check passed."); + } + Err(e) => { + panic!("Error checking valid transaction key: {:?}", e); + } + } + + // Clean up wallet files. + fs::remove_file(&wallet_path).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_path.display())) + .expect("Failed to delete test wallet keys"); +} + +#[test] +fn test_invalid_check_tx_key() { + let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + + let mnemonic_seed = "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(); + let passphrase = "".to_string(); + + // Restore the wallet using polyseed. + let wallet = WalletManager::new() + .expect("Failed to create WalletManager") + .restore_polyseed( + wallet_str.clone(), + "password".to_string(), + mnemonic_seed.clone(), + Network::Mainnet, + 0, + 1, + passphrase.clone(), + true, + ) + .expect("Failed to restore wallet from polyseed"); + + // Print the primary address. + println!( + "Primary address: {}", + wallet.get_address(0, 0).expect("Failed to get address") + ); + + // Invalid transaction details. + let invalid_txid = "invalid_tx_id".to_string(); + let invalid_tx_key = "invalid_tx_key".to_string(); + let invalid_address = "invalid_address".to_string(); + + // Check the invalid transaction key. + let invalid_check = wallet.check_tx_key( + invalid_txid.clone(), + invalid_tx_key.clone(), + invalid_address.clone(), + Some(1), + Some(false), + Some(10), + ); + + match invalid_check { + Ok(check) => { + assert!(!check.valid, "Invalid transaction key should be invalid."); + assert!( + check.error.is_some(), + "There should be an error message for invalid transaction key." + ); + println!("Invalid transaction key check correctly identified as invalid."); + } + Err(e) => { + println!("Expected error for invalid transaction key: {:?}", e); + } + } + + // Clean up wallet files. + fs::remove_file(&wallet_path).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_path.display())) + .expect("Failed to delete test wallet keys"); +} + +// Add these markers to make NonNull safe to share between threads +unsafe impl Send for WalletManager {} +unsafe impl Sync for WalletManager {} +unsafe impl Send for Wallet {} +unsafe impl Sync for Wallet {} diff --git a/monero-native/tests/integration_tests.rs b/monero-native/tests/integration_tests.rs new file mode 100644 index 0000000000..ce1a36c77e --- /dev/null +++ b/monero-native/tests/integration_tests.rs @@ -0,0 +1,1008 @@ +use monero_c_rust::{ + Network, WalletConfig, WalletError, WalletManager, WalletResult, WalletStatus_Ok, +}; +use std::fs; +use std::sync::Arc; +use std::time::Instant; +use tempfile::TempDir; + +const TEST_WALLET_NAMES: &[&str] = &[ + "test_wallet", + "mainnet_wallet", + "testnet_wallet", + "stagenet_wallet", +]; + +/// Helper function to clean up existing wallet files in a temporary directory. +fn check_and_delete_existing_wallets(temp_dir: &TempDir) -> std::io::Result<()> { + for name in TEST_WALLET_NAMES { + // Construct absolute paths for wallet files. + let wallet_file = temp_dir.path().join(name); + let keys_file = temp_dir.path().join(format!("{}.keys", name)); + let address_file = temp_dir.path().join(format!("{}.address.txt", name)); // Added + + // Delete wallet file if it exists. + if wallet_file.exists() { + if let Err(e) = fs::remove_file(&wallet_file) { + println!( + "Warning: Failed to delete wallet file {:?}: {}", + wallet_file, e + ); + } else { + println!("Deleted existing wallet file: {:?}", wallet_file); + } + } + + // Delete keys file if it exists. + if keys_file.exists() { + if let Err(e) = fs::remove_file(&keys_file) { + println!("Warning: Failed to delete keys file {:?}: {}", keys_file, e); + } else { + println!("Deleted existing keys file: {:?}", keys_file); + } + } + + // Delete address file if it exists. + if address_file.exists() { + if let Err(e) = fs::remove_file(&address_file) { + println!( + "Warning: Failed to delete address file {:?}: {}", + address_file, e + ); + } else { + println!("Deleted existing address file: {:?}", address_file); + } + } + } + Ok(()) +} + +/// Sets up the test environment by creating a temporary directory and initializing the WalletManager. +/// +/// Returns: +/// - An `Arc` wrapped `WalletManager` instance. +/// - A `TempDir` representing the temporary directory. +fn setup() -> WalletResult<(Arc, TempDir)> { + println!("Setting up test environment..."); + let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + check_and_delete_existing_wallets(&temp_dir).expect("Failed to clean up existing wallets"); + + println!("Creating WalletManager..."); + let start = Instant::now(); + let manager = WalletManager::new()?; + println!("WalletManager creation took {:?}", start.elapsed()); + + Ok((manager, temp_dir)) +} + +/// Tears down the test environment by deleting wallet files. +/// +/// Args: +/// - `temp_dir`: Reference to the temporary directory. +/// +/// Returns: +/// - `Result<(), std::io::Error>` indicating success or failure. +fn teardown(temp_dir: &TempDir) -> std::io::Result<()> { + println!("Tearing down test environment..."); + check_and_delete_existing_wallets(temp_dir) +} + +#[test] +fn test_wallet_manager_creation() { + println!("Running test_wallet_manager_creation"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet_result = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + assert!( + wallet_result.is_ok(), + "WalletManager creation seems to have failed" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_creation() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.create_wallet(wallet_str, "password", "English", Network::Mainnet); + assert!(wallet.is_ok(), "Failed to create wallet"); + let wallet = wallet.unwrap(); + assert!( + wallet.is_deterministic().is_ok(), + "Wallet creation seems to have failed" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_restore_mnemonic_integration() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + let mnemonic_seed = "hemlock jubilee eden hacksaw boil superior inroads epoxy exhale orders cavernous second brunt saved richly lower upgrade hitched launching deepest mostly playful layout lower eden".to_string(); + + let restored_wallet = manager.restore_mnemonic( + wallet_str.clone(), + "password".to_string(), + mnemonic_seed, + Network::Mainnet, + 0, // Restore from the beginning of the blockchain. + 1, // Default KDF rounds. + "".to_string(), // No seed offset. + ); + + assert!( + restored_wallet.is_ok(), + "Failed to restore wallet: {:?}", + restored_wallet.err() + ); + + // Check that the wallet is deterministic. + let wallet = restored_wallet.unwrap(); + assert!( + wallet.is_deterministic().is_ok(), + "Restored wallet seems to have failed" + ); + assert!( + wallet.is_deterministic().unwrap(), + "Restored wallet should be deterministic" + ); + + // Optionally, verify the address if applicable. + let address_result = wallet.get_address(0, 0); + assert!( + address_result.is_ok(), + "Failed to retrieve address: {:?}", + address_result.err() + ); + let address = address_result.unwrap(); + assert_eq!( + address, + "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi", + "Address does not match expected value" + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} +// TODO: Test with offset. + +#[test] +fn test_restore_polyseed_integration() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string") + .to_string(); + let mnemonic_seed = "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(); + + let restored_wallet = manager.restore_polyseed( + wallet_str.clone(), + "password".to_string(), + mnemonic_seed, + Network::Mainnet, + 0, // Restore from the beginning of the blockchain. + 1, // Default KDF rounds. + "".to_string(), // No seed offset. + true, // Create a new wallet. + ); + + assert!( + restored_wallet.is_ok(), + "Failed to restore wallet: {:?}", + restored_wallet.err() + ); + + // Check that the wallet is deterministic. + let wallet = restored_wallet.unwrap(); + assert!( + wallet.is_deterministic().is_ok(), + "Restored wallet seems to have failed" + ); + assert!( + wallet.is_deterministic().unwrap(), + "Restored wallet should be deterministic" + ); + + // Optionally, verify the address if applicable. + let address_result = wallet.get_address(0, 0); + assert!( + address_result.is_ok(), + "Failed to retrieve address: {:?}", + address_result.err() + ); + let address = address_result.unwrap(); + assert_eq!( + address, + "465cUW8wTMSCV8oVVh7CuWWHs7yeB1oxhNPrsEM5FKSqadTXmobLqsNEtRnyGsbN1rbDuBtWdtxtXhTJda1Lm9vcH2ZdrD1", + "Address does not match expected value" + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_generate_from_keys_integration() { + println!("Running test_generate_from_keys_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.generate_from_keys( + wallet_str.to_string(), + "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi".to_string(), + "29adefc8f67515b4b4bf48031780ab9d071d24f8a674b879ce7f245c37523807".to_string(), + "3bc0b202cde92fe5719c3cc0a16aa94f88a5d19f8c515d4e35fae361f6f2120e".to_string(), + 0, + "password".to_string(), + "English".to_string(), + Network::Mainnet, + 1, // KDF rounds. + ); + + assert!( + wallet.is_ok(), + "Failed to generate wallet from keys: {:?}", + wallet.err() + ); + + // Verify that the wallet was generated correctly. + let wallet = wallet.expect("Failed to create wallet"); + + // This is required even though "English" was passed as the seed language above. + let set_language_result = wallet.set_seed_language("English"); + assert!( + set_language_result.is_ok(), + "Failed to set seed language: {:?}", + set_language_result.err() + ); + + // The address should be "45wsWad9...". + let address_result = wallet.get_address(0, 0); + assert!( + address_result.is_ok(), + "Failed to get address: {:?}", + address_result.err() + ); + let address = address_result.unwrap(); + assert_eq!(address, "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi"); + + // Get the seed. It should be "hemlock jubilee...". + let seed_result = wallet.get_seed(None); + assert!( + seed_result.is_ok(), + "Failed to get seed: {:?}", + seed_result.err() + ); + let seed = seed_result.unwrap(); + assert_eq!(seed, "hemlock jubilee eden hacksaw boil superior inroads epoxy exhale orders cavernous second brunt saved richly lower upgrade hitched launching deepest mostly playful layout lower eden"); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_generate_view_only_from_keys_integration() { + println!("Running test_generate_from_keys_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.generate_from_keys( + wallet_str.to_string(), + "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi".to_string(), + "".to_string(), + "3bc0b202cde92fe5719c3cc0a16aa94f88a5d19f8c515d4e35fae361f6f2120e".to_string(), + 0, + "password".to_string(), + "English".to_string(), + Network::Mainnet, + 1, // KDF rounds. + ); + + assert!( + wallet.is_ok(), + "Failed to generate wallet from keys: {:?}", + wallet.err() + ); + + // Verify that the wallet was generated correctly. + let wallet = wallet.expect("Failed to create wallet"); + + // This is required even though "English" was passed as the seed language above. + let set_language_result = wallet.set_seed_language("English"); + assert!( + set_language_result.is_ok(), + "Failed to set seed language: {:?}", + set_language_result.err() + ); + + // The address should be "45wsWad9...". + let address_result = wallet.get_address(0, 0); + assert!( + address_result.is_ok(), + "Failed to get address: {:?}", + address_result.err() + ); + let address = address_result.unwrap(); + assert_eq!(address, "45wsWad9EwZgF3VpxQumrUCRaEtdyyh6NG8sVD3YRVVJbK1jkpJ3zq8WHLijVzodQ22LxwkdWx7fS2a6JzaRGzkNU8K2Dhi"); + + // The wallet should not be deterministic. + let is_deterministic_result = wallet.is_deterministic(); + assert!( + is_deterministic_result.is_ok(), + "Failed to check if wallet is deterministic: {:?}", + is_deterministic_result.err() + ); + assert!( + !is_deterministic_result.unwrap(), + "Wallet should not be deterministic" + ); + + // Clean up wallet files. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_seed() { + println!("Running test_get_seed"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Test getting seed without offset. + println!("Attempting to get seed without offset..."); + let start = Instant::now(); + let result = wallet.get_seed(None); + println!("get_seed without offset took {:?}", start.elapsed()); + assert!(result.is_ok(), "Failed to get seed: {:?}", result.err()); + assert!(!result.unwrap().is_empty(), "Seed is empty"); + + // Test getting seed with an offset. + println!("Attempting to get seed with offset..."); + let start = Instant::now(); + let result_with_offset = wallet.get_seed(Some("example_offset")); + println!("get_seed with offset took {:?}", start.elapsed()); + assert!( + result_with_offset.is_ok(), + "Failed to get seed with offset: {:?}", + result_with_offset.err() + ); + assert!( + !result_with_offset.unwrap().is_empty(), + "Seed with offset is empty" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_address() { + println!("Running test_get_address"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Attempting to get address..."); + let start = Instant::now(); + let result = wallet.get_address(0, 0); + println!("get_address took {:?}", start.elapsed()); + assert!(result.is_ok(), "Failed to get address: {:?}", result.err()); + assert!(!result.unwrap().is_empty(), "Address is empty"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_is_deterministic() { + println!("Running test_is_deterministic"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Checking if wallet is deterministic..."); + let start = Instant::now(); + let result = wallet.is_deterministic(); + println!("is_deterministic check took {:?}", start.elapsed()); + assert!( + result.is_ok(), + "Failed to check if wallet is deterministic: {:?}", + result.err() + ); + assert!(result.unwrap(), "Wallet should be deterministic"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_creation_with_different_networks() { + println!("Running test_wallet_creation_with_different_networks"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Define wallet names and corresponding network types. + let wallets = vec![ + ("mainnet_wallet", Network::Mainnet), + ("testnet_wallet", Network::Testnet), + ("stagenet_wallet", Network::Stagenet), + ]; + + for (name, net_type) in wallets { + println!("Creating wallet: {} on network type {:?}", name, net_type); + + // Construct the full path for each wallet within temp_dir. + let wallet_path = temp_dir.path().join(name); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager.create_wallet(wallet_str, "password", "English", net_type); + assert!(wallet.is_ok(), "Failed to create wallet: {}", name); + } + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_multiple_address_generation() { + println!("Running test_multiple_address_generation"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + for i in 0..5 { + println!("Generating address {}...", i); + let start = Instant::now(); + let result = wallet.get_address(0, i); + println!("Address generation took {:?}", start.elapsed()); + assert!( + result.is_ok(), + "Failed to get address {}: {:?}", + i, + result.err() + ); + assert!(!result.unwrap().is_empty(), "Address {} is empty", i); + } + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_wallet_error_display() { + println!("Running test_wallet_error_display"); + + // Test WalletError::FfiError variant. + let error = WalletError::FfiError("Test error".to_string()); + match error { + WalletError::FfiError(msg) => assert_eq!(msg, "Test error"), + _ => panic!("Expected FfiError variant"), + } + + // Test WalletError::NullPointer variant. + let error = WalletError::NullPointer; + match error { + WalletError::NullPointer => assert!(true), + _ => panic!("Expected NullPointer variant"), + } + + // Test WalletError::WalletErrorCode variant. + let error = WalletError::WalletErrorCode(2, "Sample wallet error".to_string()); + match error { + WalletError::WalletErrorCode(code, msg) => { + assert_eq!(code, 2); + assert_eq!(msg, "Sample wallet error"); + } + _ => panic!("Expected WalletErrorCode variant"), + } +} + +#[test] +fn test_wallet_status_integration() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Create a wallet. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Check the status of the wallet. + let status = manager.get_status(wallet.ptr.as_ptr()); + assert!( + status.is_ok(), + "Expected status OK, got error: {:?}", + status.err() + ); + + // Clean up. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_open_wallet_integration() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Create a wallet. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Drop the wallet to simulate closing it. + drop(wallet); + + // Try opening the wallet. + let open_result = manager.open_wallet(wallet_str, "password", Network::Mainnet); + assert!( + open_result.is_ok(), + "Failed to open wallet: {:?}", + open_result.err() + ); + + // Clean up. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_open_wallet_invalid_password() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create a wallet with a valid password. + let wallet = manager + .create_wallet(wallet_str, "correct_password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Drop the wallet + drop(wallet); + + // Attempt to open the wallet with an incorrect password. + let open_result = manager.open_wallet(wallet_str, "wrong_password", Network::Mainnet); + assert!( + open_result.is_err(), + "Expected an error when opening wallet with incorrect password" + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_open_wallet_invalid_path() { + let (manager, _temp_dir) = setup().expect("Failed to set up test environment"); + + // Try to open a wallet at a non-existent path. + let invalid_path = "/invalid/path/to/non_existent_wallet"; + let open_result = manager.open_wallet(invalid_path, "password", Network::Mainnet); + + // Check if the result is an error. + match open_result { + Err(e) => { + // Inspect the error to check the specific status and error message. + if let WalletError::WalletErrorCode(status, error_message) = e { + assert_ne!( + status, WalletStatus_Ok, + "Expected a non-OK status code, got OK instead." + ); + assert!( + error_message.contains("file not found") + || error_message.contains("openWallet"), + "Unexpected error message: {}", + error_message + ); + } else { + panic!("Expected WalletErrorCode, got {:?}", e); + } + } + Ok(_) => panic!("Expected an error when opening a non-existent wallet, but it succeeded."), + } +} + +#[test] +fn test_get_balance_integration() { + println!("Running test_get_balance_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Fetch the balance. + println!("Fetching wallet balance..."); + let start = Instant::now(); + let balance_result = wallet.get_balance(0); // Account index 0. + println!("Fetching balance took {:?}", start.elapsed()); + + assert!( + balance_result.is_ok(), + "Failed to fetch balance: {:?}", + balance_result.err() + ); + + let balance = balance_result.unwrap(); + println!("Balance: {:?}", balance); + + // Ensure the balance values make sense. + // assert!(balance.balance >= 0, "Balance should be non-negative"); + // assert!(balance.unlocked_balance >= 0, "Unlocked balance should be non-negative"); + // These assertions are meaningless with the constraints of the type. + // TODO: Test with scanning integration. + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_create_account_integration() { + println!("Running test_create_account_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Create a new account with a label. + println!("Creating a new account..."); + let start = Instant::now(); + let result = wallet.create_account("Test Account Integration"); + println!("create_account took {:?}", start.elapsed()); + + assert!( + result.is_ok(), + "Failed to create account: {:?}", + result.err() + ); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_accounts_integration() { + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Add multiple accounts. + wallet + .create_account("Integration Account 1") + .expect("Failed to create account"); + wallet + .create_account("Integration Account 2") + .expect("Failed to create account"); + + // Fetch accounts. + let accounts_result = wallet.get_accounts(); + assert!( + accounts_result.is_ok(), + "Failed to fetch accounts: {:?}", + accounts_result.err() + ); + let accounts = accounts_result.unwrap().accounts; + assert_eq!(accounts.len(), 3, "Expected 3 accounts"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_close_wallet_integration() { + println!("Running test_close_wallet_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let mut wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Use the wallet for operations... + println!("Using the wallet for operations..."); + + // Close the wallet. + println!("Closing the wallet..."); + let start = Instant::now(); + let close_result = wallet.close_wallet(); + println!("close_wallet took {:?}", start.elapsed()); + assert!( + close_result.is_ok(), + "Failed to close wallet: {:?}", + close_result.err() + ); + + // Attempt to close the wallet again. + println!("Attempting to close the wallet again..."); + let start = Instant::now(); + let close_again_result = wallet.close_wallet(); + println!("Second close_wallet call took {:?}", start.elapsed()); + assert!( + close_again_result.is_ok(), + "Failed to close wallet a second time: {:?}", + close_again_result.err() + ); + + // Clean up. + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_get_height_integration() { + println!("Running test_get_height_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet_height"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let _wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + + // Fetch the blockchain height. + println!("Fetching blockchain height..."); + let start = Instant::now(); + let height_result = manager.get_height(); + let duration = start.elapsed(); + println!("Blockchain height retrieval took {:?}", duration); + + assert!( + height_result.is_ok(), + "Failed to fetch blockchain height: {:?}", + height_result.err() + ); + + let height = height_result.unwrap(); + println!("Current blockchain height: {}", height); + assert!(height == 0, "Blockchain height should be equal to 0."); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_refresh_integration_success() { + println!("Running test_refresh_integration_success"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("refresh_integration_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Wallet created successfully."); + + // Define initialization configuration. + let config = WalletConfig { + daemon_address: "http://localhost:18081".to_string(), + upper_transaction_size_limit: 10000, // TODO: use sane value. + daemon_username: "user".to_string(), + daemon_password: "pass".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + }; + + // Perform the initialization. + println!("Initializing the wallet..."); + let start = Instant::now(); + let init_result = wallet.init(config); + let duration = start.elapsed(); + println!("Initialization took {:?}", duration); + + assert!( + init_result.is_ok(), + "Failed to initialize wallet: {:?}", + init_result.err() + ); + + // Perform a refresh operation after initialization. + println!("Refreshing the wallet..."); + let refresh_start = Instant::now(); + let refresh_result = wallet.refresh(); + let refresh_duration = refresh_start.elapsed(); + println!("Refresh operation took {:?}", refresh_duration); + + assert!( + refresh_result.is_ok(), + "Failed to refresh wallet: {:?}", + refresh_result.err() + ); + + // Clean up wallet files. + fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_init_integration_success() { + println!("Running test_init_integration_success"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("test_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Wallet created successfully."); + + // Define initialization configuration. + let config = WalletConfig { + daemon_address: "http://localhost:18081".to_string(), + upper_transaction_size_limit: 10000, + daemon_username: "user".to_string(), + daemon_password: "pass".to_string(), + use_ssl: false, + light_wallet: false, + proxy_address: "".to_string(), + }; + + // Perform the initialization. + println!("Initializing the wallet..."); + let start = Instant::now(); + let init_result = wallet.init(config); + let duration = start.elapsed(); + println!("Initialization took {:?}", duration); + + assert!( + init_result.is_ok(), + "Failed to initialize wallet: {:?}", + init_result.err() + ); + + // Perform a refresh operation after initialization. + println!("Refreshing the wallet..."); + let refresh_result = wallet.refresh(); + assert!( + refresh_result.is_ok(), + "Failed to refresh wallet after initialization: {:?}", + refresh_result.err() + ); + + // Clean up wallet files. + fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} + +#[test] +fn test_set_seed_language_integration() { + println!("Running test_set_seed_language_integration"); + let (manager, temp_dir) = setup().expect("Failed to set up test environment"); + + // Construct the full path for the wallet within temp_dir. + let wallet_path = temp_dir.path().join("set_seed_language_wallet"); + let wallet_str = wallet_path + .to_str() + .expect("Failed to convert wallet path to string"); + + // Create the wallet. + let wallet = manager + .create_wallet(wallet_str, "password", "English", Network::Mainnet) + .expect("Failed to create wallet"); + println!("Wallet created successfully."); + + // Set the seed language to French. + println!("Setting seed language to French..."); + let start = Instant::now(); + let set_language_result = wallet.set_seed_language("French"); + let duration = start.elapsed(); + println!("set_seed_language took {:?}", duration); + + assert!( + set_language_result.is_ok(), + "Failed to set seed language: {:?}", + set_language_result.err() + ); + + // Optionally, verify the seed language by retrieving it. + // This requires implementing a corresponding `get_seed_language` method. + + // Clean up wallet files. + fs::remove_file(wallet_str).expect("Failed to delete test wallet"); + fs::remove_file(format!("{}.keys", wallet_str)).expect("Failed to delete test wallet keys"); + + teardown(&temp_dir).expect("Failed to clean up after test"); +} diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 1dd947f95f..2a2fbb6267 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -113,6 +113,7 @@ unsigned-varint = { version = "0.8.0", features = [ "codec", "asynchronous_codec url = { version = "2", features = [ "serde" ] } uuid = { version = "1.9", features = [ "serde", "v4" ] } void = "1" +monero-native = { path = "../monero-native" } [target.'cfg(not(windows))'.dependencies] tokio-tar = "0.3" diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 2d86d303d9..298d27e4a1 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -501,7 +501,7 @@ mod tests { let alice_state3 = alice_state2.receive(bob_message4).unwrap(); let (bob_state3, _tx_lock) = bob_state2.lock_btc().await.unwrap(); - let bob_state4 = bob_state3.xmr_locked(monero_rpc::wallet::BlockHeight { height: 0 }); + let bob_state4 = bob_state3.xmr_locked(monero_c_rust::BlockHeight { height: 0 }); let encrypted_signature = bob_state4.tx_redeem_encsig(); let bob_state6 = bob_state4.cancel(); diff --git a/swap/src/cli/api.rs b/swap/src/cli/api.rs index c97daac7c6..206bfa2ec0 100644 --- a/swap/src/cli/api.rs +++ b/swap/src/cli/api.rs @@ -568,8 +568,10 @@ async fn init_monero_wallet( .await .context("Failed to start monero-wallet-rpc process")?; + let monero_wallet_manager = monero_c_rust::WalletManager::new()?; + let monero_wallet = monero::Wallet::open_or_create( - monero_wallet_rpc_process.endpoint(), + monero_wallet_manager, MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME.to_string(), env_config, ) diff --git a/swap/src/database/alice.rs b/swap/src/database/alice.rs index fcf3ead3a9..c5417981da 100644 --- a/swap/src/database/alice.rs +++ b/swap/src/database/alice.rs @@ -3,7 +3,7 @@ use crate::monero; use crate::monero::{monero_private_key, TransferProof}; use crate::protocol::alice; use crate::protocol::alice::AliceState; -use monero_rpc::wallet::BlockHeight; +use monero_c_rust::BlockHeight; use serde::{Deserialize, Serialize}; use std::fmt; diff --git a/swap/src/database/bob.rs b/swap/src/database/bob.rs index 735f45a222..da8899b597 100644 --- a/swap/src/database/bob.rs +++ b/swap/src/database/bob.rs @@ -1,7 +1,7 @@ use crate::monero::TransferProof; use crate::protocol::bob; use crate::protocol::bob::BobState; -use monero_rpc::wallet::BlockHeight; +use monero_c_rust::BlockHeight; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; use std::fmt; diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index 1017525a02..f10cd5f579 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -4,47 +4,94 @@ use crate::monero::{ }; use ::monero::{Address, Network, PrivateKey, PublicKey}; use anyhow::{Context, Result}; -use monero_rpc::wallet::{BlockHeight, MoneroWalletRpc as _, Refreshed}; -use monero_rpc::{jsonrpc, wallet}; +use monero_c_rust::{Wallet as NativeWallet, WalletManager}; +use monero_c_rust::BlockHeight; use std::future::Future; use std::ops::Div; +use std::path::PathBuf; use std::pin::Pin; use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use tokio::sync::Mutex; use tokio::time::Interval; -use url::Url; -#[derive(Debug)] +/// Structure here: +/// Wallet has constructor functions that take a WalletManager and create a new wallet based on: +/// - a seed +/// - a wallet name + pub struct Wallet { - inner: Mutex, + manager: Arc, + inner: Mutex, network: Network, name: String, main_address: monero::Address, sync_interval: Duration, + path: PathBuf, } impl Wallet { /// Connect to a wallet RPC and load the given wallet by name. - pub async fn open_or_create(url: Url, name: String, env_config: Config) -> Result { - let client = wallet::Client::new(url)?; - - match client.open_wallet(name.clone()).await { - Err(error) => { - tracing::debug!(%error, "Open wallet response error"); - client.create_wallet(name.clone(), "English".to_owned()).await.context( - "Unable to create Monero wallet, please ensure that the monero-wallet-rpc is available", - )?; + pub async fn open_or_create( + manager: Arc, + name: String, + env_config: Config, + ) -> Result { + let tempDir = std::env::temp_dir(); + let name = name.clone(); + let path = tempDir.join(&name); + + if manager.as_ref().wallet_exists(path.clone())? { + match manager.open_wallet(path.clone(), "", env_config.monero_network) { + Err(error) => { + return Err(error.into()); + } + Ok(mut wallet) => { + let address = wallet.get_address(0, 0)?; + tracing::debug!(monero_wallet_name = %name, "Opened Monero wallet"); + + return Ok(Self { + manager, + inner: Mutex::new(wallet), + network: env_config.monero_network, + name, + main_address: monero::Address::from_str(address.as_str())?, + sync_interval: env_config.monero_sync_interval(), + path, + }); + } + } + } else { + tracing::debug!(monero_wallet_name = %name.clone(), "Attempted to open Monero wallet, but it does not exist. We will create it."); - tracing::debug!(monero_wallet_name = %name, "Created Monero wallet"); + match manager.create_wallet(path.clone(), "English", "", env_config.monero_network) { + Err(error) => { + tracing::error!(%error, "Failed to create Monero wallet"); + return Err(error.into()); + } + Ok(wallet) => { + tracing::info!(monero_wallet_name = %name, "Created Monero wallet"); + + let address = monero::Address::from_str(wallet.get_address(0, 0)?.as_str())?; + + return Ok(Self { + manager, + inner: Mutex::new(wallet), + network: env_config.monero_network, + name, + main_address: address, + sync_interval: env_config.monero_sync_interval(), + path, + }); + } } - Ok(_) => tracing::debug!(monero_wallet_name = %name, "Opened Monero wallet"), } - - Self::connect(client, name, env_config).await } /// Connects to a wallet RPC where a wallet is already loaded. + // TOOD: This is needed for integration tests + /* pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result { let main_address = monero::Address::from_str(client.get_address(0).await?.address.as_str())?; @@ -57,19 +104,16 @@ impl Wallet { sync_interval: env_config.monero_sync_interval(), }) } + */ /// Re-open the wallet using the internally stored name. pub async fn re_open(&self) -> Result<()> { - self.inner - .lock() - .await - .open_wallet(self.name.clone()) - .await?; + self.inner.lock().await.close_wallet()?; Ok(()) } - pub async fn open(&self, filename: String) -> Result<()> { - self.inner.lock().await.open_wallet(filename).await?; + pub async fn open(&self, filename: PathBuf) -> Result<()> { + self.manager.open_wallet(filename, "", self.network)?; Ok(()) } @@ -87,16 +131,15 @@ impl Wallet { let address = Address::standard(self.network, public_spend_key, public_view_key); - let wallet = self.inner.lock().await; + let mut wallet = self.inner.lock().await; // Properly close the wallet before generating the other wallet to ensure that // it saves its state correctly let _ = wallet .close_wallet() - .await .context("Failed to close wallet")?; - let _ = wallet + let _ = self.manager .generate_from_keys( file_name, address.to_string(), @@ -104,9 +147,10 @@ impl Wallet { PrivateKey::from(private_view_key).to_string(), restore_height.height, String::from(""), - true, + String::from("English"), + self.network, + 1, ) - .await .context("Failed to generate new wallet from keys")?; Ok(()) @@ -131,12 +175,9 @@ impl Wallet { // Close the default wallet before generating the other wallet to ensure that // it saves its state correctly - let _ = self.inner.lock().await.close_wallet().await?; + let _ = self.inner.lock().await.close_wallet()?; - let _ = self - .inner - .lock() - .await + let _ = self.manager .generate_from_keys( file_name, temp_wallet_address.to_string(), @@ -144,9 +185,10 @@ impl Wallet { PrivateKey::from(private_view_key).to_string(), restore_height.height, String::from(""), - true, - ) - .await?; + String::from("English"), + self.network, + 1, + )?; // Try to send all the funds from the generated wallet to the default wallet match self.refresh(3).await { @@ -154,18 +196,16 @@ impl Wallet { .inner .lock() .await - .sweep_all(self.main_address.to_string()) - .await + .sweep_all(0, self.main_address, true) { Ok(sweep_all) => { - for tx in sweep_all.tx_hash_list { - tracing::info!( - %tx, - monero_address = %self.main_address, - "Monero transferred back to default wallet"); - } + tracing::info!( + txid = %sweep_all.txid, + monero_address = %self.main_address, + "Monero transferred back to default wallet"); } Err(error) => { + // TODO: Re-add the retry fix here from https://github.com/UnstoppableSwap/core/pull/254 tracing::warn!( address = %self.main_address, "Failed to transfer Monero to default wallet: {:#}", error @@ -178,11 +218,8 @@ impl Wallet { } let _ = self - .inner - .lock() - .await - .open_wallet(self.name.clone()) - .await?; + .manager + .open_wallet(self.path.clone(), "", self.network)?; Ok(()) } @@ -206,12 +243,12 @@ impl Wallet { tracing::debug!( %amount, to = %public_spend_key, - tx_id = %res.tx_hash, + tx_id = %res.txid, "Successfully initiated Monero transfer" ); Ok(TransferProof::new( - TxHash(res.tx_hash), + TxHash(res.txid), res.tx_key .context("Missing tx_key in `transfer` response")?, )) @@ -269,54 +306,56 @@ impl Wallet { .inner .lock() .await - .sweep_all(address.to_string()) - .await?; + .sweep_all(0, address, true)?; - let tx_hashes = sweep_all.tx_hash_list.into_iter().map(TxHash).collect(); - Ok(tx_hashes) + Ok(vec![TxHash(sweep_all.txid)]) } /// Get the balance of the primary account. - pub async fn get_balance(&self) -> Result { - Ok(self.inner.lock().await.get_balance(0).await?) + pub async fn get_balance(&self) -> Result { + Ok(self.inner.lock().await.get_balance(0)?) } - pub async fn block_height(&self) -> Result { - Ok(self.inner.lock().await.get_height().await?) + pub async fn block_height(&self) -> Result { + Ok(self.manager.get_height()?) } pub fn get_main_address(&self) -> Address { self.main_address } - pub async fn refresh(&self, max_attempts: usize) -> Result { + pub async fn refresh(&self, max_attempts: usize) -> Result { const RETRY_INTERVAL: Duration = Duration::from_secs(1); for i in 1..=max_attempts { tracing::info!(name = %self.name, attempt=i, "Syncing Monero wallet"); - let result = self.inner.lock().await.refresh().await; + let result = self.inner.lock().await.refresh(); match result { Ok(refreshed) => { - tracing::info!(name = %self.name, "Monero wallet synced"); + tracing::info!(name = %self.name, "Syncing Monero wallet"); + + loop { + let sync_height = self.inner.lock().await.get_blockchain_height()?; + let daemon_height = self.manager.get_height()?; + + if sync_height >= daemon_height { + tracing::info!(name = %self.name, "Monero wallet synced"); + break; + } + + tracing::info!(name = %self.name, %sync_height, %daemon_height, "Syncing Monero wallet"); + + tokio::time::sleep(Duration::from_secs(1)).await; + } + return Ok(refreshed); } Err(error) => { let attempts_left = max_attempts - i; - // We would not want to fail here if the height is not available - // as it is not critical for the operation of the wallet. - // We can just log a warning and continue. - let height = match self.inner.lock().await.get_height().await { - Ok(height) => height.to_string(), - Err(_) => { - tracing::warn!(name = %self.name, "Failed to fetch Monero wallet height during sync"); - "unknown".to_string() - } - }; - - tracing::warn!(attempt=i, %height, %attempts_left, name = %self.name, %error, "Failed to sync Monero wallet"); + tracing::warn!(attempt=i, %attempts_left, name = %self.name, %error, "Failed to sync Monero wallet"); if attempts_left == 0 { return Err(error.into()); @@ -328,6 +367,11 @@ impl Wallet { } unreachable!("Loop should have returned by now"); } + + pub async fn close_wallet(&self) -> Result<()> { + self.inner.lock().await.close_wallet()?; + Ok(()) + } } #[derive(Debug)] @@ -350,10 +394,8 @@ type ConfirmationListener = Box Pin + Send + 'static>> + Send + 'static>; #[allow(clippy::too_many_arguments)] -async fn wait_for_confirmations_with< - C: monero_rpc::wallet::MoneroWalletRpc + Sync, ->( - client: &Mutex, +async fn wait_for_confirmations_with( + client: &Mutex, transfer_proof: TransferProof, to_address: Address, expected: Amount, @@ -370,22 +412,16 @@ async fn wait_for_confirmations_with< let txid = transfer_proof.tx_hash().to_string(); let client = client.lock().await; - let tx = match client - .check_tx_key( - txid.clone(), - transfer_proof.tx_key.to_string(), - to_address.to_string(), - ) - .await - { + let tx = match client.check_tx_key( + txid.clone(), + transfer_proof.tx_key.to_string(), + to_address.to_string(), + ) { Ok(proof) => proof, - Err(jsonrpc::Error::JsonRpc(jsonrpc::JsonRpcError { - code: -1, - message, - data, - })) => { - tracing::debug!(message, ?data); - tracing::warn!(%txid, message, "`monero-wallet-rpc` failed to fetch transaction, may need to be restarted"); + /* + TODO: monero-native todo, re-implement + Err(err) => { + tracing::warn!(%txid, %err, "Failed to fetch Monero transaction, may need to be restarted"); continue; } // TODO: Implement this using a generic proxy for each function call once https://github.com/thomaseizinger/rust-jsonrpc-client/issues/47 is fixed. @@ -396,7 +432,7 @@ async fn wait_for_confirmations_with< ); let _ = client.open_wallet(wallet_name.clone()).await; continue; - } + }*/ Err(other) => { tracing::debug!( %txid, diff --git a/swap/src/network/swap_setup/alice.rs b/swap/src/network/swap_setup/alice.rs index c02672b200..94c6cc4370 100644 --- a/swap/src/network/swap_setup/alice.rs +++ b/swap/src/network/swap_setup/alice.rs @@ -41,7 +41,7 @@ pub enum OutEvent { #[derive(Debug)] pub struct WalletSnapshot { - balance: monero_rpc::wallet::GetBalance, + balance: monero_c_rust::GetBalance, lock_fee: monero::Amount, // TODO: Consider using the same address for punish and redeem (they are mutually exclusive, so @@ -537,7 +537,7 @@ pub enum Error { }, #[error("Unlocked balance ({balance}) too low to fulfill swapping {buy}")] BalanceTooLow { - balance: monero_rpc::wallet::GetBalance, + balance: monero_c_rust::GetBalance, buy: bitcoin::Amount, }, #[error("Failed to fetch latest rate")] diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 7627a52954..15ca8e92da 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -9,7 +9,7 @@ use crate::monero_ext::ScalarExt; use crate::protocol::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM}; use crate::{bitcoin, monero}; use anyhow::{anyhow, bail, Context, Result}; -use monero_rpc::wallet::BlockHeight; +use monero_c_rust::BlockHeight; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof; diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 1e6425a5e8..19018d97a2 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -13,7 +13,7 @@ use bdk::database::BatchDatabase; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::nonce::Deterministic; use ecdsa_fun::Signature; -use monero_rpc::wallet::BlockHeight; +use monero_c_rust::BlockHeight; use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use sha2::Sha256; @@ -677,7 +677,8 @@ impl State5 { tracing::info!(%wallet_file_name, "Falling back to trying to open the wallet if it already exists", ); - monero_wallet.open(wallet_file_name).await?; + todo!("We dont know the path only the name because of temp dir"); + // monero_wallet.open(wallet_file_name).await?; } // Ensure that the generated wallet is synced so we have a proper balance