Re-structure errors and clippy happy

This commit is contained in:
Daniel 2026-01-26 10:29:37 +01:00
parent 6d883d5528
commit a97066c41d
8 changed files with 221 additions and 150 deletions

View File

@ -5,7 +5,7 @@ use std::ptr;
use nssa::AccountId;
use crate::block_on;
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
use crate::types::{
FfiAccount, FfiAccountList, FfiAccountListEntry, FfiBytes32, FfiProgramId, WalletHandle,
};
@ -23,8 +23,12 @@ use crate::wallet::get_wallet;
/// # Returns
/// - `Success` on successful creation
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_create_account_public(
pub unsafe extern "C" fn wallet_ffi_create_account_public(
handle: *mut WalletHandle,
out_account_id: *mut FfiBytes32,
) -> WalletFfiError {
@ -34,14 +38,14 @@ pub extern "C" fn wallet_ffi_create_account_public(
};
if out_account_id.is_null() {
set_last_error("Null output pointer for account_id");
print_error("Null output pointer for account_id");
return WalletFfiError::NullPointer;
}
let mut wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -67,8 +71,12 @@ pub extern "C" fn wallet_ffi_create_account_public(
/// # Returns
/// - `Success` on successful creation
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_create_account_private(
pub unsafe extern "C" fn wallet_ffi_create_account_private(
handle: *mut WalletHandle,
out_account_id: *mut FfiBytes32,
) -> WalletFfiError {
@ -78,14 +86,14 @@ pub extern "C" fn wallet_ffi_create_account_private(
};
if out_account_id.is_null() {
set_last_error("Null output pointer for account_id");
print_error("Null output pointer for account_id");
return WalletFfiError::NullPointer;
}
let mut wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -113,8 +121,12 @@ pub extern "C" fn wallet_ffi_create_account_private(
///
/// # Memory
/// The returned list must be freed with `wallet_ffi_free_account_list()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `out_list` must be a valid pointer to a `FfiAccountList` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_list_accounts(
pub unsafe extern "C" fn wallet_ffi_list_accounts(
handle: *mut WalletHandle,
out_list: *mut FfiAccountList,
) -> WalletFfiError {
@ -124,14 +136,14 @@ pub extern "C" fn wallet_ffi_list_accounts(
};
if out_list.is_null() {
set_last_error("Null output pointer for account list");
print_error("Null output pointer for account list");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -196,7 +208,7 @@ pub extern "C" fn wallet_ffi_list_accounts(
/// # Safety
/// The list must be either null or a valid list returned by `wallet_ffi_list_accounts`.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_account_list(list: *mut FfiAccountList) {
pub unsafe extern "C" fn wallet_ffi_free_account_list(list: *mut FfiAccountList) {
if list.is_null() {
return;
}
@ -224,8 +236,13 @@ pub extern "C" fn wallet_ffi_free_account_list(list: *mut FfiAccountList) {
/// # Returns
/// - `Success` on successful query
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_balance` must be a valid pointer to a `[u8; 16]` array
#[no_mangle]
pub extern "C" fn wallet_ffi_get_balance(
pub unsafe extern "C" fn wallet_ffi_get_balance(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
is_public: bool,
@ -237,14 +254,14 @@ pub extern "C" fn wallet_ffi_get_balance(
};
if account_id.is_null() || out_balance.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -255,7 +272,7 @@ pub extern "C" fn wallet_ffi_get_balance(
match block_on(wallet.get_account_balance(account_id)) {
Ok(Ok(b)) => b,
Ok(Err(e)) => {
set_last_error(format!("Failed to get balance: {}", e));
print_error(format!("Failed to get balance: {}", e));
return WalletFfiError::NetworkError;
}
Err(e) => return e,
@ -264,7 +281,7 @@ pub extern "C" fn wallet_ffi_get_balance(
match wallet.get_account_private(&account_id) {
Some(account) => account.balance,
None => {
set_last_error("Private account not found");
print_error("Private account not found");
return WalletFfiError::AccountNotFound;
}
}
@ -290,8 +307,13 @@ pub extern "C" fn wallet_ffi_get_balance(
///
/// # Memory
/// The account data must be freed with `wallet_ffi_free_account_data()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_account` must be a valid pointer to a `FfiAccount` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_get_account_public(
pub unsafe extern "C" fn wallet_ffi_get_account_public(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_account: *mut FfiAccount,
@ -302,14 +324,14 @@ pub extern "C" fn wallet_ffi_get_account_public(
};
if account_id.is_null() || out_account.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -319,7 +341,7 @@ pub extern "C" fn wallet_ffi_get_account_public(
let account = match block_on(wallet.get_account_public(account_id)) {
Ok(Ok(a)) => a,
Ok(Err(e)) => {
set_last_error(format!("Failed to get account: {}", e));
print_error(format!("Failed to get account: {}", e));
return WalletFfiError::NetworkError;
}
Err(e) => return e,
@ -356,7 +378,7 @@ pub extern "C" fn wallet_ffi_get_account_public(
/// The account must be either null or a valid account returned by
/// `wallet_ffi_get_account_public`.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_account_data(account: *mut FfiAccount) {
pub unsafe extern "C" fn wallet_ffi_free_account_data(account: *mut FfiAccount) {
if account.is_null() {
return;
}

View File

@ -1,10 +1,6 @@
//! Error handling for the FFI layer.
//!
//! Uses numeric error codes with a thread-local last error message.
use std::cell::RefCell;
use std::ffi::{c_char, CString};
use std::ptr;
//! Uses numeric error codes with error messages printed to stderr.
/// Error codes returned by FFI functions.
#[repr(C)]
@ -44,50 +40,7 @@ pub enum WalletFfiError {
InternalError = 99,
}
// Thread-local storage for the last error message
thread_local! {
static LAST_ERROR: RefCell<Option<String>> = const { RefCell::new(None) };
}
/// Set the last error message for the current thread.
pub fn set_last_error(msg: impl Into<String>) {
LAST_ERROR.with(|e| {
*e.borrow_mut() = Some(msg.into());
});
}
/// Clear the last error message.
pub fn clear_last_error() {
LAST_ERROR.with(|e| {
*e.borrow_mut() = None;
});
}
/// Get the last error message.
///
/// Returns a pointer to a null-terminated string, or null if no error is set.
/// The caller owns the returned string and must free it with
/// `wallet_ffi_free_error_string`.
#[no_mangle]
pub extern "C" fn wallet_ffi_get_last_error() -> *mut c_char {
LAST_ERROR.with(|e| match e.borrow_mut().take() {
Some(msg) => CString::new(msg)
.map(|s| s.into_raw())
.unwrap_or(ptr::null_mut()),
None => ptr::null_mut(),
})
}
/// Free an error string returned by `wallet_ffi_get_last_error`.
///
/// # Safety
/// The pointer must be either null or a valid pointer returned by
/// `wallet_ffi_get_last_error`.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_error_string(ptr: *mut c_char) {
if !ptr.is_null() {
unsafe {
drop(CString::from_raw(ptr));
}
}
/// Log an error message to stderr.
pub fn print_error(msg: impl Into<String>) {
eprintln!("[wallet-ffi] {}", msg.into());
}

View File

@ -4,7 +4,7 @@ use std::ptr;
use nssa::{AccountId, PublicKey};
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
use crate::types::{FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, WalletHandle};
use crate::wallet::get_wallet;
@ -21,8 +21,13 @@ use crate::wallet::get_wallet;
/// - `Success` on successful retrieval
/// - `KeyNotFound` if the account's key is not in this wallet
/// - Error code on other failures
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_public_key` must be a valid pointer to a `FfiPublicAccountKey` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_get_public_account_key(
pub unsafe extern "C" fn wallet_ffi_get_public_account_key(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_public_key: *mut FfiPublicAccountKey,
@ -33,14 +38,14 @@ pub extern "C" fn wallet_ffi_get_public_account_key(
};
if account_id.is_null() || out_public_key.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -50,7 +55,7 @@ pub extern "C" fn wallet_ffi_get_public_account_key(
let private_key = match wallet.get_account_public_signing_key(&account_id) {
Some(k) => k,
None => {
set_last_error("Public account key not found in wallet");
print_error("Public account key not found in wallet");
return WalletFfiError::KeyNotFound;
}
};
@ -81,8 +86,13 @@ pub extern "C" fn wallet_ffi_get_public_account_key(
///
/// # Memory
/// The keys structure must be freed with `wallet_ffi_free_private_account_keys()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_get_private_account_keys(
pub unsafe extern "C" fn wallet_ffi_get_private_account_keys(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_keys: *mut FfiPrivateAccountKeys,
@ -93,14 +103,14 @@ pub extern "C" fn wallet_ffi_get_private_account_keys(
};
if account_id.is_null() || out_keys.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -110,7 +120,7 @@ pub extern "C" fn wallet_ffi_get_private_account_keys(
let (key_chain, _account) = match wallet.storage().user_data.get_private_account(&account_id) {
Some(k) => k,
None => {
set_last_error("Private account not found in wallet");
print_error("Private account not found in wallet");
return WalletFfiError::AccountNotFound;
}
};
@ -140,7 +150,7 @@ pub extern "C" fn wallet_ffi_get_private_account_keys(
/// The keys must be either null or valid keys returned by
/// `wallet_ffi_get_private_account_keys`.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPrivateAccountKeys) {
pub unsafe extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPrivateAccountKeys) {
if keys.is_null() {
return;
}
@ -168,12 +178,15 @@ pub extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPrivateAcco
///
/// # Memory
/// The returned string must be freed with `wallet_ffi_free_string()`.
///
/// # Safety
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_account_id_to_base58(
pub unsafe extern "C" fn wallet_ffi_account_id_to_base58(
account_id: *const FfiBytes32,
) -> *mut std::ffi::c_char {
if account_id.is_null() {
set_last_error("Null account_id pointer");
print_error("Null account_id pointer");
return ptr::null_mut();
}
@ -183,7 +196,7 @@ pub extern "C" fn wallet_ffi_account_id_to_base58(
match std::ffi::CString::new(base58_str) {
Ok(s) => s.into_raw(),
Err(e) => {
set_last_error(format!("Failed to create C string: {}", e));
print_error(format!("Failed to create C string: {}", e));
ptr::null_mut()
}
}
@ -199,13 +212,17 @@ pub extern "C" fn wallet_ffi_account_id_to_base58(
/// - `Success` on successful parsing
/// - `InvalidAccountId` if the string is not valid Base58
/// - Error code on other failures
///
/// # Safety
/// - `base58_str` must be a valid pointer to a null-terminated C string
/// - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_account_id_from_base58(
pub unsafe extern "C" fn wallet_ffi_account_id_from_base58(
base58_str: *const std::ffi::c_char,
out_account_id: *mut FfiBytes32,
) -> WalletFfiError {
if base58_str.is_null() || out_account_id.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
@ -213,7 +230,7 @@ pub extern "C" fn wallet_ffi_account_id_from_base58(
let str_slice = match c_str.to_str() {
Ok(s) => s,
Err(e) => {
set_last_error(format!("Invalid UTF-8: {}", e));
print_error(format!("Invalid UTF-8: {}", e));
return WalletFfiError::InvalidUtf8;
}
};
@ -221,7 +238,7 @@ pub extern "C" fn wallet_ffi_account_id_from_base58(
let account_id: AccountId = match str_slice.parse() {
Ok(id) => id,
Err(e) => {
set_last_error(format!("Invalid Base58 account ID: {}", e));
print_error(format!("Invalid Base58 account ID: {}", e));
return WalletFfiError::InvalidAccountId;
}
};

View File

@ -32,7 +32,7 @@ use once_cell::sync::OnceCell;
use std::sync::Arc;
use tokio::runtime::Runtime;
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
// Re-export public types for cbindgen
pub use error::WalletFfiError as FfiError;
@ -44,7 +44,7 @@ static RUNTIME: OnceCell<Arc<Runtime>> = OnceCell::new();
/// Get a reference to the global runtime.
pub(crate) fn get_runtime() -> Result<&'static Arc<Runtime>, WalletFfiError> {
RUNTIME.get().ok_or_else(|| {
set_last_error("Runtime not initialized. Call wallet_ffi_init_runtime() first.");
print_error("Runtime not initialized. Call wallet_ffi_init_runtime() first.");
WalletFfiError::RuntimeError
})
}
@ -75,7 +75,7 @@ pub extern "C" fn wallet_ffi_init_runtime() -> WalletFfiError {
match result {
Ok(_) => WalletFfiError::Success,
Err(e) => {
set_last_error(format!("Failed to initialize runtime: {}", e));
print_error(format!("Failed to initialize runtime: {}", e));
WalletFfiError::RuntimeError
}
}

View File

@ -1,7 +1,7 @@
//! Block synchronization functions.
use crate::block_on;
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
use crate::types::WalletHandle;
use crate::wallet::get_wallet;
@ -22,8 +22,11 @@ use crate::wallet::get_wallet;
/// # Note
/// This operation can take a while for large block ranges. The wallet
/// internally uses a progress bar which may output to stdout.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
#[no_mangle]
pub extern "C" fn wallet_ffi_sync_to_block(
pub unsafe extern "C" fn wallet_ffi_sync_to_block(
handle: *mut WalletHandle,
block_id: u64,
) -> WalletFfiError {
@ -35,7 +38,7 @@ pub extern "C" fn wallet_ffi_sync_to_block(
let mut wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -43,7 +46,7 @@ pub extern "C" fn wallet_ffi_sync_to_block(
match block_on(wallet.sync_to_block(block_id)) {
Ok(Ok(())) => WalletFfiError::Success,
Ok(Err(e)) => {
set_last_error(format!("Sync failed: {}", e));
print_error(format!("Sync failed: {}", e));
WalletFfiError::SyncError
}
Err(e) => e,
@ -59,8 +62,12 @@ pub extern "C" fn wallet_ffi_sync_to_block(
/// # Returns
/// - `Success` on success
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `out_block_id` must be a valid pointer to a `u64`
#[no_mangle]
pub extern "C" fn wallet_ffi_get_last_synced_block(
pub unsafe extern "C" fn wallet_ffi_get_last_synced_block(
handle: *mut WalletHandle,
out_block_id: *mut u64,
) -> WalletFfiError {
@ -70,14 +77,14 @@ pub extern "C" fn wallet_ffi_get_last_synced_block(
};
if out_block_id.is_null() {
set_last_error("Null output pointer");
print_error("Null output pointer");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -99,8 +106,12 @@ pub extern "C" fn wallet_ffi_get_last_synced_block(
/// - `Success` on success
/// - `NetworkError` if the sequencer is unreachable
/// - Error code on other failures
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `out_block_height` must be a valid pointer to a `u64`
#[no_mangle]
pub extern "C" fn wallet_ffi_get_current_block_height(
pub unsafe extern "C" fn wallet_ffi_get_current_block_height(
handle: *mut WalletHandle,
out_block_height: *mut u64,
) -> WalletFfiError {
@ -110,14 +121,14 @@ pub extern "C" fn wallet_ffi_get_current_block_height(
};
if out_block_height.is_null() {
set_last_error("Null output pointer");
print_error("Null output pointer");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -130,7 +141,7 @@ pub extern "C" fn wallet_ffi_get_current_block_height(
WalletFfiError::Success
}
Ok(Err(e)) => {
set_last_error(format!("Failed to get block height: {:?}", e));
print_error(format!("Failed to get block height: {:?}", e));
WalletFfiError::NetworkError
}
Err(e) => e,

View File

@ -8,7 +8,7 @@ use nssa::AccountId;
use wallet::program_facades::native_token_transfer::NativeTokenTransfer;
use crate::block_on;
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
use crate::types::{FfiBytes32, FfiTransferResult, WalletHandle};
use crate::wallet::get_wallet;
@ -31,8 +31,15 @@ use crate::wallet::get_wallet;
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `from` must be a valid pointer to a `FfiBytes32` struct
/// - `to` must be a valid pointer to a `FfiBytes32` struct
/// - `amount` must be a valid pointer to a `[u8; 16]` array
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_transfer_public(
pub unsafe extern "C" fn wallet_ffi_transfer_public(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to: *const FfiBytes32,
@ -45,14 +52,14 @@ pub extern "C" fn wallet_ffi_transfer_public(
};
if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -76,7 +83,7 @@ pub extern "C" fn wallet_ffi_transfer_public(
WalletFfiError::Success
}
Ok(Err(e)) => {
set_last_error(format!("Transfer failed: {:?}", e));
print_error(format!("Transfer failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
@ -109,8 +116,13 @@ pub extern "C" fn wallet_ffi_transfer_public(
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub extern "C" fn wallet_ffi_register_public_account(
pub unsafe extern "C" fn wallet_ffi_register_public_account(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_result: *mut FfiTransferResult,
@ -121,14 +133,14 @@ pub extern "C" fn wallet_ffi_register_public_account(
};
if account_id.is_null() || out_result.is_null() {
set_last_error("Null pointer argument");
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -150,7 +162,7 @@ pub extern "C" fn wallet_ffi_register_public_account(
WalletFfiError::Success
}
Ok(Err(e)) => {
set_last_error(format!("Registration failed: {:?}", e));
print_error(format!("Registration failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
@ -172,7 +184,7 @@ pub extern "C" fn wallet_ffi_register_public_account(
/// # Safety
/// The result must be either null or a valid result from a transfer function.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult) {
pub unsafe extern "C" fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult) {
if result.is_null() {
return;
}

View File

@ -8,7 +8,7 @@ use std::sync::Mutex;
use wallet::WalletCore;
use crate::block_on;
use crate::error::{set_last_error, WalletFfiError};
use crate::error::{print_error, WalletFfiError};
use crate::types::WalletHandle;
/// Internal wrapper around WalletCore with mutex for thread safety.
@ -21,7 +21,7 @@ pub(crate) fn get_wallet(
handle: *mut WalletHandle,
) -> Result<&'static WalletWrapper, WalletFfiError> {
if handle.is_null() {
set_last_error("Null wallet handle");
print_error("Null wallet handle");
return Err(WalletFfiError::NullPointer);
}
Ok(unsafe { &*(handle as *mut WalletWrapper) })
@ -33,7 +33,7 @@ pub(crate) fn get_wallet_mut(
handle: *mut WalletHandle,
) -> Result<&'static mut WalletWrapper, WalletFfiError> {
if handle.is_null() {
set_last_error("Null wallet handle");
print_error("Null wallet handle");
return Err(WalletFfiError::NullPointer);
}
Ok(unsafe { &mut *(handle as *mut WalletWrapper) })
@ -42,7 +42,7 @@ pub(crate) fn get_wallet_mut(
/// Helper to convert a C string to a Rust PathBuf.
fn c_str_to_path(ptr: *const c_char, name: &str) -> Result<PathBuf, WalletFfiError> {
if ptr.is_null() {
set_last_error(format!("Null pointer for {}", name));
print_error(format!("Null pointer for {}", name));
return Err(WalletFfiError::NullPointer);
}
@ -50,7 +50,7 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result<PathBuf, WalletFfiErr
match c_str.to_str() {
Ok(s) => Ok(PathBuf::from(s)),
Err(e) => {
set_last_error(format!("Invalid UTF-8 in {}: {}", name, e));
print_error(format!("Invalid UTF-8 in {}: {}", name, e));
Err(WalletFfiError::InvalidUtf8)
}
}
@ -59,7 +59,7 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result<PathBuf, WalletFfiErr
/// Helper to convert a C string to a Rust String.
fn c_str_to_string(ptr: *const c_char, name: &str) -> Result<String, WalletFfiError> {
if ptr.is_null() {
set_last_error(format!("Null pointer for {}", name));
print_error(format!("Null pointer for {}", name));
return Err(WalletFfiError::NullPointer);
}
@ -67,7 +67,7 @@ fn c_str_to_string(ptr: *const c_char, name: &str) -> Result<String, WalletFfiEr
match c_str.to_str() {
Ok(s) => Ok(s.to_string()),
Err(e) => {
set_last_error(format!("Invalid UTF-8 in {}: {}", name, e));
print_error(format!("Invalid UTF-8 in {}: {}", name, e));
Err(WalletFfiError::InvalidUtf8)
}
}
@ -90,7 +90,7 @@ fn c_str_to_string(ptr: *const c_char, name: &str) -> Result<String, WalletFfiEr
/// # Safety
/// All string parameters must be valid null-terminated UTF-8 strings.
#[no_mangle]
pub extern "C" fn wallet_ffi_create_new(
pub unsafe extern "C" fn wallet_ffi_create_new(
config_path: *const c_char,
storage_path: *const c_char,
password: *const c_char,
@ -118,7 +118,7 @@ pub extern "C" fn wallet_ffi_create_new(
Box::into_raw(wrapper) as *mut WalletHandle
}
Err(e) => {
set_last_error(format!("Failed to create wallet: {}", e));
print_error(format!("Failed to create wallet: {}", e));
ptr::null_mut()
}
}
@ -139,7 +139,7 @@ pub extern "C" fn wallet_ffi_create_new(
/// # Safety
/// All string parameters must be valid null-terminated UTF-8 strings.
#[no_mangle]
pub extern "C" fn wallet_ffi_open(
pub unsafe extern "C" fn wallet_ffi_open(
config_path: *const c_char,
storage_path: *const c_char,
) -> *mut WalletHandle {
@ -161,7 +161,7 @@ pub extern "C" fn wallet_ffi_open(
Box::into_raw(wrapper) as *mut WalletHandle
}
Err(e) => {
set_last_error(format!("Failed to open wallet: {}", e));
print_error(format!("Failed to open wallet: {}", e));
ptr::null_mut()
}
}
@ -176,7 +176,7 @@ pub extern "C" fn wallet_ffi_open(
/// or `wallet_ffi_open()`.
/// - The handle must not be used after this call.
#[no_mangle]
pub extern "C" fn wallet_ffi_destroy(handle: *mut WalletHandle) {
pub unsafe extern "C" fn wallet_ffi_destroy(handle: *mut WalletHandle) {
if !handle.is_null() {
unsafe {
drop(Box::from_raw(handle as *mut WalletWrapper));
@ -195,8 +195,11 @@ pub extern "C" fn wallet_ffi_destroy(handle: *mut WalletHandle) {
/// # Returns
/// - `Success` on successful save
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
#[no_mangle]
pub extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfiError {
pub unsafe extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
@ -205,7 +208,7 @@ pub extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfiError {
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
@ -213,7 +216,7 @@ pub extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfiError {
match block_on(wallet.store_persistent_data()) {
Ok(Ok(())) => WalletFfiError::Success,
Ok(Err(e)) => {
set_last_error(format!("Failed to save wallet: {}", e));
print_error(format!("Failed to save wallet: {}", e));
WalletFfiError::StorageError
}
Err(e) => e,
@ -228,8 +231,11 @@ pub extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfiError {
/// # Returns
/// - Pointer to null-terminated string on success (caller must free with `wallet_ffi_free_string()`)
/// - Null pointer on error
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
#[no_mangle]
pub extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *mut c_char {
pub unsafe extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *mut c_char {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(_) => return ptr::null_mut(),
@ -238,7 +244,7 @@ pub extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *m
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
set_last_error(format!("Failed to lock wallet: {}", e));
print_error(format!("Failed to lock wallet: {}", e));
return ptr::null_mut();
}
};
@ -248,7 +254,7 @@ pub extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *m
match std::ffi::CString::new(addr) {
Ok(s) => s.into_raw(),
Err(e) => {
set_last_error(format!("Invalid sequencer address: {}", e));
print_error(format!("Invalid sequencer address: {}", e));
ptr::null_mut()
}
}
@ -259,7 +265,7 @@ pub extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *m
/// # Safety
/// The pointer must be either null or a valid string returned by an FFI function.
#[no_mangle]
pub extern "C" fn wallet_ffi_free_string(ptr: *mut c_char) {
pub unsafe extern "C" fn wallet_ffi_free_string(ptr: *mut c_char) {
if !ptr.is_null() {
unsafe {
drop(std::ffi::CString::from_raw(ptr));

View File

@ -240,6 +240,10 @@ bool wallet_ffi_runtime_initialized(void);
* # Returns
* - `Success` on successful creation
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
*/
enum WalletFfiError wallet_ffi_create_account_public(struct WalletHandle *handle,
struct FfiBytes32 *out_account_id);
@ -257,6 +261,10 @@ enum WalletFfiError wallet_ffi_create_account_public(struct WalletHandle *handle
* # Returns
* - `Success` on successful creation
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
*/
enum WalletFfiError wallet_ffi_create_account_private(struct WalletHandle *handle,
struct FfiBytes32 *out_account_id);
@ -276,6 +284,10 @@ enum WalletFfiError wallet_ffi_create_account_private(struct WalletHandle *handl
*
* # Memory
* The returned list must be freed with `wallet_ffi_free_account_list()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `out_list` must be a valid pointer to a `FfiAccountList` struct
*/
enum WalletFfiError wallet_ffi_list_accounts(struct WalletHandle *handle,
struct FfiAccountList *out_list);
@ -303,6 +315,11 @@ void wallet_ffi_free_account_list(struct FfiAccountList *list);
* # Returns
* - `Success` on successful query
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_balance` must be a valid pointer to a `[u8; 16]` array
*/
enum WalletFfiError wallet_ffi_get_balance(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
@ -323,6 +340,11 @@ enum WalletFfiError wallet_ffi_get_balance(struct WalletHandle *handle,
*
* # Memory
* The account data must be freed with `wallet_ffi_free_account_data()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_account` must be a valid pointer to a `FfiAccount` struct
*/
enum WalletFfiError wallet_ffi_get_account_public(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
@ -337,24 +359,6 @@ enum WalletFfiError wallet_ffi_get_account_public(struct WalletHandle *handle,
*/
void wallet_ffi_free_account_data(struct FfiAccount *account);
/**
* Get the last error message.
*
* Returns a pointer to a null-terminated string, or null if no error is set.
* The caller owns the returned string and must free it with
* `wallet_ffi_free_error_string`.
*/
char *wallet_ffi_get_last_error(void);
/**
* Free an error string returned by `wallet_ffi_get_last_error`.
*
* # Safety
* The pointer must be either null or a valid pointer returned by
* `wallet_ffi_get_last_error`.
*/
void wallet_ffi_free_error_string(char *ptr);
/**
* Get the public key for a public account.
*
@ -369,6 +373,11 @@ void wallet_ffi_free_error_string(char *ptr);
* - `Success` on successful retrieval
* - `KeyNotFound` if the account's key is not in this wallet
* - Error code on other failures
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_public_key` must be a valid pointer to a `FfiPublicAccountKey` struct
*/
enum WalletFfiError wallet_ffi_get_public_account_key(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
@ -392,6 +401,11 @@ enum WalletFfiError wallet_ffi_get_public_account_key(struct WalletHandle *handl
*
* # Memory
* The keys structure must be freed with `wallet_ffi_free_private_account_keys()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
*/
enum WalletFfiError wallet_ffi_get_private_account_keys(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
@ -418,6 +432,9 @@ void wallet_ffi_free_private_account_keys(struct FfiPrivateAccountKeys *keys);
*
* # Memory
* The returned string must be freed with `wallet_ffi_free_string()`.
*
* # Safety
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
*/
char *wallet_ffi_account_id_to_base58(const struct FfiBytes32 *account_id);
@ -432,6 +449,10 @@ char *wallet_ffi_account_id_to_base58(const struct FfiBytes32 *account_id);
* - `Success` on successful parsing
* - `InvalidAccountId` if the string is not valid Base58
* - Error code on other failures
*
* # Safety
* - `base58_str` must be a valid pointer to a null-terminated C string
* - `out_account_id` must be a valid pointer to a `FfiBytes32` struct
*/
enum WalletFfiError wallet_ffi_account_id_from_base58(const char *base58_str,
struct FfiBytes32 *out_account_id);
@ -454,6 +475,9 @@ enum WalletFfiError wallet_ffi_account_id_from_base58(const char *base58_str,
* # Note
* This operation can take a while for large block ranges. The wallet
* internally uses a progress bar which may output to stdout.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
*/
enum WalletFfiError wallet_ffi_sync_to_block(struct WalletHandle *handle, uint64_t block_id);
@ -467,6 +491,10 @@ enum WalletFfiError wallet_ffi_sync_to_block(struct WalletHandle *handle, uint64
* # Returns
* - `Success` on success
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `out_block_id` must be a valid pointer to a `u64`
*/
enum WalletFfiError wallet_ffi_get_last_synced_block(struct WalletHandle *handle,
uint64_t *out_block_id);
@ -482,6 +510,10 @@ enum WalletFfiError wallet_ffi_get_last_synced_block(struct WalletHandle *handle
* - `Success` on success
* - `NetworkError` if the sequencer is unreachable
* - Error code on other failures
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `out_block_height` must be a valid pointer to a `u64`
*/
enum WalletFfiError wallet_ffi_get_current_block_height(struct WalletHandle *handle,
uint64_t *out_block_height);
@ -506,6 +538,13 @@ enum WalletFfiError wallet_ffi_get_current_block_height(struct WalletHandle *han
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `from` must be a valid pointer to a `FfiBytes32` struct
* - `to` must be a valid pointer to a `FfiBytes32` struct
* - `amount` must be a valid pointer to a `[u8; 16]` array
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_transfer_public(struct WalletHandle *handle,
const struct FfiBytes32 *from,
@ -530,6 +569,11 @@ enum WalletFfiError wallet_ffi_transfer_public(struct WalletHandle *handle,
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_register_public_account(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
@ -608,6 +652,9 @@ void wallet_ffi_destroy(struct WalletHandle *handle);
* # Returns
* - `Success` on successful save
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
*/
enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle);
@ -620,6 +667,9 @@ enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle);
* # Returns
* - Pointer to null-terminated string on success (caller must free with `wallet_ffi_free_string()`)
* - Null pointer on error
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
*/
char *wallet_ffi_get_sequencer_addr(struct WalletHandle *handle);