summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--impls/monero.rs/.gitignore1
-rw-r--r--impls/monero.rs/Cargo.lock436
-rw-r--r--impls/monero.rs/Cargo.toml21
-rw-r--r--impls/monero.rs/README.md31
-rw-r--r--impls/monero.rs/build.rs136
-rw-r--r--impls/monero.rs/example/Cargo.lock444
-rw-r--r--impls/monero.rs/example/Cargo.toml9
-rw-r--r--impls/monero.rs/example/README.md22
-rw-r--r--impls/monero.rs/example/src/main.rs67
-rwxr-xr-ximpls/monero.rs/scripts/build_monero_c.sh68
-rw-r--r--impls/monero.rs/src/bindings.rs1632
-rw-r--r--impls/monero.rs/src/lib.rs2039
-rw-r--r--impls/monero.rs/tests/integration_tests.rs828
-rw-r--r--monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp13
-rw-r--r--monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h1
15 files changed, 5748 insertions, 0 deletions
diff --git a/impls/monero.rs/.gitignore b/impls/monero.rs/.gitignore
new file mode 100644
index 0000000..2f7896d
--- /dev/null
+++ b/impls/monero.rs/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/impls/monero.rs/Cargo.lock b/impls/monero.rs/Cargo.lock
new file mode 100644
index 0000000..9991a45
--- /dev/null
+++ b/impls/monero.rs/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/impls/monero.rs/Cargo.toml b/impls/monero.rs/Cargo.toml
new file mode 100644
index 0000000..f055225
--- /dev/null
+++ b/impls/monero.rs/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "monero_c_rust"
+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"
+tempfile = "3.13.0"
+
+[build-dependencies]
+bindgen = "0.70.1"
+
diff --git a/impls/monero.rs/README.md b/impls/monero.rs/README.md
new file mode 100644
index 0000000..e9e8da9
--- /dev/null
+++ b/impls/monero.rs/README.md
@@ -0,0 +1,31 @@
+# `monero_rust`
+Proof of concept `monero_c` bindings for Rust.
+
+## Getting started
+<!--
+### Prerequisites
+You may need
+```
+sudo apt-get install libhidapi-dev
+```
+-->
+### Build or download `monero_c` library
+Build or download the `monero_c` library for your architecture. Follow the
+upstream docs at https://github.com/MrCyjaneK/monero_c or download the latest
+release from https://github.com/MrCyjaneK/monero_c/releases. The library must
+be placed in `../../../../release` (as in `monero_c/release`) and its name
+should match your platform as in:
+- Android: `libmonero_libwallet2_api_c.so`
+- iOS: `MoneroWallet.framework/MoneroWallet`
+- Linux: `monero_libwallet2_api_c.so`
+- macOS: `monero_libwallet2_api_c.dylib`
+- Windows: `monero_libwallet2_api_c.dll`
+
+### Run demo
+With the library in a supported location, from `monero_c/impls/monero_rust`:
+```
+cargo run
+```
+
+## Using `monero_rust` in your own crate
+Refer to the `example` folder. Library placement is the same as for the demo.
diff --git a/impls/monero.rs/build.rs b/impls/monero.rs/build.rs
new file mode 100644
index 0000000..3fe2f81
--- /dev/null
+++ b/impls/monero.rs/build.rs
@@ -0,0 +1,136 @@
+use std::env;
+use std::fs::{self, OpenOptions};
+use std::io::Write;
+use std::path::PathBuf;
+use bindgen::EnumVariation;
+
+#[cfg(unix)]
+use std::os::unix::fs as unix_fs;
+
+#[cfg(target_os = "windows")]
+use std::fs::copy;
+
+fn main() {
+ let header_path = "../../monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h";
+ let lib_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("../../release");
+
+ // 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("monero_libwallet2_api_c.dll")
+ } else if cfg!(target_os = "macos") {
+ lib_path.join("monero_libwallet2_api_c.dylib")
+ } else {
+ lib_path.join("monero_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");
+ println!("cargo:rustc-link-lib=dylib=stdc++");
+ println!("cargo:rustc-link-lib=dylib=hidapi-hidraw");
+ 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/impls/monero.rs/example/Cargo.lock b/impls/monero.rs/example/Cargo.lock
new file mode 100644
index 0000000..03e1106
--- /dev/null
+++ b/impls/monero.rs/example/Cargo.lock
@@ -0,0 +1,444 @@
+# 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 = "monero_example"
+version = "0.0.1"
+dependencies = [
+ "monero_c_rust",
+ "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/impls/monero.rs/example/Cargo.toml b/impls/monero.rs/example/Cargo.toml
new file mode 100644
index 0000000..a5c30be
--- /dev/null
+++ b/impls/monero.rs/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "monero_example"
+version = "0.0.1"
+edition = "2021"
+
+[dependencies]
+monero_c_rust = { path = ".." }
+tempfile = "3.13.0"
+# monero_c_rust = { git = "https://github.com/MrCyjaneK/monero_c" }
diff --git a/impls/monero.rs/example/README.md b/impls/monero.rs/example/README.md
new file mode 100644
index 0000000..febb9cf
--- /dev/null
+++ b/impls/monero.rs/example/README.md
@@ -0,0 +1,22 @@
+# `monero_c/impls/monero.rs/example`
+Refer to https://github.com/MrCyjaneK/monero_c/blob/master/README.md and
+https://github.com/MrCyjaneK/monero_c/blob/master/impls/monero.rs/README.md for
+the latest documentation.
+
+## `monero_c` library
+A `monero_c` library is required to build this example. Build or download the
+`monero_c` library for your architecture. Follow the upstream docs at
+https://github.com/MrCyjaneK/monero_c or download the latest release from
+https://github.com/MrCyjaneK/monero_c/releases. The library should then be
+placed adjacent to the binary: that is, if your binary is in `target/debug` or
+`target/release`, the library should also be in `release` or `debug`,
+respectively. Its name should also match your platform as in:
+- Android: `libmonero_libwallet2_api_c.so`
+- iOS: `MoneroWallet.framework/MoneroWallet`
+- Linux: `monero_libwallet2_api_c.so`
+- macOS: `monero_libwallet2_api_c.dylib`
+- Windows: `monero_libwallet2_api_c.dll`
+
+On Linux you must also symlink "libmonero_libwallet2_api_c.so" and
+"libwallet2_api_c.so" to "monero_libwallet2_api_c.so". Other systems will also
+need similar symlinks or copies.
diff --git a/impls/monero.rs/example/src/main.rs b/impls/monero.rs/example/src/main.rs
new file mode 100644
index 0000000..245013a
--- /dev/null
+++ b/impls/monero.rs/example/src/main.rs
@@ -0,0 +1,67 @@
+use monero_c_rust::{NetworkType, WalletError, WalletManager, WalletConfig};
+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(),
+ NetworkType::Mainnet,
+ 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: "https://monero.stackwallet.com:18081".to_string(),
+ upper_transaction_size_limit: 10000, // TODO: use sane value.
+ daemon_username: "".to_string(),
+ daemon_password: "".to_string(),
+ use_ssl: true,
+ light_wallet: false,
+ proxy_address: "".to_string(),
+ };
+
+ // Perform the initialization.
+ wallet.init(config)?;
+ wallet.throw_if_error()?;
+
+ // Refresh the wallet.
+ wallet.refresh()?;
+ wallet.throw_if_error()?;
+
+ // Wait for the refresh to complete.
+ loop {
+ let height = manager.get_height().expect("Failed to get blockchain height");
+ println!("Current blockchain height: {}", height);
+ if height > 3263501 { // 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/impls/monero.rs/scripts/build_monero_c.sh b/impls/monero.rs/scripts/build_monero_c.sh
new file mode 100755
index 0000000..ca9fba4
--- /dev/null
+++ b/impls/monero.rs/scripts/build_monero_c.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+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)
+
+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="host-apple-ios"
+ ;;
+ *)
+ echo "Unsupported architecture: $ARCH on OS: $OS"
+ exit 1
+ ;;
+esac
+
+
+unxz -f release/monero/${TARGET_ARCH}_libwallet2_api_c.so.xz
+#unxz -f release/wownero/${TARGET_ARCH}_libwallet2_api_c.so.xz
+
+# Navigate back to /scripts.
+cd ..
+
+# Copy the built .so file to a generic name.
+SO_FILE="monero_c/release/monero/${TARGET_ARCH}_libwallet2_api_c.so"
+if [[ -f "$SO_FILE" ]]; then
+ cp "$SO_FILE" "../lib/libwallet2_api_c.so"
+ echo "Copied $SO_FILE to libwallet2_api_c.so"
+else
+ echo "Error: $SO_FILE not found."
+ exit 1
+fi
diff --git a/impls/monero.rs/src/bindings.rs b/impls/monero.rs/src/bindings.rs
new file mode 100644
index 0000000..30a03cd
--- /dev/null
+++ b/impls/monero.rs/src/bindings.rs
@@ -0,0 +1,1632 @@
+#![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"e8db0ef0324a153f5e3ecca4c0db23c54f4576e84988f04bd4f11c1142f9d7ad\0";
+pub const MONERO_wallet2_api_c_cpp_sha256 : & [u8 ; 106] = b"dca52ac9ee009fda9fb5726543a454885e61d8eb74fb33112288029ed625bec5-b089f9ee69924882c5d14dd1a6991deb05d9d1cd\0" ;
+pub const MONERO_wallet2_api_c_exp_sha256: &[u8; 65] =
+ b"c8913ac41068f67b57c9b0a3c7dd8973e3c1273b66c2ff0aadb0003931da748c\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_daemonBlockChainHeight_cached(
+ wallet_ptr: *mut ::std::os::raw::c_void,
+ ) -> u64;
+}
+extern "C" {
+ pub fn MONERO_Wallet_daemonBlockChainHeight_runThread(
+ wallet_ptr: *mut ::std::os::raw::c_void,
+ seconds: ::std::os::raw::c_int,
+ );
+}
+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: u64,
+ in_pool: bool,
+ confirmations: 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(
+ device_type: ::std::os::raw::c_int,
+ keys_file_name: *const ::std::os::raw::c_char,
+ password: *const ::std::os::raw::c_char,
+ kdf_rounds: u64,
+ ) -> bool;
+}
+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/impls/monero.rs/src/lib.rs b/impls/monero.rs/src/lib.rs
new file mode 100644
index 0000000..56373da
--- /dev/null
+++ b/impls/monero.rs/src/lib.rs
@@ -0,0 +1,2039 @@
+use std::ffi::{CStr, CString};
+use std::os::raw::{c_int, c_void};
+use std::ptr::NonNull;
+use std::sync::Arc;
+
+pub mod bindings;
+pub use bindings::WalletStatus_Ok;
+pub use bindings::WalletStatus_Error;
+pub use bindings::WalletStatus_Critical;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum NetworkType {
+ Mainnet = bindings::NetworkType_MAINNET as isize,
+ Testnet = bindings::NetworkType_TESTNET as isize,
+ Stagenet = bindings::NetworkType_STAGENET as isize,
+}
+
+impl NetworkType {
+ pub fn from_c_int(value: c_int) -> Option<Self> {
+ match value {
+ bindings::NetworkType_MAINNET => Some(NetworkType::Mainnet),
+ bindings::NetworkType_TESTNET => Some(NetworkType::Testnet),
+ bindings::NetworkType_STAGENET => Some(NetworkType::Stagenet),
+ _ => None,
+ }
+ }
+
+ pub fn to_c_int(self) -> c_int {
+ self as c_int
+ }
+}
+
+#[derive(Debug)]
+pub enum WalletError {
+ NullPointer,
+ FfiError(String),
+ WalletErrorCode(c_int, String),
+}
+
+pub type WalletResult<T> = Result<T, WalletError>;
+
+#[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<Account>,
+}
+
+pub struct Wallet {
+ pub ptr: NonNull<c_void>,
+ pub manager: Arc<WalletManager>,
+ pub is_closed: bool,
+}
+
+pub struct WalletManager {
+ ptr: NonNull<c_void>,
+}
+
+/// 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(),
+ }
+ }
+}
+
+pub type BlockHeight = u64;
+
+#[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<String>,
+ /// 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 {
+ /// Indicates whether the transaction key is valid.
+ pub valid: bool,
+ /// An optional error message providing details if the verification fails.
+ pub error: Option<String>,
+}
+
+impl WalletManager {
+ /// Creates a new `WalletManager`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use monero_c_rust::WalletManager;
+ /// let manager = WalletManager::new();
+ /// assert!(manager.is_ok());
+ /// ```
+ pub fn new() -> WalletResult<Arc<Self>> {
+ unsafe {
+ 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, NetworkType};
+ /// 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", NetworkType::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, NetworkType};
+ /// 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", NetworkType::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))
+ }
+ }
+ }
+
+ /// 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, NetworkType};
+ /// 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", NetworkType::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<Self>,
+ path: &str,
+ password: &str,
+ language: &str,
+ network_type: NetworkType,
+ ) -> WalletResult<Wallet> {
+ let c_path = CString::new(path).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, NetworkType};
+ /// 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,
+ /// NetworkType::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<Self>,
+ path: String,
+ password: String,
+ seed: String,
+ network_type: NetworkType,
+ restore_height: u64,
+ kdf_rounds: u64,
+ seed_offset: String, // TODO: Make an Option.
+ ) -> WalletResult<Wallet> {
+ // 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, NetworkType};
+ /// 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,
+ /// NetworkType::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<Self>,
+ path: String,
+ password: String,
+ polyseed: String,
+ network_type: NetworkType,
+ restore_height: u64,
+ kdf_rounds: u64,
+ seed_offset: String,
+ new_wallet: bool,
+ ) -> WalletResult<Wallet> {
+ // 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,
+ })
+ }
+ }
+
+ /// Generates a wallet from provided keys.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use monero_c_rust::{WalletManager, NetworkType};
+ /// 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(),
+ /// NetworkType::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<Self>,
+ filename: String,
+ address: String,
+ spendkey: String,
+ viewkey: String,
+ restore_height: u64,
+ password: String,
+ language: String,
+ network_type: NetworkType,
+ kdf_rounds: u64,
+ ) -> WalletResult<Wallet> {
+ 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, NetworkType};
+ /// 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", NetworkType::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", NetworkType::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<Self>,
+ path: &str,
+ password: &str,
+ network_type: NetworkType,
+ ) -> WalletResult<Wallet> {
+ let c_path = CString::new(path).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, NetworkType};
+ ///
+ /// let manager = WalletManager::new().unwrap();
+ /// let height = manager.get_height().unwrap();
+ /// println!("Current blockchain height: {}", height);
+ /// ```
+ pub fn get_height(&self) -> WalletResult<BlockHeight> {
+ 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(height)
+ }
+ }
+}
+
+impl Wallet {
+ /// Retrieves the wallet's seed with an optional offset.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use monero_c_rust::{WalletManager, NetworkType};
+ /// 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", NetworkType::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<String> {
+ 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, NetworkType};
+ /// 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", NetworkType::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<String> {
+ 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, NetworkType};
+ /// 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", NetworkType::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<bool> {
+ 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, NetworkType, WalletError};
+ /// let manager = WalletManager::new().unwrap();
+ /// // Intentionally pass an invalid wallet to force an error.
+ /// let invalid_wallet = manager.create_wallet("", "", "", NetworkType::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, NetworkType, 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", NetworkType::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<GetBalance> {
+ 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, NetworkType};
+ /// 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", NetworkType::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, NetworkType};
+ /// 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", NetworkType::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<GetAccounts> {
+ 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, NetworkType, 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", NetworkType::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, NetworkType, 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", NetworkType::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<()> {
+ 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 {
+ let result = bindings::MONERO_Wallet_init(
+ self.ptr.as_ptr(),
+ c_daemon_address.as_ptr(),
+ config.upper_transaction_size_limit,
+ c_daemon_username.as_ptr(),
+ c_daemon_password.as_ptr(),
+ config.use_ssl,
+ config.light_wallet,
+ c_proxy_address.as_ptr(),
+ );
+
+ if result {
+ Ok(())
+ } else {
+ // Retrieve the last error from the wallet
+ Err(self.get_last_error())
+ }
+ }
+ }
+
+ /// Refreshes the wallet's state by synchronizing it with the blockchain.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use monero_c_rust::{WalletManager, NetworkType, 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", NetworkType::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<Refreshed> {
+ 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())
+ }
+ }
+ }
+
+ /// Initiates a transfer from the wallet to the specified destinations.
+ ///
+ /// # Returns
+ ///
+ /// * `WalletResult<Transfer>` - On success, returns a `Transfer` struct containing transaction details.
+ /// On failure, returns a `WalletError`.
+ pub fn transfer(&self, account_index: u32, destinations: Vec<Destination>, get_tx_key: bool, sweep_all: bool) -> WalletResult<Transfer> {
+ // 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<String> = 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<String> = 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 {
+ Some(CStr::from_ptr(tx_key_ptr).to_string_lossy().into_owned())
+ }
+ } 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,
+ })
+ }
+ }
+
+ /// Sweep all funds from the specific account to the specified destination.
+ ///
+ /// TODO: Example / docs-tests.
+ pub fn sweep_all(&self, account_index: u32, destination: Destination, get_tx_key: bool) -> WalletResult<Transfer> {
+ // Convert the destination address to a CString.
+ let c_address = CString::new(destination.address.clone()).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 {
+ Some(CStr::from_ptr(tx_key_ptr).to_string_lossy().into_owned())
+ }
+ } 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, NetworkType};
+ /// 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", NetworkType::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,
+ received: Option<u64>,
+ in_pool: Option<bool>,
+ confirmations: Option<u64>,
+ ) -> WalletResult<CheckTxKey> {
+ // 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 received_val = received.unwrap_or(0);
+ let in_pool_val = in_pool.unwrap_or(false);
+ let confirmations_val = confirmations.unwrap_or(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(),
+ received_val,
+ in_pool_val,
+ confirmations_val,
+ )
+ };
+
+ if result {
+ Ok(CheckTxKey {
+ valid: true,
+ error: None,
+ })
+ } 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 Drop for Wallet {
+ fn drop(&mut self) {
+ if !self.is_closed {
+ let _ = self.close_wallet();
+ }
+ }
+}
+
+#[cfg(test)]
+use tempfile::TempDir;
+#[cfg(test)]
+use std::fs;
+
+#[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<WalletManager>, 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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::Mainnet),
+ ("testnet_wallet", NetworkType::Testnet),
+ ("stagenet_wallet", NetworkType::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,
+ NetworkType::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(),
+ NetworkType::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 = NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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(),
+ NetworkType::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(),
+ NetworkType::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");
+} \ No newline at end of file
diff --git a/impls/monero.rs/tests/integration_tests.rs b/impls/monero.rs/tests/integration_tests.rs
new file mode 100644
index 0000000..079a9a6
--- /dev/null
+++ b/impls/monero.rs/tests/integration_tests.rs
@@ -0,0 +1,828 @@
+use monero_c_rust::{WalletManager, NetworkType, WalletConfig, WalletError, 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<WalletManager>, 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", NetworkType::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", NetworkType::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,
+ NetworkType::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,
+ NetworkType::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(),
+ NetworkType::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(),
+ NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::Mainnet),
+ ("testnet_wallet", NetworkType::Testnet),
+ ("stagenet_wallet", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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", NetworkType::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/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
index 19192cf..0617a97 100644
--- a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
+++ b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
@@ -1972,6 +1972,19 @@ const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid) {
DEBUG_END()
}
+bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t received, bool in_pool, uint64_t confirmations) {
+ Monero::Wallet* wallet = reinterpret_cast<Monero::Wallet*>(wallet_ptr);
+ bool result = wallet->checkTxKey(
+ std::string(txid),
+ std::string(tx_key),
+ std::string(address),
+ received,
+ in_pool,
+ confirmations
+ );
+ return result;
+}
+
const char* MONERO_Wallet_signMessage(void* wallet_ptr, const char* message, const char* address) {
DEBUG_START()
Monero::Wallet *wallet = reinterpret_cast<Monero::Wallet*>(wallet_ptr);
diff --git a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
index 17c647c..a0094b7 100644
--- a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
+++ b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
@@ -778,6 +778,7 @@ extern ADDAPI const char* MONERO_Wallet_getUserNote(void* wallet_ptr, const char
// virtual std::string getTxKey(const std::string &txid) const = 0;
extern ADDAPI const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid);
// virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0;
+extern ADDAPI bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t received, bool in_pool, uint64_t confirmations);
// virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const = 0;
// virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0;
// virtual std::string getSpendProof(const std::string &txid, const std::string &message) const = 0;