2021-06-04 18:03:34 -07:00
|
|
|
#![deny(unsafe_code)] /* No `unsafe` needed! */
|
|
|
|
|
2021-06-04 23:01:51 -07:00
|
|
|
use ::safer_ffi::prelude::*;
|
2021-06-04 11:07:51 -07:00
|
|
|
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;
|
2021-06-04 18:03:34 -07:00
|
|
|
use bdk::wallet::AddressIndex::New;
|
|
|
|
use safer_ffi::char_p::{char_p_ref, char_p_boxed};
|
2021-06-04 23:01:51 -07:00
|
|
|
use safer_ffi::boxed::Box;
|
2021-06-04 18:03:34 -07:00
|
|
|
|
2021-06-08 18:15:20 -07:00
|
|
|
#[ffi_export]
|
|
|
|
fn print_string (string: char_p_ref)
|
|
|
|
{
|
|
|
|
println!("{}", string);
|
|
|
|
}
|
|
|
|
|
2021-06-04 18:03:34 -07:00
|
|
|
/// Concatenate two input UTF-8 (_e.g._, ASCII) strings.
|
|
|
|
///
|
2021-06-08 18:15:20 -07:00
|
|
|
/// The returned string must be freed with `rust_free_string`
|
2021-06-04 18:03:34 -07:00
|
|
|
#[ffi_export]
|
2021-06-08 18:15:20 -07:00
|
|
|
fn concat_string(fst: char_p_ref, snd: char_p_ref)
|
2021-06-04 18:03:34 -07:00
|
|
|
-> char_p_boxed
|
|
|
|
{
|
|
|
|
let fst = fst.to_str(); // : &'_ str
|
|
|
|
let snd = snd.to_str(); // : &'_ str
|
|
|
|
let ccat = format!("{}{}", fst, snd).try_into().unwrap();
|
|
|
|
ccat
|
|
|
|
}
|
|
|
|
|
2021-06-08 18:15:20 -07:00
|
|
|
/// Frees a Rust-allocated string
|
2021-06-04 18:03:34 -07:00
|
|
|
#[ffi_export]
|
|
|
|
fn free_string (string: char_p_boxed)
|
|
|
|
{
|
|
|
|
drop(string)
|
|
|
|
}
|
2021-06-03 17:51:07 -07:00
|
|
|
|
|
|
|
/// A `struct` usable from both Rust and C
|
|
|
|
#[derive_ReprC]
|
|
|
|
#[repr(C)]
|
2021-06-08 18:15:20 -07:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Config {
|
|
|
|
name: char_p_boxed,
|
|
|
|
count: i64
|
2021-06-03 17:51:07 -07:00
|
|
|
}
|
|
|
|
|
2021-06-08 18:15:20 -07:00
|
|
|
/// Debug print a Point
|
2021-06-03 17:51:07 -07:00
|
|
|
#[ffi_export]
|
2021-06-08 18:15:20 -07:00
|
|
|
fn print_config(config: &Config) {
|
|
|
|
println!("{:?}", config);
|
2021-06-03 17:51:07 -07:00
|
|
|
}
|
|
|
|
|
2021-06-08 18:15:20 -07:00
|
|
|
/// Create a new Config
|
2021-06-03 17:51:07 -07:00
|
|
|
#[ffi_export]
|
2021-06-08 18:15:20 -07:00
|
|
|
fn new_config(name: char_p_ref, count: i64) -> Box<Config> {
|
|
|
|
let name = name.to_string().try_into().unwrap();
|
|
|
|
Box::new(Config { name, count })
|
2021-06-03 17:51:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[ffi_export]
|
2021-06-08 18:15:20 -07:00
|
|
|
fn free_config(config: Box<Config>) {
|
|
|
|
drop(config)
|
2021-06-03 17:51:07 -07:00
|
|
|
}
|
|
|
|
|
2021-06-10 13:40:58 -07:00
|
|
|
#[derive_ReprC]
|
|
|
|
#[ReprC::opaque]
|
|
|
|
pub struct WalletPtr {
|
|
|
|
raw: Wallet<ElectrumBlockchain, Tree>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Wallet<ElectrumBlockchain, Tree>> for WalletPtr {
|
|
|
|
fn from(wallet: Wallet<ElectrumBlockchain, Tree>) -> Self {
|
|
|
|
WalletPtr {
|
|
|
|
raw: wallet,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[ffi_export]
|
|
|
|
fn new_wallet(
|
|
|
|
name: char_p_ref,
|
|
|
|
descriptor: char_p_ref,
|
|
|
|
change_descriptor: Option<char_p_ref>,
|
|
|
|
) -> Box<WalletPtr> {
|
|
|
|
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<Box<WalletPtr>>) {
|
|
|
|
drop(wallet)
|
|
|
|
}
|
2021-06-04 23:01:51 -07:00
|
|
|
|
2021-06-03 17:51:07 -07:00
|
|
|
/// 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()
|
|
|
|
}
|