mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-07-16 18:59:29 +00:00
Merge pull request #518 from logos-blockchain/Pravdyvy/ffi-mnemonic
feat(wallet-ffi)!: mnemonic-based updates
This commit is contained in:
commit
fb8cbac40e
@ -18,7 +18,6 @@ ignore = [
|
|||||||
|
|
||||||
{ id = "RUSTSEC-2024-0370", reason = "transitive dependency of `logos-blockchain-http-api-common`, can't do anything than wait for upstream fix" },
|
{ id = "RUSTSEC-2024-0370", reason = "transitive dependency of `logos-blockchain-http-api-common`, can't do anything than wait for upstream fix" },
|
||||||
{ id = "RUSTSEC-2026-0173", reason = "`proc-macro-error2` is unmaintained; pulled in transitively via `leptos_macro` and `overwatch-derive`, waiting on upstream fix" },
|
{ id = "RUSTSEC-2026-0173", reason = "`proc-macro-error2` is unmaintained; pulled in transitively via `leptos_macro` and `overwatch-derive`, waiting on upstream fix" },
|
||||||
{ id = "RUSTSEC-2026-0185", reason = "`quinn-proto` remote memory exhaustion; pulled in transitively via `logos-blockchain-libp2p`, waiting on upstream fix" },
|
|
||||||
]
|
]
|
||||||
yanked = "deny"
|
yanked = "deny"
|
||||||
unused-ignored-advisory = "deny"
|
unused-ignored-advisory = "deny"
|
||||||
|
|||||||
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2038,7 +2038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
|
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"syn 2.0.117",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7610,9 +7610,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn-proto"
|
name = "quinn-proto"
|
||||||
version = "0.11.14"
|
version = "0.11.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
|
checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
@ -10765,6 +10765,7 @@ dependencies = [
|
|||||||
name = "wallet-ffi"
|
name = "wallet-ffi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bip39",
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"common",
|
"common",
|
||||||
"key_protocol",
|
"key_protocol",
|
||||||
|
|||||||
2222
flake.lock
generated
2222
flake.lock
generated
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,7 @@ use wallet_ffi::{
|
|||||||
FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys,
|
FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys,
|
||||||
FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error,
|
FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error,
|
||||||
generic_transaction::{FfiProgramWithDependencies, FfiTransactionResult},
|
generic_transaction::{FfiProgramWithDependencies, FfiTransactionResult},
|
||||||
|
wallet::FfiCreateWalletOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
@ -40,7 +41,7 @@ unsafe extern "C" {
|
|||||||
config_path: *const c_char,
|
config_path: *const c_char,
|
||||||
storage_path: *const c_char,
|
storage_path: *const c_char,
|
||||||
password: *const c_char,
|
password: *const c_char,
|
||||||
) -> *mut WalletHandle;
|
) -> FfiCreateWalletOutput;
|
||||||
|
|
||||||
fn wallet_ffi_open(
|
fn wallet_ffi_open(
|
||||||
config_path: *const c_char,
|
config_path: *const c_char,
|
||||||
@ -214,6 +215,13 @@ unsafe extern "C" {
|
|||||||
out_block_height: *mut u64,
|
out_block_height: *mut u64,
|
||||||
) -> error::WalletFfiError;
|
) -> error::WalletFfiError;
|
||||||
|
|
||||||
|
fn wallet_ffi_restore_data(
|
||||||
|
handle: *mut WalletHandle,
|
||||||
|
mnemonic: *const c_char,
|
||||||
|
password: *const c_char,
|
||||||
|
depth: u32,
|
||||||
|
) -> error::WalletFfiError;
|
||||||
|
|
||||||
fn wallet_ffi_resolve_public_account(
|
fn wallet_ffi_resolve_public_account(
|
||||||
account_id: FfiBytes32,
|
account_id: FfiBytes32,
|
||||||
needs_sign: bool,
|
needs_sign: bool,
|
||||||
@ -254,7 +262,7 @@ unsafe extern "C" {
|
|||||||
fn new_wallet_ffi_with_test_context_config(
|
fn new_wallet_ffi_with_test_context_config(
|
||||||
ctx: &BlockingTestContext,
|
ctx: &BlockingTestContext,
|
||||||
home: &Path,
|
home: &Path,
|
||||||
) -> Result<*mut WalletHandle> {
|
) -> Result<FfiCreateWalletOutput> {
|
||||||
let config_path = home.join("wallet_config.json");
|
let config_path = home.join("wallet_config.json");
|
||||||
let storage_path = home.join("storage.json");
|
let storage_path = home.join("storage.json");
|
||||||
let mut config = ctx.ctx().wallet().config().to_owned();
|
let mut config = ctx.ctx().wallet().config().to_owned();
|
||||||
@ -275,7 +283,7 @@ fn new_wallet_ffi_with_test_context_config(
|
|||||||
let storage_path = CString::new(storage_path.to_str().unwrap())?;
|
let storage_path = CString::new(storage_path.to_str().unwrap())?;
|
||||||
let password = CString::new(ctx.ctx().wallet_password())?;
|
let password = CString::new(ctx.ctx().wallet_password())?;
|
||||||
|
|
||||||
let wallet_ffi_handle = unsafe {
|
let create_wallet_result = unsafe {
|
||||||
wallet_ffi_create_new(
|
wallet_ffi_create_new(
|
||||||
config_path.as_ptr(),
|
config_path.as_ptr(),
|
||||||
storage_path.as_ptr(),
|
storage_path.as_ptr(),
|
||||||
@ -293,8 +301,10 @@ fn new_wallet_ffi_with_test_context_config(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
let private_key_hex = CString::new(private_key_hex)?;
|
let private_key_hex = CString::new(private_key_hex)?;
|
||||||
unsafe { wallet_ffi_import_public_account(wallet_ffi_handle, private_key_hex.as_ptr()) }
|
unsafe {
|
||||||
.unwrap();
|
wallet_ffi_import_public_account(create_wallet_result.wallet, private_key_hex.as_ptr())
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (account_id, _chain_index) in source_key_chain.private_account_ids() {
|
for (account_id, _chain_index) in source_key_chain.private_account_ids() {
|
||||||
@ -317,7 +327,7 @@ fn new_wallet_ffi_with_test_context_config(
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
wallet_ffi_import_private_account(
|
wallet_ffi_import_private_account(
|
||||||
wallet_ffi_handle,
|
create_wallet_result.wallet,
|
||||||
key_chain_json.as_ptr(),
|
key_chain_json.as_ptr(),
|
||||||
chain_index_ptr,
|
chain_index_ptr,
|
||||||
&raw const identifier,
|
&raw const identifier,
|
||||||
@ -327,10 +337,10 @@ fn new_wallet_ffi_with_test_context_config(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(wallet_ffi_handle)
|
Ok(create_wallet_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandle> {
|
fn new_wallet_ffi_with_default_config(password: &str) -> Result<FfiCreateWalletOutput> {
|
||||||
let tempdir = tempdir()?;
|
let tempdir = tempdir()?;
|
||||||
let config_path = tempdir.path().join("wallet_config.json");
|
let config_path = tempdir.path().join("wallet_config.json");
|
||||||
let storage_path = tempdir.path().join("storage.json");
|
let storage_path = tempdir.path().join("storage.json");
|
||||||
@ -338,13 +348,15 @@ fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandl
|
|||||||
let storage_path_c = CString::new(storage_path.to_str().unwrap())?;
|
let storage_path_c = CString::new(storage_path.to_str().unwrap())?;
|
||||||
let password = CString::new(password)?;
|
let password = CString::new(password)?;
|
||||||
|
|
||||||
Ok(unsafe {
|
let create_wallet_result = unsafe {
|
||||||
wallet_ffi_create_new(
|
wallet_ffi_create_new(
|
||||||
config_path_c.as_ptr(),
|
config_path_c.as_ptr(),
|
||||||
storage_path_c.as_ptr(),
|
storage_path_c.as_ptr(),
|
||||||
password.as_ptr(),
|
password.as_ptr(),
|
||||||
)
|
)
|
||||||
})
|
};
|
||||||
|
|
||||||
|
Ok(create_wallet_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> {
|
fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> {
|
||||||
@ -365,7 +377,10 @@ fn wallet_ffi_create_public_accounts() -> Result<()> {
|
|||||||
let new_public_account_ids_ffi = unsafe {
|
let new_public_account_ids_ffi = unsafe {
|
||||||
let mut account_ids = Vec::new();
|
let mut account_ids = Vec::new();
|
||||||
|
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_default_config(password)?;
|
||||||
for _ in 0..n_accounts {
|
for _ in 0..n_accounts {
|
||||||
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
||||||
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id).unwrap();
|
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id).unwrap();
|
||||||
@ -401,7 +416,10 @@ fn wallet_ffi_create_private_accounts() -> Result<()> {
|
|||||||
let new_npks_ffi = unsafe {
|
let new_npks_ffi = unsafe {
|
||||||
let mut npks = Vec::new();
|
let mut npks = Vec::new();
|
||||||
|
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_default_config(password)?;
|
||||||
for _ in 0..n_accounts {
|
for _ in 0..n_accounts {
|
||||||
let mut out_keys = FfiPrivateAccountKeys::default();
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
||||||
@ -430,7 +448,10 @@ fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
|
|||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
// Create a receiving key and save
|
// Create a receiving key and save
|
||||||
let first_npk = unsafe {
|
let first_npk = unsafe {
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let mut out_keys = FfiPrivateAccountKeys::default();
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
||||||
let npk = out_keys.nullifier_public_key.data;
|
let npk = out_keys.nullifier_public_key.data;
|
||||||
@ -467,7 +488,10 @@ fn test_wallet_ffi_list_accounts() -> Result<()> {
|
|||||||
|
|
||||||
// Create the wallet FFI and track which account IDs were created as public/private
|
// Create the wallet FFI and track which account IDs were created as public/private
|
||||||
let (wallet_ffi_handle, created_public_ids) = unsafe {
|
let (wallet_ffi_handle, created_public_ids) = unsafe {
|
||||||
let handle = new_wallet_ffi_with_default_config(password)?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_default_config(password)?;
|
||||||
let mut public_ids: Vec<[u8; 32]> = Vec::new();
|
let mut public_ids: Vec<[u8; 32]> = Vec::new();
|
||||||
|
|
||||||
// Create 5 public accounts and 5 receiving keys
|
// Create 5 public accounts and 5 receiving keys
|
||||||
@ -532,7 +556,10 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> {
|
|||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
let balance = unsafe {
|
let balance = unsafe {
|
||||||
let mut out_balance: [u8; 16] = [0; 16];
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
@ -562,7 +589,10 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
|
|||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let mut out_account = FfiAccount::default();
|
let mut out_account = FfiAccount::default();
|
||||||
|
|
||||||
let account: Account = unsafe {
|
let account: Account = unsafe {
|
||||||
@ -599,7 +629,10 @@ fn test_wallet_ffi_get_account_private() -> Result<()> {
|
|||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let mut out_account = FfiAccount::default();
|
let mut out_account = FfiAccount::default();
|
||||||
|
|
||||||
let account: Account = unsafe {
|
let account: Account = unsafe {
|
||||||
@ -635,7 +668,10 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
|
|||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let mut out_key = FfiPublicAccountKey::default();
|
let mut out_key = FfiPublicAccountKey::default();
|
||||||
|
|
||||||
let key: PublicKey = unsafe {
|
let key: PublicKey = unsafe {
|
||||||
@ -674,7 +710,10 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
|
|||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let mut keys = FfiPrivateAccountKeys::default();
|
let mut keys = FfiPrivateAccountKeys::default();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -756,7 +795,10 @@ fn wallet_ffi_base58_to_account_id() -> Result<()> {
|
|||||||
fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
// Create a new uninitialized public account
|
// Create a new uninitialized public account
|
||||||
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
|
||||||
@ -819,7 +861,10 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
|
|||||||
fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
// Create a new private account
|
// Create a new private account
|
||||||
let mut out_account_id = FfiBytes32::default();
|
let mut out_account_id = FfiBytes32::default();
|
||||||
@ -876,7 +921,10 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_public() -> Result<()> {
|
fn test_wallet_ffi_transfer_public() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into();
|
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into();
|
||||||
let amount: [u8; 16] = 100_u128.to_le_bytes();
|
let amount: [u8; 16] = 100_u128.to_le_bytes();
|
||||||
@ -930,7 +978,10 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
let (to, to_keys) = unsafe {
|
let (to, to_keys) = unsafe {
|
||||||
let mut out_keys = FfiPrivateAccountKeys::default();
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
@ -1006,7 +1057,10 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
|
fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
||||||
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
let amount: [u8; 16] = 100_u128.to_le_bytes();
|
let amount: [u8; 16] = 100_u128.to_le_bytes();
|
||||||
@ -1066,7 +1120,10 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_private() -> Result<()> {
|
fn test_wallet_ffi_transfer_private() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
||||||
let (to, to_keys) = unsafe {
|
let (to, to_keys) = unsafe {
|
||||||
@ -1138,11 +1195,303 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn restore_keys_from_seed_ffi() -> Result<()> {
|
||||||
|
let ctx = BlockingTestContext::new()?;
|
||||||
|
let home = tempfile::tempdir()?;
|
||||||
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
|
let mnemonic = unsafe { CString::from_raw(mnemonic) };
|
||||||
|
|
||||||
|
// Create 2 new private accounts
|
||||||
|
let (private_account_id_1, private_account_1_keys) = unsafe {
|
||||||
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
|
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
||||||
|
let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128);
|
||||||
|
let to: FfiBytes32 = account_id.into();
|
||||||
|
(to, out_keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (private_account_id_2, private_account_2_keys) = unsafe {
|
||||||
|
let mut out_keys = FfiPrivateAccountKeys::default();
|
||||||
|
wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap();
|
||||||
|
let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128);
|
||||||
|
let to: FfiBytes32 = account_id.into();
|
||||||
|
(to, out_keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create 2 new public accounts
|
||||||
|
let mut public_account_id_1 = FfiBytes32::default();
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut public_account_id_1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut public_account_id_2 = FfiBytes32::default();
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut public_account_id_2).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Accounts created");
|
||||||
|
|
||||||
|
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, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send funds to accounts
|
||||||
|
let from_private: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
||||||
|
let from_public: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
|
|
||||||
|
let amount_1: [u8; 16] = 100_u128.to_le_bytes();
|
||||||
|
|
||||||
|
let mut transfer_result_1 = FfiTransferResult::default();
|
||||||
|
unsafe {
|
||||||
|
let to_identifier = FfiU128 {
|
||||||
|
data: 0_u128.to_le_bytes(),
|
||||||
|
};
|
||||||
|
wallet_ffi_transfer_private(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const from_private,
|
||||||
|
&raw const private_account_1_keys,
|
||||||
|
&raw const to_identifier,
|
||||||
|
&raw const amount_1,
|
||||||
|
&raw mut transfer_result_1,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
let amount_2: [u8; 16] = 101_u128.to_le_bytes();
|
||||||
|
|
||||||
|
let mut transfer_result_2 = FfiTransferResult::default();
|
||||||
|
unsafe {
|
||||||
|
let to_identifier = FfiU128 {
|
||||||
|
data: 0_u128.to_le_bytes(),
|
||||||
|
};
|
||||||
|
wallet_ffi_transfer_private(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const from_private,
|
||||||
|
&raw const private_account_2_keys,
|
||||||
|
&raw const to_identifier,
|
||||||
|
&raw const amount_2,
|
||||||
|
&raw mut transfer_result_2,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
let amount_3: [u8; 16] = 102_u128.to_le_bytes();
|
||||||
|
|
||||||
|
let mut transfer_result_3 = FfiTransferResult::default();
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_transfer_public(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const from_public,
|
||||||
|
&raw const public_account_id_1,
|
||||||
|
&raw const amount_3,
|
||||||
|
&raw mut transfer_result_3,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
let amount_4: [u8; 16] = 103_u128.to_le_bytes();
|
||||||
|
|
||||||
|
let mut transfer_result_4 = FfiTransferResult::default();
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_transfer_public(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const from_public,
|
||||||
|
&raw const public_account_id_2,
|
||||||
|
&raw const amount_4,
|
||||||
|
&raw mut transfer_result_4,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_free_transfer_result(&raw mut transfer_result_1);
|
||||||
|
wallet_ffi_free_transfer_result(&raw mut transfer_result_2);
|
||||||
|
wallet_ffi_free_transfer_result(&raw mut transfer_result_3);
|
||||||
|
wallet_ffi_free_transfer_result(&raw mut transfer_result_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Preparation complete, performing keys restoration");
|
||||||
|
|
||||||
|
let password = CString::new(ctx.ctx().wallet_password())?;
|
||||||
|
|
||||||
|
info!("Checking balance correctness before restoration");
|
||||||
|
|
||||||
|
let private_account_id_1_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const private_account_id_1,
|
||||||
|
false,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let private_account_id_2_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const private_account_id_2,
|
||||||
|
false,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let public_account_id_1_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const public_account_id_1,
|
||||||
|
true,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let public_account_id_2_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const public_account_id_2,
|
||||||
|
true,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(private_account_id_1_balance, 100);
|
||||||
|
assert_eq!(private_account_id_2_balance, 101);
|
||||||
|
assert_eq!(public_account_id_1_balance, 102);
|
||||||
|
assert_eq!(public_account_id_2_balance, 103);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
wallet_ffi_restore_data(wallet_ffi_handle, mnemonic.as_ptr(), password.as_ptr(), 5)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync private account local storage with onchain encrypted state
|
||||||
|
unsafe {
|
||||||
|
let mut current_height = 0;
|
||||||
|
wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap();
|
||||||
|
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Checking balance correctness after restoration");
|
||||||
|
|
||||||
|
let private_account_id_1_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const private_account_id_1,
|
||||||
|
false,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let private_account_id_2_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const private_account_id_2,
|
||||||
|
false,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let public_account_id_1_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const public_account_id_1,
|
||||||
|
true,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
let public_account_id_2_balance = unsafe {
|
||||||
|
let mut out_balance: [u8; 16] = [0; 16];
|
||||||
|
let _result = wallet_ffi_get_balance(
|
||||||
|
wallet_ffi_handle,
|
||||||
|
&raw const public_account_id_2,
|
||||||
|
true,
|
||||||
|
&raw mut out_balance,
|
||||||
|
);
|
||||||
|
u128::from_le_bytes(out_balance)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(private_account_id_1_balance, 100);
|
||||||
|
assert_eq!(private_account_id_2_balance, 101);
|
||||||
|
assert_eq!(public_account_id_1_balance, 102);
|
||||||
|
assert_eq!(public_account_id_2_balance, 103);
|
||||||
|
|
||||||
|
info!("Accounts restored");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
let bridge_account: FfiBytes32 = lee::system_bridge_account_id().into();
|
let bridge_account: FfiBytes32 = lee::system_bridge_account_id().into();
|
||||||
let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
|
let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
|
||||||
@ -1202,7 +1551,10 @@ fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into();
|
||||||
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into();
|
let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into();
|
||||||
let amount = 100_u128;
|
let amount = 100_u128;
|
||||||
@ -1294,7 +1646,10 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
|||||||
fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
|
fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into();
|
||||||
let to: FfiBytes32 = ctx.ctx().existing_private_accounts()[1].into();
|
let to: FfiBytes32 = ctx.ctx().existing_private_accounts()[1].into();
|
||||||
let amount = 100_u128;
|
let amount = 100_u128;
|
||||||
@ -1400,7 +1755,10 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> {
|
|||||||
fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> {
|
fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
let sender = ctx.ctx().existing_public_accounts()[0];
|
let sender = ctx.ctx().existing_public_accounts()[0];
|
||||||
let owner = ctx.ctx().existing_public_accounts()[1];
|
let owner = ctx.ctx().existing_public_accounts()[1];
|
||||||
@ -1482,7 +1840,10 @@ fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> {
|
|||||||
fn test_wallet_ffi_vault_balance_and_claim_private() -> Result<()> {
|
fn test_wallet_ffi_vault_balance_and_claim_private() -> Result<()> {
|
||||||
let ctx = BlockingTestContext::new()?;
|
let ctx = BlockingTestContext::new()?;
|
||||||
let home = tempfile::tempdir()?;
|
let home = tempfile::tempdir()?;
|
||||||
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
let FfiCreateWalletOutput {
|
||||||
|
wallet: wallet_ffi_handle,
|
||||||
|
mnemonic: _,
|
||||||
|
} = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
|
||||||
|
|
||||||
let sender = ctx.ctx().existing_public_accounts()[0];
|
let sender = ctx.ctx().existing_public_accounts()[0];
|
||||||
let owner = ctx.ctx().existing_private_accounts()[0];
|
let owner = ctx.ctx().existing_private_accounts()[0];
|
||||||
|
|||||||
@ -21,6 +21,7 @@ tokio.workspace = true
|
|||||||
key_protocol.workspace = true
|
key_protocol.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
risc0-zkvm.workspace = true
|
risc0-zkvm.workspace = true
|
||||||
|
bip39.workspace = true
|
||||||
vault_core.workspace = true
|
vault_core.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
//! Wallet lifecycle management functions.
|
//! Wallet lifecycle management functions.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{c_char, CStr},
|
ffi::{c_char, CStr, CString},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
ptr,
|
ptr,
|
||||||
|
str::FromStr as _,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use wallet::WalletCore;
|
use bip39::Mnemonic;
|
||||||
|
use wallet::{cli::execute_keys_restoration, WalletCore};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
c_str_to_string,
|
block_on, c_str_to_string,
|
||||||
error::{print_error, WalletFfiError},
|
error::{print_error, WalletFfiError},
|
||||||
types::WalletHandle,
|
types::WalletHandle,
|
||||||
};
|
};
|
||||||
@ -20,6 +22,22 @@ pub(crate) struct WalletWrapper {
|
|||||||
pub core: Mutex<WalletCore>,
|
pub core: Mutex<WalletCore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FfiCreateWalletOutput {
|
||||||
|
pub wallet: *mut WalletHandle,
|
||||||
|
/// C compatible(null terminated) string.
|
||||||
|
pub mnemonic: *mut c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FfiCreateWalletOutput {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
wallet: std::ptr::null_mut(),
|
||||||
|
mnemonic: std::ptr::null_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper to get the wallet wrapper from an opaque handle.
|
/// Helper to get the wallet wrapper from an opaque handle.
|
||||||
pub(crate) fn get_wallet(
|
pub(crate) fn get_wallet(
|
||||||
handle: *mut WalletHandle,
|
handle: *mut WalletHandle,
|
||||||
@ -71,8 +89,8 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result<PathBuf, WalletFfiErr
|
|||||||
/// - `password`: Password for encrypting the wallet seed
|
/// - `password`: Password for encrypting the wallet seed
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// - Opaque wallet handle on success
|
/// - Result, which contains opaque wallet handle and mnemonic words on success
|
||||||
/// - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
|
/// - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// All string parameters must be valid null-terminated UTF-8 strings.
|
/// All string parameters must be valid null-terminated UTF-8 strings.
|
||||||
@ -81,29 +99,40 @@ pub unsafe extern "C" fn wallet_ffi_create_new(
|
|||||||
config_path: *const c_char,
|
config_path: *const c_char,
|
||||||
storage_path: *const c_char,
|
storage_path: *const c_char,
|
||||||
password: *const c_char,
|
password: *const c_char,
|
||||||
) -> *mut WalletHandle {
|
) -> FfiCreateWalletOutput {
|
||||||
let Ok(config_path) = c_str_to_path(config_path, "config_path") else {
|
let Ok(config_path) = c_str_to_path(config_path, "config_path") else {
|
||||||
return ptr::null_mut();
|
return FfiCreateWalletOutput::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(storage_path) = c_str_to_path(storage_path, "storage_path") else {
|
let Ok(storage_path) = c_str_to_path(storage_path, "storage_path") else {
|
||||||
return ptr::null_mut();
|
return FfiCreateWalletOutput::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(password) = c_str_to_string(password, "password") else {
|
let Ok(password) = c_str_to_string(password, "password") else {
|
||||||
return ptr::null_mut();
|
return FfiCreateWalletOutput::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
match WalletCore::new_init_storage(config_path, storage_path, None, &password) {
|
match WalletCore::new_init_storage(config_path, storage_path, None, &password) {
|
||||||
Ok((core, _mnemonic)) => {
|
Ok((core, mnemonic)) => {
|
||||||
let wrapper = Box::new(WalletWrapper {
|
let wrapper = Box::new(WalletWrapper {
|
||||||
core: Mutex::new(core),
|
core: Mutex::new(core),
|
||||||
});
|
});
|
||||||
Box::into_raw(wrapper).cast::<WalletHandle>()
|
let handle = Box::into_raw(wrapper).cast::<WalletHandle>();
|
||||||
|
|
||||||
|
let Ok(c_mnemonic_string) = CString::new(mnemonic.to_string()) else {
|
||||||
|
return FfiCreateWalletOutput::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_pointer = CString::into_raw(c_mnemonic_string);
|
||||||
|
|
||||||
|
FfiCreateWalletOutput {
|
||||||
|
wallet: handle,
|
||||||
|
mnemonic: raw_pointer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
print_error(format!("Failed to create wallet: {e}"));
|
print_error(format!("Failed to create wallet: {e}"));
|
||||||
ptr::null_mut()
|
FfiCreateWalletOutput::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,6 +233,81 @@ pub unsafe extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restore wallet data from mnemonic and password.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `handle`: Valid wallet handle
|
||||||
|
/// - `mnemonic`: Valid pointer to instance of `* char`, provided by `wallet_ffi_create_new`
|
||||||
|
/// - `password`: Valid pointer to C string.
|
||||||
|
/// - `depth`: Depth of a reconstructed tree
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Success` on successful restoration
|
||||||
|
/// - Error code on failure
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||||
|
/// - `mnemonic` must be a valid pointer to instance of `* char`, provided by
|
||||||
|
/// `wallet_ffi_create_new`
|
||||||
|
/// - `password` must be a valid pointer to C string.
|
||||||
|
/// - `depth` parameter induces exponential growth in execution time, be aware of it.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wallet_ffi_restore_data(
|
||||||
|
handle: *mut WalletHandle,
|
||||||
|
mnemonic: *const c_char,
|
||||||
|
password: *const c_char,
|
||||||
|
depth: u32,
|
||||||
|
) -> WalletFfiError {
|
||||||
|
let wrapper = match get_wallet(handle) {
|
||||||
|
Ok(w) => w,
|
||||||
|
Err(e) => return e,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut wallet = match wrapper.core.lock() {
|
||||||
|
Ok(w) => w,
|
||||||
|
Err(e) => {
|
||||||
|
print_error(format!("Failed to lock wallet: {e}"));
|
||||||
|
return WalletFfiError::InternalError;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(password) = c_str_to_string(password, "password") else {
|
||||||
|
return WalletFfiError::NullPointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(mnemonic) = c_str_to_string(mnemonic, "mnemonic") else {
|
||||||
|
return WalletFfiError::NullPointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mnemonic = match Mnemonic::from_str(&mnemonic) {
|
||||||
|
Ok(mn) => mn,
|
||||||
|
Err(e) => {
|
||||||
|
print_error(format!("Failed to parse mnemonic: {e}"));
|
||||||
|
return WalletFfiError::SerializationError;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = match wallet.restore_storage(&mnemonic, &password) {
|
||||||
|
Ok(()) => WalletFfiError::Success,
|
||||||
|
Err(e) => {
|
||||||
|
print_error(format!("Failed to restore wallet data: {e}"));
|
||||||
|
WalletFfiError::StorageError
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if res == WalletFfiError::Success {
|
||||||
|
match block_on(execute_keys_restoration(&mut wallet, depth)) {
|
||||||
|
Ok(()) => WalletFfiError::Success,
|
||||||
|
Err(err) => {
|
||||||
|
print_error(format!("Failed to restore wallet data: {err}"));
|
||||||
|
WalletFfiError::StorageError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the sequencer address from the wallet configuration.
|
/// Get the sequencer address from the wallet configuration.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
|||||||
@ -299,6 +299,14 @@ typedef struct FfiPublicAccountKey {
|
|||||||
struct FfiBytes32 public_key;
|
struct FfiBytes32 public_key;
|
||||||
} FfiPublicAccountKey;
|
} FfiPublicAccountKey;
|
||||||
|
|
||||||
|
typedef struct FfiCreateWalletOutput {
|
||||||
|
struct WalletHandle *wallet;
|
||||||
|
/**
|
||||||
|
* C compatible(null terminated) string.
|
||||||
|
*/
|
||||||
|
char *mnemonic;
|
||||||
|
} FfiCreateWalletOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new public account.
|
* Create a new public account.
|
||||||
*
|
*
|
||||||
@ -1452,15 +1460,15 @@ enum WalletFfiError wallet_ffi_vault_claim_private(struct WalletHandle *handle,
|
|||||||
* - `password`: Password for encrypting the wallet seed
|
* - `password`: Password for encrypting the wallet seed
|
||||||
*
|
*
|
||||||
* # Returns
|
* # Returns
|
||||||
* - Opaque wallet handle on success
|
* - Result, which contains opaque wallet handle and mnemonic words on success
|
||||||
* - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
|
* - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
|
||||||
*
|
*
|
||||||
* # Safety
|
* # Safety
|
||||||
* All string parameters must be valid null-terminated UTF-8 strings.
|
* All string parameters must be valid null-terminated UTF-8 strings.
|
||||||
*/
|
*/
|
||||||
struct WalletHandle *wallet_ffi_create_new(const char *config_path,
|
struct FfiCreateWalletOutput wallet_ffi_create_new(const char *config_path,
|
||||||
const char *storage_path,
|
const char *storage_path,
|
||||||
const char *password);
|
const char *password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open an existing wallet from storage.
|
* Open an existing wallet from storage.
|
||||||
@ -1510,6 +1518,31 @@ void wallet_ffi_destroy(struct WalletHandle *handle);
|
|||||||
*/
|
*/
|
||||||
enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle);
|
enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore wallet data from mnemonic and password.
|
||||||
|
*
|
||||||
|
* # Parameters
|
||||||
|
* - `handle`: Valid wallet handle
|
||||||
|
* - `mnemonic`: Valid pointer to instance of `* char`, provided by `wallet_ffi_create_new`
|
||||||
|
* - `password`: Valid pointer to C string.
|
||||||
|
* - `depth`: Depth of a reconstructed tree
|
||||||
|
*
|
||||||
|
* # Returns
|
||||||
|
* - `Success` on successful restoration
|
||||||
|
* - Error code on failure
|
||||||
|
*
|
||||||
|
* # Safety
|
||||||
|
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||||
|
* - `mnemonic` must be a valid pointer to instance of `* char`, provided by
|
||||||
|
* `wallet_ffi_create_new`
|
||||||
|
* - `password` must be a valid pointer to C string.
|
||||||
|
* - `depth` parameter induces exponential growth in execution time, be aware of it.
|
||||||
|
*/
|
||||||
|
enum WalletFfiError wallet_ffi_restore_data(struct WalletHandle *handle,
|
||||||
|
const char *mnemonic,
|
||||||
|
const char *password,
|
||||||
|
uint32_t depth);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the sequencer address from the wallet configuration.
|
* Get the sequencer address from the wallet configuration.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -872,3 +872,26 @@ impl WalletCore {
|
|||||||
&self.config_overrides
|
&self.config_overrides
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{ffi::CString, str::FromStr as _};
|
||||||
|
|
||||||
|
use bip39::Mnemonic;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mnemonic_roundtrip() {
|
||||||
|
let mnemonic =
|
||||||
|
Mnemonic::from_entropy(&[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]).unwrap();
|
||||||
|
|
||||||
|
let c_mnemonic_string = CString::new(mnemonic.to_string()).unwrap();
|
||||||
|
let c_mnemonic_string_raw = c_mnemonic_string.into_raw();
|
||||||
|
// Safety: Will be safe, pointer is created from CString
|
||||||
|
let c_str = unsafe { CString::from_raw(c_mnemonic_string_raw) };
|
||||||
|
let mn_string = c_str.to_str().unwrap();
|
||||||
|
|
||||||
|
let mn_ret = Mnemonic::from_str(mn_string).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(mnemonic, mn_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -94,6 +94,7 @@ impl Storage {
|
|||||||
|
|
||||||
self.key_chain = UserKeyChain::new_with_accounts(public_tree, private_tree);
|
self.key_chain = UserKeyChain::new_with_accounts(public_tree, private_tree);
|
||||||
self.labels = BTreeMap::new();
|
self.labels = BTreeMap::new();
|
||||||
|
self.last_synced_block = 0;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user