#![deny(unsafe_code)] /* No `unsafe` needed! */ use ::safer_ffi::prelude::*; use bdk::bitcoin::network::constants::Network::Testnet; use bdk::blockchain::{ElectrumBlockchain, log_progress}; use bdk::electrum_client::Client; use bdk::sled; use bdk::sled::Tree; use bdk::Wallet; use bdk::wallet::AddressIndex::New; use safer_ffi::char_p::{char_p_ref, char_p_boxed}; use safer_ffi::boxed::Box; #[ffi_export] fn print_string (string: char_p_ref) { println!("{}", string); } /// Concatenate two input UTF-8 (_e.g._, ASCII) strings. /// /// The returned string must be freed with `rust_free_string` #[ffi_export] fn concat_string(fst: char_p_ref, snd: char_p_ref) -> char_p_boxed { let fst = fst.to_str(); // : &'_ str let snd = snd.to_str(); // : &'_ str let ccat = format!("{}{}", fst, snd).try_into().unwrap(); ccat } /// Frees a Rust-allocated string #[ffi_export] fn free_string (string: char_p_boxed) { drop(string) } /// A `struct` usable from both Rust and C #[derive_ReprC] #[repr(C)] #[derive(Debug, Clone)] pub struct Config { name: char_p_boxed, count: i64 } /// Debug print a Point #[ffi_export] fn print_config(config: &Config) { println!("{:?}", config); } /// Create a new Config #[ffi_export] fn new_config(name: char_p_ref, count: i64) -> Box { let name = name.to_string().try_into().unwrap(); Box::new(Config { name, count }) } #[ffi_export] fn free_config(config: Box) { drop(config) } #[derive_ReprC] #[ReprC::opaque] pub struct WalletPtr { raw: Wallet, } impl From> for WalletPtr { fn from(wallet: Wallet) -> Self { WalletPtr { raw: wallet, } } } #[ffi_export] fn new_wallet( name: char_p_ref, descriptor: char_p_ref, change_descriptor: Option, ) -> Box { let name = name.to_string(); let descriptor = descriptor.to_string(); let change_descriptor = change_descriptor.map(|s| s.to_string()); let database = sled::open("./wallet_db").unwrap(); let tree = database.open_tree(name.clone()).unwrap(); let descriptor: &str = descriptor.as_str(); let change_descriptor: Option<&str> = change_descriptor.as_deref(); let electrum_url = "ssl://electrum.blockstream.info:60002"; let client = Client::new(&electrum_url).unwrap(); let wallet = Wallet::new( descriptor, change_descriptor, Testnet, tree, ElectrumBlockchain::from(client), ) .unwrap(); println!("created wallet"); Box::new(WalletPtr::from(wallet)) } #[ffi_export] fn sync_wallet( wallet: &WalletPtr) { let _r = wallet.raw.sync(log_progress(), Some(100)); } #[ffi_export] fn new_address( wallet: &WalletPtr) -> char_p_boxed { let new_address = wallet.raw.get_address(New); let new_address = new_address.unwrap(); let new_address = new_address.to_string(); new_address.try_into().unwrap() } #[ffi_export] fn free_wallet( wallet: Option>) { drop(wallet) } /// The following test function is necessary for the header generation. #[::safer_ffi::cfg_headers] #[test] fn generate_headers() -> ::std::io::Result<()> { ::safer_ffi::headers::builder() .to_file("bdk_ffi.h")? .generate() }