From b2ef5e915cd525edc89469def60ceb805cfa48fe Mon Sep 17 00:00:00 2001 From: danielSanchezQ <3danimanimal@gmail.com> Date: Tue, 17 Feb 2026 11:54:55 +0000 Subject: [PATCH] Update wallet ffi with transfer calls --- wallet-ffi/src/transfer.rs | 170 +++++++++++++++++++++++++++ wallet-ffi/wallet_ffi.h | 227 +++++++++++++++++++++++++++++++++++++ 2 files changed, 397 insertions(+) diff --git a/wallet-ffi/src/transfer.rs b/wallet-ffi/src/transfer.rs index 2c0ccc7c..c609529d 100644 --- a/wallet-ffi/src/transfer.rs +++ b/wallet-ffi/src/transfer.rs @@ -359,6 +359,176 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( } } +/// Send a shielded token transfer to an owned private account. +/// +/// Transfers tokens from a public account to a private account that is owned +/// by this wallet. Unlike `wallet_ffi_transfer_shielded` which sends to a +/// foreign account using NPK/VPK keys, this variant takes a destination +/// account ID that must belong to this wallet. +/// +/// # Parameters +/// - `handle`: Valid wallet handle +/// - `from`: Source public account ID (must be owned by this wallet) +/// - `to`: Destination private account ID (must be owned by this wallet) +/// - `amount`: Amount to transfer as little-endian [u8; 16] +/// - `out_result`: Output pointer for transfer result +/// +/// # Returns +/// - `Success` if the transfer was submitted successfully +/// - `InsufficientFunds` if the source account doesn't have enough balance +/// - `KeyNotFound` if either account's keys are not in this wallet +/// - Error code on other failures +/// +/// # 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 unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( + handle: *mut WalletHandle, + from: *const FfiBytes32, + to: *const FfiBytes32, + amount: *const [u8; 16], + out_result: *mut FfiTransferResult, +) -> WalletFfiError { + let wrapper = match get_wallet(handle) { + Ok(w) => w, + Err(e) => return e, + }; + + if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() { + print_error("Null pointer argument"); + return WalletFfiError::NullPointer; + } + + let wallet = match wrapper.core.lock() { + Ok(w) => w, + Err(e) => { + print_error(format!("Failed to lock wallet: {}", e)); + return WalletFfiError::InternalError; + } + }; + + let from_id = AccountId::new(unsafe { (*from).data }); + let to_id = AccountId::new(unsafe { (*to).data }); + let amount = u128::from_le_bytes(unsafe { *amount }); + + let transfer = NativeTokenTransfer(&wallet); + + match block_on(transfer.send_shielded_transfer(from_id, to_id, amount)) { + Ok(Ok((response, _shared_key))) => { + let tx_hash = CString::new(response.tx_hash) + .map(|s| s.into_raw()) + .unwrap_or(ptr::null_mut()); + + unsafe { + (*out_result).tx_hash = tx_hash; + (*out_result).success = true; + } + WalletFfiError::Success + } + Ok(Err(e)) => { + print_error(format!("Transfer failed: {:?}", e)); + unsafe { + (*out_result).tx_hash = ptr::null_mut(); + (*out_result).success = false; + } + map_execution_error(e) + } + Err(e) => e, + } +} + +/// Send a private token transfer to an owned private account. +/// +/// Transfers tokens from a private account to another private account that is +/// owned by this wallet. Unlike `wallet_ffi_transfer_private` which sends to a +/// foreign account using NPK/VPK keys, this variant takes a destination +/// account ID that must belong to this wallet. +/// +/// # Parameters +/// - `handle`: Valid wallet handle +/// - `from`: Source private account ID (must be owned by this wallet) +/// - `to`: Destination private account ID (must be owned by this wallet) +/// - `amount`: Amount to transfer as little-endian [u8; 16] +/// - `out_result`: Output pointer for transfer result +/// +/// # Returns +/// - `Success` if the transfer was submitted successfully +/// - `InsufficientFunds` if the source account doesn't have enough balance +/// - `KeyNotFound` if either account's keys are not in this wallet +/// - Error code on other failures +/// +/// # 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 unsafe extern "C" fn wallet_ffi_transfer_private_owned( + handle: *mut WalletHandle, + from: *const FfiBytes32, + to: *const FfiBytes32, + amount: *const [u8; 16], + out_result: *mut FfiTransferResult, +) -> WalletFfiError { + let wrapper = match get_wallet(handle) { + Ok(w) => w, + Err(e) => return e, + }; + + if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() { + print_error("Null pointer argument"); + return WalletFfiError::NullPointer; + } + + let wallet = match wrapper.core.lock() { + Ok(w) => w, + Err(e) => { + print_error(format!("Failed to lock wallet: {}", e)); + return WalletFfiError::InternalError; + } + }; + + let from_id = AccountId::new(unsafe { (*from).data }); + let to_id = AccountId::new(unsafe { (*to).data }); + let amount = u128::from_le_bytes(unsafe { *amount }); + + let transfer = NativeTokenTransfer(&wallet); + + match block_on(transfer.send_private_transfer_to_owned_account(from_id, to_id, amount)) { + Ok(Ok((response, _shared_keys))) => { + let tx_hash = CString::new(response.tx_hash) + .map(|s| s.into_raw()) + .unwrap_or(ptr::null_mut()); + + unsafe { + (*out_result).tx_hash = tx_hash; + (*out_result).success = true; + } + WalletFfiError::Success + } + Ok(Err(e)) => { + print_error(format!("Transfer failed: {:?}", e)); + unsafe { + (*out_result).tx_hash = ptr::null_mut(); + (*out_result).success = false; + } + map_execution_error(e) + } + Err(e) => e, + } +} + /// Register a public account on the network. /// /// This initializes a public account on the blockchain. The account must be diff --git a/wallet-ffi/wallet_ffi.h b/wallet-ffi/wallet_ffi.h index 0b2b0176..55f37cff 100644 --- a/wallet-ffi/wallet_ffi.h +++ b/wallet-ffi/wallet_ffi.h @@ -344,6 +344,30 @@ enum WalletFfiError wallet_ffi_get_account_public(struct WalletHandle *handle, const struct FfiBytes32 *account_id, struct FfiAccount *out_account); +/** + * Get full private account data from the local storage. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `account_id`: The account ID (32 bytes) + * - `out_account`: Output pointer for account data + * + * # Returns + * - `Success` on successful query + * - Error code on failure + * + * # 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_private(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiAccount *out_account); + /** * Free account data returned by `wallet_ffi_get_account_public`. * @@ -546,6 +570,182 @@ enum WalletFfiError wallet_ffi_transfer_public(struct WalletHandle *handle, const uint8_t (*amount)[16], struct FfiTransferResult *out_result); +/** + * Send a shielded token transfer. + * + * Transfers tokens from a public account to a private account. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `from`: Source account ID (must be owned by this wallet) + * - `to_keys`: Destination account keys + * - `amount`: Amount to transfer as little-endian [u8; 16] + * - `out_result`: Output pointer for transfer result + * + * # Returns + * - `Success` if the transfer was submitted successfully + * - `InsufficientFunds` if the source account doesn't have enough balance + * - `KeyNotFound` if the source account's signing key is not in this wallet + * - Error code on other failures + * + * # 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_keys` must be a valid pointer to a `FfiPrivateAccountKeys` 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_shielded(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiPrivateAccountKeys *to_keys, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + +/** + * Send a deshielded token transfer. + * + * Transfers tokens from a private account to a public account. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `from`: Source account ID (must be owned by this wallet) + * - `to`: Destination account ID + * - `amount`: Amount to transfer as little-endian [u8; 16] + * - `out_result`: Output pointer for transfer result + * + * # Returns + * - `Success` if the transfer was submitted successfully + * - `InsufficientFunds` if the source account doesn't have enough balance + * - `KeyNotFound` if the source account's signing key is not in this wallet + * - Error code on other failures + * + * # 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_deshielded(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiBytes32 *to, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + +/** + * Send a private token transfer. + * + * Transfers tokens from a private account to another private account. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `from`: Source account ID (must be owned by this wallet) + * - `to_keys`: Destination account keys + * - `amount`: Amount to transfer as little-endian [u8; 16] + * - `out_result`: Output pointer for transfer result + * + * # Returns + * - `Success` if the transfer was submitted successfully + * - `InsufficientFunds` if the source account doesn't have enough balance + * - `KeyNotFound` if the source account's signing key is not in this wallet + * - Error code on other failures + * + * # 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_keys` must be a valid pointer to a `FfiPrivateAccountKeys` 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_private(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiPrivateAccountKeys *to_keys, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + +/** + * Send a shielded token transfer to an owned private account. + * + * Transfers tokens from a public account to a private account that is owned + * by this wallet. Unlike `wallet_ffi_transfer_shielded` which sends to a + * foreign account using NPK/VPK keys, this variant takes a destination + * account ID that must belong to this wallet. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `from`: Source public account ID (must be owned by this wallet) + * - `to`: Destination private account ID (must be owned by this wallet) + * - `amount`: Amount to transfer as little-endian [u8; 16] + * - `out_result`: Output pointer for transfer result + * + * # Returns + * - `Success` if the transfer was submitted successfully + * - `InsufficientFunds` if the source account doesn't have enough balance + * - `KeyNotFound` if either account's keys are not in this wallet + * - Error code on other failures + * + * # 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_shielded_owned(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiBytes32 *to, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + +/** + * Send a private token transfer to an owned private account. + * + * Transfers tokens from a private account to another private account that is + * owned by this wallet. Unlike `wallet_ffi_transfer_private` which sends to a + * foreign account using NPK/VPK keys, this variant takes a destination + * account ID that must belong to this wallet. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `from`: Source private account ID (must be owned by this wallet) + * - `to`: Destination private account ID (must be owned by this wallet) + * - `amount`: Amount to transfer as little-endian [u8; 16] + * - `out_result`: Output pointer for transfer result + * + * # Returns + * - `Success` if the transfer was submitted successfully + * - `InsufficientFunds` if the source account doesn't have enough balance + * - `KeyNotFound` if either account's keys are not in this wallet + * - Error code on other failures + * + * # 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_private_owned(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiBytes32 *to, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + /** * Register a public account on the network. * @@ -573,6 +773,33 @@ enum WalletFfiError wallet_ffi_register_public_account(struct WalletHandle *hand const struct FfiBytes32 *account_id, struct FfiTransferResult *out_result); +/** + * Register a private account on the network. + * + * This initializes a private account. The account must be + * owned by this wallet. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `account_id`: Account ID to register + * - `out_result`: Output pointer for registration result + * + * # Returns + * - `Success` if the registration was submitted successfully + * - Error code on failure + * + * # 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_private_account(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiTransferResult *out_result); + /** * Free a transfer result returned by `wallet_ffi_transfer_public` or * `wallet_ffi_register_public_account`.