mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-16 21:20:00 +00:00
add wallet ffi auth-transfer shielded method
This commit is contained in:
parent
707ea7d379
commit
c3ca6c7563
@ -2,7 +2,7 @@ use std::{
|
|||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
ffi::{CStr, CString, c_char},
|
ffi::{CStr, CString, c_char},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::{Path, PathBuf},
|
path::Path,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,6 +101,14 @@ unsafe extern "C" {
|
|||||||
out_result: *mut FfiTransferResult,
|
out_result: *mut FfiTransferResult,
|
||||||
) -> error::WalletFfiError;
|
) -> error::WalletFfiError;
|
||||||
|
|
||||||
|
fn wallet_ffi_transfer_shielded(
|
||||||
|
handle: *mut WalletHandle,
|
||||||
|
from: *const FfiBytes32,
|
||||||
|
to_keys: *const FfiPrivateAccountKeys,
|
||||||
|
amount: *const [u8; 16],
|
||||||
|
out_result: *mut FfiTransferResult,
|
||||||
|
) -> error::WalletFfiError;
|
||||||
|
|
||||||
fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult);
|
fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult);
|
||||||
|
|
||||||
fn wallet_ffi_register_public_account(
|
fn wallet_ffi_register_public_account(
|
||||||
@ -732,6 +740,7 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
|||||||
info!("Waiting for next block creation");
|
info!("Waiting for next block creation");
|
||||||
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
|
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
|
||||||
|
|
||||||
|
// Sync private account local storage with onchain encrypted state
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut current_height = 0;
|
let mut current_height = 0;
|
||||||
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
|
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
|
||||||
@ -816,3 +825,79 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
||||||
|
let ctx = BlockingTestContext::new().unwrap();
|
||||||
|
let home = tempfile::tempdir().unwrap();
|
||||||
|
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||||
|
let from: FfiBytes32 = (&ACC_SENDER.parse::<AccountId>().unwrap()).into();
|
||||||
|
let (to, to_keys) = unsafe {
|
||||||
|
let mut out_account_id = FfiBytes32::default();
|
||||||
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
|
wallet_ffi_create_account_private(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
(&mut out_account_id) as *mut FfiBytes32,
|
||||||
|
);
|
||||||
|
wallet_ffi_get_private_account_keys(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
(&out_account_id) as *const FfiBytes32,
|
||||||
|
(&mut out_keys) as *mut FfiPrivateAccountKeys,
|
||||||
|
);
|
||||||
|
(out_account_id, out_keys)
|
||||||
|
};
|
||||||
|
let amount: [u8; 16] = 100u128.to_le_bytes();
|
||||||
|
|
||||||
|
let mut transfer_result = FfiTransferResult::default();
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_transfer_shielded(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
(&from) as *const FfiBytes32,
|
||||||
|
(&to_keys) as *const FfiPrivateAccountKeys,
|
||||||
|
(&amount) as *const [u8; 16],
|
||||||
|
(&mut transfer_result) as *mut FfiTransferResult,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
|
||||||
|
|
||||||
|
// Sync private account local storage with onchain encrypted state
|
||||||
|
unsafe {
|
||||||
|
let mut current_height = 0;
|
||||||
|
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
(&from) as *const FfiBytes32,
|
||||||
|
true,
|
||||||
|
(&mut out_balance) as *mut [u8; 16],
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
(&to) as *const FfiBytes32,
|
||||||
|
false,
|
||||||
|
(&mut out_balance) as *mut [u8; 16],
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(from_balance, 9900);
|
||||||
|
assert_eq!(to_balance, 100);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
|
||||||
|
wallet_ffi_destroy(wallet_ffi_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use crate::{
|
|||||||
error::{print_error, WalletFfiError},
|
error::{print_error, WalletFfiError},
|
||||||
types::{FfiBytes32, FfiTransferResult, WalletHandle},
|
types::{FfiBytes32, FfiTransferResult, WalletHandle},
|
||||||
wallet::get_wallet,
|
wallet::get_wallet,
|
||||||
|
FfiPrivateAccountKeys,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Send a public token transfer.
|
/// Send a public token transfer.
|
||||||
@ -101,6 +102,103 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a token transfer shielded transfer.
|
||||||
|
///
|
||||||
|
/// Transfers tokens from one private account to another on the network.
|
||||||
|
///
|
||||||
|
/// # 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
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wallet_ffi_transfer_shielded(
|
||||||
|
handle: *mut WalletHandle,
|
||||||
|
from: *const FfiBytes32,
|
||||||
|
to_keys: *const FfiPrivateAccountKeys,
|
||||||
|
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_keys.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_npk = (*to_keys).npk();
|
||||||
|
let to_ipk = match (*to_keys).ivk() {
|
||||||
|
Ok(ipk) => ipk,
|
||||||
|
Err(e) => {
|
||||||
|
print_error("Invalid viewing key");
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let amount = u128::from_le_bytes(unsafe { *amount });
|
||||||
|
|
||||||
|
let transfer = NativeTokenTransfer(&wallet);
|
||||||
|
|
||||||
|
match block_on(
|
||||||
|
transfer.send_shielded_transfer_to_outer_account(from_id, to_npk, to_ipk, 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;
|
||||||
|
}
|
||||||
|
match e {
|
||||||
|
ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds,
|
||||||
|
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
|
||||||
|
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
|
||||||
|
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
|
||||||
|
_ => WalletFfiError::InternalError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Register a public account on the network.
|
/// Register a public account on the network.
|
||||||
///
|
///
|
||||||
/// This initializes a public account on the blockchain. The account must be
|
/// This initializes a public account on the blockchain. The account must be
|
||||||
@ -179,7 +277,6 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Register a private account on the network.
|
/// Register a private account on the network.
|
||||||
///
|
///
|
||||||
/// This initializes a private account. The account must be
|
/// This initializes a private account. The account must be
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user