mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-06-26 08:59:45 +00:00
Merge pull request #543 from logos-blockchain/schouhy/add-withdrawal-ffi
feat: add withdraw ffi
This commit is contained in:
commit
2c122440ce
@ -60,7 +60,7 @@ allow-git = [
|
||||
"https://github.com/logos-blockchain/logos-blockchain.git",
|
||||
"https://github.com/logos-blockchain/logos-blockchain-circuits.git",
|
||||
"https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git",
|
||||
"https://github.com/arkworks-rs/spongefish.git"
|
||||
"https://github.com/arkworks-rs/spongefish.git",
|
||||
]
|
||||
unknown-git = "deny"
|
||||
unknown-registry = "deny"
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -975,9 +975,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.14.100"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c9901a56e133a1fc86eeb1113e2591f45f4682451ca893bff494d2f88918e3f"
|
||||
checksum = "4ed83caece3afc59919481b33b472e1432d1abc4641ed9100be142ef5110b406"
|
||||
dependencies = [
|
||||
"hex-conservative",
|
||||
]
|
||||
|
||||
@ -165,6 +165,14 @@ unsafe extern "C" {
|
||||
|
||||
fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult);
|
||||
|
||||
fn wallet_ffi_bridge_withdraw(
|
||||
handle: *mut WalletHandle,
|
||||
from: *const FfiBytes32,
|
||||
amount: u64,
|
||||
bedrock_account_pk: *const FfiBytes32,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> error::WalletFfiError;
|
||||
|
||||
fn wallet_ffi_register_public_account(
|
||||
handle: *mut WalletHandle,
|
||||
account_id: *const FfiBytes32,
|
||||
@ -1110,6 +1118,66 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_bridge_withdraw() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
let home = tempfile::tempdir()?;
|
||||
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 bridge_account: FfiBytes32 = lee::system_bridge_account_id().into();
|
||||
let bedrock_account_pk = FfiBytes32::from_bytes([0x42; 32]);
|
||||
let amount = 100_u64;
|
||||
|
||||
let mut transfer_result = FfiTransferResult::default();
|
||||
unsafe {
|
||||
wallet_ffi_bridge_withdraw(
|
||||
wallet_ffi_handle,
|
||||
&raw const from,
|
||||
amount,
|
||||
&raw const bedrock_account_pk,
|
||||
&raw mut transfer_result,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
|
||||
|
||||
let from_balance = unsafe {
|
||||
let mut out_balance: [u8; 16] = [0; 16];
|
||||
wallet_ffi_get_balance(
|
||||
wallet_ffi_handle,
|
||||
&raw const from,
|
||||
true,
|
||||
&raw mut out_balance,
|
||||
)
|
||||
.unwrap();
|
||||
u128::from_le_bytes(out_balance)
|
||||
};
|
||||
|
||||
let bridge_balance = unsafe {
|
||||
let mut out_balance: [u8; 16] = [0; 16];
|
||||
wallet_ffi_get_balance(
|
||||
wallet_ffi_handle,
|
||||
&raw const bridge_account,
|
||||
true,
|
||||
&raw mut out_balance,
|
||||
)
|
||||
.unwrap();
|
||||
u128::from_le_bytes(out_balance)
|
||||
};
|
||||
|
||||
assert_eq!(from_balance, 9900);
|
||||
assert_eq!(bridge_balance, 1_000_100);
|
||||
|
||||
unsafe {
|
||||
wallet_ffi_free_transfer_result(&raw mut transfer_result);
|
||||
wallet_ffi_destroy(wallet_ffi_handle);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_ffi_transfer_generic_public() -> Result<()> {
|
||||
let ctx = BlockingTestContext::new()?;
|
||||
|
||||
91
lez/wallet-ffi/src/bridge.rs
Normal file
91
lez/wallet-ffi/src/bridge.rs
Normal file
@ -0,0 +1,91 @@
|
||||
//! Bridge program functions (deposit/withdraw between L1 Bedrock and L2).
|
||||
|
||||
use std::{ffi::CString, ptr};
|
||||
|
||||
use lee::AccountId;
|
||||
use wallet::program_facades::bridge::Bridge;
|
||||
|
||||
use crate::{
|
||||
block_on,
|
||||
error::{print_error, WalletFfiError},
|
||||
map_execution_error,
|
||||
types::{FfiBytes32, FfiTransferResult, WalletHandle},
|
||||
wallet::get_wallet,
|
||||
};
|
||||
|
||||
/// Withdraw native tokens from a public account to Bedrock (L1) through the bridge.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `handle`: Valid wallet handle
|
||||
/// - `from`: Source public account ID (must be owned by this wallet). Bridge withdrawals only
|
||||
/// support public sender accounts.
|
||||
/// - `amount`: Amount of native tokens to withdraw
|
||||
/// - `bedrock_account_pk`: Recipient's Bedrock (L1) public key, 32 bytes
|
||||
/// - `out_result`: Output pointer for the withdraw result
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` if the withdraw transaction 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
|
||||
/// - `bedrock_account_pk` 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_bridge_withdraw(
|
||||
handle: *mut WalletHandle,
|
||||
from: *const FfiBytes32,
|
||||
amount: u64,
|
||||
bedrock_account_pk: *const FfiBytes32,
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if from.is_null() || bedrock_account_pk.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 bedrock_account_pk = unsafe { (*bedrock_account_pk).data };
|
||||
|
||||
let bridge = Bridge(&wallet);
|
||||
|
||||
match block_on(bridge.send_withdraw(from_id, amount, bedrock_account_pk)) {
|
||||
Ok(tx_hash) => {
|
||||
let tx_hash = CString::new(tx_hash.to_string())
|
||||
.map_or(ptr::null_mut(), std::ffi::CString::into_raw);
|
||||
|
||||
unsafe {
|
||||
(*out_result).tx_hash = tx_hash;
|
||||
(*out_result).success = true;
|
||||
}
|
||||
WalletFfiError::Success
|
||||
}
|
||||
Err(e) => {
|
||||
print_error(format!("Bridge withdraw failed: {e:?}"));
|
||||
unsafe {
|
||||
(*out_result).tx_hash = ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,6 +42,7 @@ pub use types::*;
|
||||
use crate::error::print_error;
|
||||
|
||||
pub mod account;
|
||||
pub mod bridge;
|
||||
pub mod error;
|
||||
pub mod generic_transaction;
|
||||
pub mod keys;
|
||||
|
||||
@ -219,6 +219,20 @@ typedef struct FfiAccount {
|
||||
struct FfiU128 nonce;
|
||||
} FfiAccount;
|
||||
|
||||
/**
|
||||
* Result of a transfer operation.
|
||||
*/
|
||||
typedef struct FfiTransferResult {
|
||||
/**
|
||||
* Transaction hash (null-terminated string, or null on failure).
|
||||
*/
|
||||
char *tx_hash;
|
||||
/**
|
||||
* Whether the transfer succeeded.
|
||||
*/
|
||||
bool success;
|
||||
} FfiTransferResult;
|
||||
|
||||
typedef struct FfiInstructionWords {
|
||||
uint32_t *instruction_words;
|
||||
uintptr_t instruction_words_size;
|
||||
@ -285,20 +299,6 @@ typedef struct FfiPublicAccountKey {
|
||||
struct FfiBytes32 public_key;
|
||||
} FfiPublicAccountKey;
|
||||
|
||||
/**
|
||||
* Result of a transfer operation.
|
||||
*/
|
||||
typedef struct FfiTransferResult {
|
||||
/**
|
||||
* Transaction hash (null-terminated string, or null on failure).
|
||||
*/
|
||||
char *tx_hash;
|
||||
/**
|
||||
* Whether the transfer succeeded.
|
||||
*/
|
||||
bool success;
|
||||
} FfiTransferResult;
|
||||
|
||||
/**
|
||||
* Create a new public account.
|
||||
*
|
||||
@ -532,6 +532,38 @@ enum WalletFfiError wallet_ffi_import_private_account(struct WalletHandle *handl
|
||||
const struct FfiU128 *identifier,
|
||||
const char *account_state_json);
|
||||
|
||||
/**
|
||||
* Withdraw native tokens from a public account to Bedrock (L1) through the bridge.
|
||||
*
|
||||
* # Parameters
|
||||
* - `handle`: Valid wallet handle
|
||||
* - `from`: Source public account ID (must be owned by this wallet). Bridge withdrawals only
|
||||
* support public sender accounts.
|
||||
* - `amount`: Amount of native tokens to withdraw
|
||||
* - `bedrock_account_pk`: Recipient's Bedrock (L1) public key, 32 bytes
|
||||
* - `out_result`: Output pointer for the withdraw result
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` if the withdraw transaction 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
|
||||
* - `bedrock_account_pk` must be a valid pointer to a `FfiBytes32` struct
|
||||
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_bridge_withdraw(struct WalletHandle *handle,
|
||||
const struct FfiBytes32 *from,
|
||||
uint64_t amount,
|
||||
const struct FfiBytes32 *bedrock_account_pk,
|
||||
struct FfiTransferResult *out_result);
|
||||
|
||||
/**
|
||||
* Serialize sequence of bytes into RISC0 readable words.
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user