mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-02-17 20:03:21 +00:00
Merge pull request #332 from logos-blockchain/schouhy/finish-auth-transfer-ffi-functionality
Add auth transfer FFI full functionality
This commit is contained in:
commit
2ac5d8d7de
11
.deny.toml
11
.deny.toml
@ -12,6 +12,7 @@ ignore = [
|
||||
{ id = "RUSTSEC-2024-0436", reason = "`paste` has a security vulnerability; consider using an alternative. Use `cargo tree -p paste -i > tmp.txt` to check the dependency tree." },
|
||||
{ id = "RUSTSEC-2025-0055", reason = "`tracing-subscriber` v0.2.25 pulled in by ark-relations v0.4.0 - will be addressed before mainnet" },
|
||||
{ id = "RUSTSEC-2025-0141", reason = "`bincode` is unmaintained but continuing to use it." },
|
||||
{ id = "RUSTSEC-2023-0089", reason = "atomic-polyfill is pulled transitively via risc0-zkvm; waiting on upstream fix (see https://github.com/risc0/risc0/issues/3453)" },
|
||||
]
|
||||
yanked = "deny"
|
||||
unused-ignored-advisory = "deny"
|
||||
@ -35,6 +36,16 @@ allow = [
|
||||
"Unicode-3.0",
|
||||
"Zlib",
|
||||
]
|
||||
exceptions = [
|
||||
# TEMP: Pending legal review. Pulled transitively via `risc0-zkvm`
|
||||
{ name = "downloader", version = "0.2.8", allow = ["LGPL-3.0-or-later"] },
|
||||
{ name = "malachite", version = "0.4.22", allow = ["LGPL-3.0-only"] },
|
||||
{ name = "malachite-base", version = "0.4.22", allow = ["LGPL-3.0-only"] },
|
||||
{ name = "malachite-float", version = "0.4.22", allow = ["LGPL-3.0-only"] },
|
||||
{ name = "malachite-nz", version = "0.4.22", allow = ["LGPL-3.0-only"] },
|
||||
{ name = "malachite-q", version = "0.4.22", allow = ["LGPL-3.0-only"] },
|
||||
{ name = "managed", version = "0.8.0", allow = ["0BSD"] },
|
||||
]
|
||||
private = { ignore = false }
|
||||
unused-allowed-license = "deny"
|
||||
|
||||
|
||||
911
Cargo.lock
generated
911
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -67,8 +67,8 @@ tokio = { version = "1.28.2", features = [
|
||||
"fs",
|
||||
] }
|
||||
tokio-util = "0.7.18"
|
||||
risc0-zkvm = { version = "3.0.3", features = ['std'] }
|
||||
risc0-build = "3.0.3"
|
||||
risc0-zkvm = { version = "3.0.5", features = ['std'] }
|
||||
risc0-build = "3.0.5"
|
||||
anyhow = "1.0.98"
|
||||
num_cpus = "1.13.1"
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -254,7 +254,7 @@ impl indexer_service_rpc::RpcServer for MockIndexerService {
|
||||
.collect();
|
||||
|
||||
// Sort by block ID descending (most recent first)
|
||||
account_txs.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
account_txs.sort_by_key(|b| std::cmp::Reverse(b.1));
|
||||
|
||||
let start = offset as usize;
|
||||
if start >= account_txs.len() {
|
||||
|
||||
@ -2,6 +2,7 @@ use std::{
|
||||
collections::HashSet,
|
||||
ffi::{CStr, CString, c_char},
|
||||
io::Write,
|
||||
path::Path,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
@ -24,6 +25,11 @@ unsafe extern "C" {
|
||||
password: *const c_char,
|
||||
) -> *mut WalletHandle;
|
||||
|
||||
fn wallet_ffi_open(
|
||||
config_path: *const c_char,
|
||||
storage_path: *const c_char,
|
||||
) -> *mut WalletHandle;
|
||||
|
||||
fn wallet_ffi_destroy(handle: *mut WalletHandle);
|
||||
|
||||
fn wallet_ffi_create_account_public(
|
||||
@ -56,6 +62,12 @@ unsafe extern "C" {
|
||||
out_account: *mut FfiAccount,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_get_account_private(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: *const FfiBytes32,
|
||||
out_account: *mut FfiAccount,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_free_account_data(account: *mut FfiAccount);
|
||||
|
||||
fn wallet_ffi_get_public_account_key(
|
||||
@ -89,6 +101,30 @@ unsafe extern "C" {
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> 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_transfer_deshielded(
|
||||
handle: *mut WalletHandle,
|
||||
from: *const FfiBytes32,
|
||||
to: *const FfiBytes32,
|
||||
amount: *const [u8; 16],
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_transfer_private(
|
||||
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_register_public_account(
|
||||
@ -96,12 +132,29 @@ unsafe extern "C" {
|
||||
account_id: *const FfiBytes32,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_register_private_account(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: *const FfiBytes32,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_save(handle: *mut WalletHandle) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_sync_to_block(handle: *mut WalletHandle, block_id: u64) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_get_current_block_height(
|
||||
handle: *mut WalletHandle,
|
||||
out_block_height: *mut u64,
|
||||
) -> error::WalletFfiError;
|
||||
}
|
||||
|
||||
fn new_wallet_ffi_with_test_context_config(ctx: &BlockingTestContext) -> *mut WalletHandle {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let config_path = tempdir.path().join("wallet_config.json");
|
||||
let storage_path = tempdir.path().join("storage.json");
|
||||
fn new_wallet_ffi_with_test_context_config(
|
||||
ctx: &BlockingTestContext,
|
||||
home: &Path,
|
||||
) -> *mut WalletHandle {
|
||||
let config_path = home.join("wallet_config.json");
|
||||
let storage_path = home.join("storage.json");
|
||||
let mut config = ctx.ctx().wallet().config().to_owned();
|
||||
if let Some(config_overrides) = ctx.ctx().wallet().config_overrides().clone() {
|
||||
config.apply_overrides(config_overrides);
|
||||
@ -161,6 +214,15 @@ fn new_wallet_rust_with_default_config(password: &str) -> WalletCore {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn load_existing_ffi_wallet(home: &Path) -> *mut WalletHandle {
|
||||
let config_path = home.join("wallet_config.json");
|
||||
let storage_path = home.join("storage.json");
|
||||
let config_path = CString::new(config_path.to_str().unwrap()).unwrap();
|
||||
let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap();
|
||||
|
||||
unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_create_public_accounts() {
|
||||
let password = "password_for_tests";
|
||||
@ -232,6 +294,56 @@ fn test_wallet_ffi_create_private_accounts() {
|
||||
|
||||
assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust)
|
||||
}
|
||||
#[test]
|
||||
fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let mut out_private_account_id = FfiBytes32::from_bytes([0; 32]);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
|
||||
// Create a private account with the wallet FFI and save it
|
||||
unsafe {
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
wallet_ffi_create_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&mut out_private_account_id) as *mut FfiBytes32,
|
||||
);
|
||||
|
||||
wallet_ffi_save(wallet_ffi_handle);
|
||||
wallet_ffi_destroy(wallet_ffi_handle);
|
||||
}
|
||||
|
||||
let private_account_keys = unsafe {
|
||||
let wallet_ffi_handle = load_existing_ffi_wallet(home.path());
|
||||
|
||||
let mut private_account = FfiAccount::default();
|
||||
|
||||
let result = wallet_ffi_get_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&out_private_account_id) as *const FfiBytes32,
|
||||
(&mut private_account) as *mut FfiAccount,
|
||||
);
|
||||
assert_eq!(result, error::WalletFfiError::Success);
|
||||
|
||||
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||
let result = wallet_ffi_get_private_account_keys(
|
||||
wallet_ffi_handle,
|
||||
(&out_private_account_id) as *const FfiBytes32,
|
||||
(&mut out_keys) as *mut FfiPrivateAccountKeys,
|
||||
);
|
||||
assert_eq!(result, error::WalletFfiError::Success);
|
||||
|
||||
wallet_ffi_destroy(wallet_ffi_handle);
|
||||
|
||||
out_keys
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
nssa::AccountId::from(&private_account_keys.npk()),
|
||||
out_private_account_id.into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_list_accounts() {
|
||||
@ -326,7 +438,8 @@ fn test_wallet_ffi_list_accounts() {
|
||||
fn test_wallet_ffi_get_balance_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
|
||||
let balance = unsafe {
|
||||
let mut out_balance: [u8; 16] = [0; 16];
|
||||
@ -354,7 +467,8 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> {
|
||||
fn test_wallet_ffi_get_account_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
let mut out_account = FfiAccount::default();
|
||||
|
||||
let account: Account = unsafe {
|
||||
@ -385,11 +499,48 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_account_private() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
let mut out_account = FfiAccount::default();
|
||||
|
||||
let account: Account = unsafe {
|
||||
let ffi_account_id = FfiBytes32::from(&account_id);
|
||||
let _result = wallet_ffi_get_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&ffi_account_id) as *const FfiBytes32,
|
||||
(&mut out_account) as *mut FfiAccount,
|
||||
);
|
||||
(&out_account).try_into().unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
account.program_owner,
|
||||
Program::authenticated_transfer_program().id()
|
||||
);
|
||||
assert_eq!(account.balance, 10000);
|
||||
assert!(account.data.is_empty());
|
||||
assert_eq!(account.nonce, 0);
|
||||
|
||||
unsafe {
|
||||
wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount);
|
||||
wallet_ffi_destroy(wallet_ffi_handle);
|
||||
}
|
||||
|
||||
info!("Successfully retrieved account with correct details");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
let mut out_key = FfiPublicAccountKey::default();
|
||||
|
||||
let key: PublicKey = unsafe {
|
||||
@ -426,7 +577,8 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
|
||||
fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
let mut keys = FfiPrivateAccountKeys::default();
|
||||
|
||||
unsafe {
|
||||
@ -504,7 +656,8 @@ fn test_wallet_ffi_base58_to_account_id() {
|
||||
#[test]
|
||||
fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
|
||||
// Create a new uninitialized public account
|
||||
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
||||
@ -563,10 +716,81 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_init_private_account_auth_transfer() -> 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());
|
||||
|
||||
// Create a new uninitialized public account
|
||||
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
||||
unsafe {
|
||||
wallet_ffi_create_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&mut out_account_id) as *mut FfiBytes32,
|
||||
);
|
||||
}
|
||||
|
||||
// Check its program owner is the default program id
|
||||
let account: Account = unsafe {
|
||||
let mut out_account = FfiAccount::default();
|
||||
wallet_ffi_get_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&out_account_id) as *const FfiBytes32,
|
||||
(&mut out_account) as *mut FfiAccount,
|
||||
);
|
||||
(&out_account).try_into().unwrap()
|
||||
};
|
||||
assert_eq!(account.program_owner, DEFAULT_PROGRAM_ID);
|
||||
|
||||
// Call the init funciton
|
||||
let mut transfer_result = FfiTransferResult::default();
|
||||
unsafe {
|
||||
wallet_ffi_register_private_account(
|
||||
wallet_ffi_handle,
|
||||
(&out_account_id) as *const FfiBytes32,
|
||||
(&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);
|
||||
};
|
||||
|
||||
// Check that the program owner is now the authenticated transfer program
|
||||
let account: Account = unsafe {
|
||||
let mut out_account = FfiAccount::default();
|
||||
let _result = wallet_ffi_get_account_private(
|
||||
wallet_ffi_handle,
|
||||
(&out_account_id) as *const FfiBytes32,
|
||||
(&mut out_account) as *mut FfiAccount,
|
||||
);
|
||||
(&out_account).try_into().unwrap()
|
||||
};
|
||||
assert_eq!(
|
||||
account.program_owner,
|
||||
Program::authenticated_transfer_program().id()
|
||||
);
|
||||
|
||||
unsafe {
|
||||
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
|
||||
wallet_ffi_destroy(wallet_ffi_handle);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
|
||||
let from: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[0]).into();
|
||||
let to: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[1]).into();
|
||||
let amount: [u8; 16] = 100u128.to_le_bytes();
|
||||
@ -617,3 +841,220 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
|
||||
|
||||
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 = (&ctx.ctx().existing_public_accounts()[0]).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(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_deshielded() -> 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 = (&ctx.ctx().existing_private_accounts()[0]).into();
|
||||
let to = FfiBytes32::from_bytes([37; 32]);
|
||||
let amount: [u8; 16] = 100u128.to_le_bytes();
|
||||
|
||||
let mut transfer_result = FfiTransferResult::default();
|
||||
unsafe {
|
||||
wallet_ffi_transfer_deshielded(
|
||||
wallet_ffi_handle,
|
||||
(&from) as *const FfiBytes32,
|
||||
(&to) as *const FfiBytes32,
|
||||
(&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,
|
||||
false,
|
||||
(&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,
|
||||
true,
|
||||
(&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(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_private() -> 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 = (&ctx.ctx().existing_private_accounts()[0]).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_private(
|
||||
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,
|
||||
false,
|
||||
(&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(())
|
||||
}
|
||||
|
||||
@ -33,3 +33,4 @@ test-case = "3.3.1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
prove = ["risc0-zkvm/prove"]
|
||||
|
||||
@ -118,7 +118,7 @@ pub fn add_liquidity(
|
||||
assert!(delta_lp != 0, "Payable LP must be nonzero");
|
||||
|
||||
assert!(
|
||||
delta_lp >= min_amount_liquidity.into(),
|
||||
delta_lp >= min_amount_liquidity.get(),
|
||||
"Payable LP is less than provided minimum LP amount"
|
||||
);
|
||||
|
||||
|
||||
@ -19,3 +19,7 @@ cbindgen = "0.29"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
prove = ["nssa/prove"]
|
||||
|
||||
@ -354,6 +354,61 @@ pub unsafe extern "C" fn wallet_ffi_get_account_public(
|
||||
WalletFfiError::Success
|
||||
}
|
||||
|
||||
/// 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
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_get_account_private(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: *const FfiBytes32,
|
||||
out_account: *mut FfiAccount,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if account_id.is_null() || out_account.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 account_id = AccountId::new(unsafe { (*account_id).data });
|
||||
|
||||
let Some(account) = wallet.get_account_private(account_id) else {
|
||||
return WalletFfiError::AccountNotFound;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
*out_account = account.into();
|
||||
}
|
||||
|
||||
WalletFfiError::Success
|
||||
}
|
||||
|
||||
/// Free account data returned by `wallet_ffi_get_account_public`.
|
||||
///
|
||||
/// # Safety
|
||||
|
||||
@ -11,6 +11,7 @@ use crate::{
|
||||
error::{print_error, WalletFfiError},
|
||||
types::{FfiBytes32, FfiTransferResult, WalletHandle},
|
||||
wallet::get_wallet,
|
||||
FfiPrivateAccountKeys,
|
||||
};
|
||||
|
||||
/// Send a public token transfer.
|
||||
@ -89,13 +90,270 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public(
|
||||
(*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,
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
#[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;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_transfer_deshielded(
|
||||
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_deshielded_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.
|
||||
///
|
||||
/// 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
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_transfer_private(
|
||||
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_private_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;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
@ -168,12 +426,80 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account(
|
||||
(*out_result).tx_hash = ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
match e {
|
||||
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
|
||||
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
|
||||
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
|
||||
_ => WalletFfiError::InternalError,
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_register_private_account(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: *const FfiBytes32,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if account_id.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 account_id = AccountId::new(unsafe { (*account_id).data });
|
||||
|
||||
let transfer = NativeTokenTransfer(&wallet);
|
||||
|
||||
match block_on(transfer.register_account_private(account_id)) {
|
||||
Ok(Ok((res, _secret))) => {
|
||||
let tx_hash = CString::new(res.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!("Registration failed: {:?}", e));
|
||||
unsafe {
|
||||
(*out_result).tx_hash = ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
@ -197,3 +523,13 @@ pub unsafe extern "C" fn wallet_ffi_free_transfer_result(result: *mut FfiTransfe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn map_execution_error(e: ExecutionFailureKind) -> WalletFfiError {
|
||||
match e {
|
||||
ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds,
|
||||
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
|
||||
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
|
||||
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
|
||||
_ => WalletFfiError::InternalError,
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,6 +298,8 @@ impl WalletCore {
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
// TODO: handle large Err-variant properly
|
||||
#[allow(clippy::result_large_err)]
|
||||
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@ -20,6 +20,9 @@ fn auth_transfer_preparation(
|
||||
) {
|
||||
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
|
||||
let program = Program::authenticated_transfer_program();
|
||||
|
||||
// TODO: handle large Err-variant properly
|
||||
#[allow(clippy::result_large_err)]
|
||||
let tx_pre_check = move |accounts: &[&Account]| {
|
||||
let from = accounts[0];
|
||||
if from.balance >= balance_to_move {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user