use std::cell::Cell;
use std::ops::BitOr;
use std::rc::Rc;
use serde_json::Value;
use crate::{check_at, error_codes, ffi, to_cstring, Mesmo, MesmoShared, MesmoError, Network, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SigningRole(pub u32);
impl SigningRole {
pub const PAYMENT: SigningRole = SigningRole(1);
pub const STAKE: SigningRole = SigningRole(1 << 1);
pub const DREP: SigningRole = SigningRole(1 << 2);
pub const COMMITTEE_COLD: SigningRole = SigningRole(1 << 3);
pub const COMMITTEE_HOT: SigningRole = SigningRole(1 << 4);
}
impl BitOr for SigningRole {
type Output = SigningRole;
fn bitor(self, rhs: SigningRole) -> SigningRole {
SigningRole(self.0 | rhs.0)
}
}
pub struct AccountsApi<'a> {
pub(crate) lib: &'a Mesmo,
}
impl<'a> AccountsApi<'a> {
pub fn from_mnemonic(
&self,
mnemonic: &str,
network: Network,
account_index: u32,
address_index: u32,
) -> Result<Account> {
let mnemonic_cs = to_cstring(mnemonic)?;
let mut handle: i64 = 0;
let thread = self.lib.shared.thread()?;
let rc = unsafe {
ffi::mesmo_account_open_mnemonic(
thread,
network.into(),
mnemonic_cs.as_ptr(),
account_index as i32,
address_index as i32,
&mut handle,
)
};
check_at(thread, rc)?;
Ok(Account {
shared: Rc::clone(&self.lib.shared),
handle: Cell::new(handle),
})
}
pub fn create(&self, network: Network) -> Result<Account> {
let mut handle: i64 = 0;
let thread = self.lib.shared.thread()?;
let rc = unsafe { ffi::mesmo_account_create_handle(thread, network.into(), &mut handle) };
check_at(thread, rc)?;
Ok(Account {
shared: Rc::clone(&self.lib.shared),
handle: Cell::new(handle),
})
}
}
pub struct Account {
shared: Rc<MesmoShared>,
handle: Cell<i64>,
}
impl Account {
pub fn info(&self) -> Result<Value> {
let thread = self.shared.thread()?;
let rc = unsafe { ffi::mesmo_account_get_info(thread, self.handle.get()) };
let json = check_at(thread, rc)?;
serde_json::from_str(&json).map_err(|e| MesmoError {
code: error_codes::MESMO_ERROR_SERIALIZATION,
message: format!("Failed to parse account info: {}", e),
})
}
pub fn sign_tx(&self, tx_cbor_hex: &str, roles: SigningRole) -> Result<String> {
let tx_cs = to_cstring(tx_cbor_hex)?;
let thread = self.shared.thread()?;
let rc = unsafe {
ffi::mesmo_account_sign_tx_handle(thread, self.handle.get(), tx_cs.as_ptr(), roles.0 as i32)
};
check_at(thread, rc)
}
pub fn export_recovery_phrase(&self) -> Result<String> {
let thread = self.shared.thread()?;
let mut out: *mut std::os::raw::c_char = std::ptr::null_mut();
let rc = unsafe {
ffi::mesmo_account_export_recovery_phrase(thread, self.handle.get(), &mut out)
};
if rc != crate::error_codes::MESMO_SUCCESS {
return Err(crate::MesmoError { code: rc, message: crate::get_error_at(thread) });
}
let phrase = unsafe { std::ffi::CStr::from_ptr(out) }
.to_string_lossy()
.into_owned();
unsafe { ffi::mesmo_free_string(thread, out) };
Ok(phrase)
}
pub fn close(&self) -> Result<()> {
let handle = self.handle.replace(0); if handle != 0 {
if let Ok(thread) = self.shared.thread() {
let rc = unsafe { ffi::mesmo_account_close(thread, handle) };
check_at(thread, rc)?;
}
}
Ok(())
}
}
impl Drop for Account {
fn drop(&mut self) {
let _ = self.close(); }
}
impl std::fmt::Debug for Account {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let handle = self.handle.get();
if handle == 0 {
write!(f, "<mesmo::Account closed>")
} else {
write!(f, "<mesmo::Account handle={}>", handle)
}
}
}