Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions lez/wallet-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,192 @@ pub unsafe extern "C" fn wallet_ffi_open(
}
}

/// Resolve LEZ's canonical wallet paths (`LEE_WALLET_HOME_DIR` or `~/.lee/wallet`)
/// and ensure the home directory exists. Centralizes the path layout so callers
/// don't have to reconstruct it.
fn default_wallet_paths() -> Result<(PathBuf, PathBuf), WalletFfiError> {
let home = wallet::helperfunctions::get_home().map_err(|e| {
print_error(format!("Failed to resolve wallet home: {e}"));
WalletFfiError::InternalError
})?;

if let Err(e) = std::fs::create_dir_all(&home) {
print_error(format!(
"Failed to create wallet home {}: {e}",
home.display()
));
return Err(WalletFfiError::StorageError);
}

let config_path = wallet::helperfunctions::fetch_config_path().map_err(|e| {
print_error(format!("Failed to resolve config path: {e}"));
WalletFfiError::InternalError
})?;
let storage_path = wallet::helperfunctions::fetch_persistent_storage_path().map_err(|e| {
print_error(format!("Failed to resolve storage path: {e}"));
WalletFfiError::InternalError
})?;

Ok((config_path, storage_path))
}

/// Create a new wallet at LEZ's canonical home, deriving the paths from the
/// environment (`LEE_WALLET_HOME_DIR` or `~/.lee/wallet`) and creating the
/// directory if needed.
///
/// This is the path-free equivalent of [`wallet_ffi_create_new`]: callers that
/// just want the default location don't have to reconstruct LEZ's path layout.
///
/// # Parameters
/// - `password`: Password for encrypting the wallet seed
///
/// # Returns
/// - Result, which contains opaque wallet handle and mnemonic words on success
/// - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
///
/// # Safety
/// `password` must be a valid null-terminated UTF-8 string.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_create_new_default(
password: *const c_char,
) -> FfiCreateWalletOutput {
let Ok(password) = c_str_to_string(password, "password") else {
return FfiCreateWalletOutput::default();
};

let Ok((config_path, storage_path)) = default_wallet_paths() else {
return FfiCreateWalletOutput::default();
};

match WalletCore::new_init_storage(config_path, storage_path, None, &password) {
Ok((core, mnemonic)) => {
let wrapper = Box::new(WalletWrapper {
core: Mutex::new(core),
});
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) => {
print_error(format!("Failed to create wallet: {e}"));
FfiCreateWalletOutput::default()
}
}
}

/// Open the existing wallet at LEZ's canonical home, deriving the paths from the
/// environment (`LEE_WALLET_HOME_DIR` or `~/.lee/wallet`).
///
/// This is the path-free equivalent of [`wallet_ffi_open`].
///
/// # Returns
/// - Opaque wallet handle on success
/// - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
///
/// # Safety
/// This function takes no pointer arguments and is always safe to call.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_open_default() -> *mut WalletHandle {
match WalletCore::from_env() {
Ok(core) => {
let wrapper = Box::new(WalletWrapper {
core: Mutex::new(core),
});
Box::into_raw(wrapper).cast::<WalletHandle>()
}
Err(e) => {
print_error(format!("Failed to open wallet: {e}"));
ptr::null_mut()
}
}
}

/// Convert a resolved path into an owned C string for return across the FFI.
fn path_to_c_string(path: PathBuf) -> *mut c_char {
match CString::new(path.to_string_lossy().into_owned()) {
Ok(s) => s.into_raw(),
Err(e) => {
print_error(format!("Invalid path string: {e}"));
ptr::null_mut()
}
}
}

/// Return LEZ's canonical wallet config path (`LEE_WALLET_HOME_DIR` or
/// `~/.lee/wallet`, plus `wallet_config.json`).
///
/// Lets callers display or inspect the default location without reconstructing
/// LEZ's path layout themselves.
///
/// # Returns
/// - Pointer to null-terminated string on success (caller must free with
/// `wallet_ffi_free_string()`)
/// - Null pointer on error
///
/// # Safety
/// This function takes no pointer arguments and is always safe to call.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_default_config_path() -> *mut c_char {
match wallet::helperfunctions::fetch_config_path() {
Ok(path) => path_to_c_string(path),
Err(e) => {
print_error(format!("Failed to resolve config path: {e}"));
ptr::null_mut()
}
}
}

/// Return LEZ's canonical wallet storage path (`LEE_WALLET_HOME_DIR` or
/// `~/.lee/wallet`, plus `storage.json`).
///
/// # Returns
/// - Pointer to null-terminated string on success (caller must free with
/// `wallet_ffi_free_string()`)
/// - Null pointer on error
///
/// # Safety
/// This function takes no pointer arguments and is always safe to call.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_default_storage_path() -> *mut c_char {
match wallet::helperfunctions::fetch_persistent_storage_path() {
Ok(path) => path_to_c_string(path),
Err(e) => {
print_error(format!("Failed to resolve storage path: {e}"));
ptr::null_mut()
}
}
}

/// Whether a wallet already exists at LEZ's canonical home (i.e. its
/// `storage.json` is present). Lets callers decide between an open and a
/// create flow without touching the filesystem or knowing the path.
///
/// # Returns
/// - `true` if the default storage file exists, `false` otherwise (including
/// when the path can't be resolved)
///
/// # Safety
/// This function takes no pointer arguments and is always safe to call.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_wallet_exists_default() -> bool {
match wallet::helperfunctions::fetch_persistent_storage_path() {
Ok(path) => path.exists(),
Err(e) => {
print_error(format!("Failed to resolve storage path: {e}"));
false
}
}
}

/// Destroy a wallet handle and free its resources.
///
/// After calling this function, the handle is invalid and must not be used.
Expand Down
80 changes: 80 additions & 0 deletions lez/wallet-ffi/wallet_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,86 @@ struct FfiCreateWalletOutput wallet_ffi_create_new(const char *config_path,
*/
struct WalletHandle *wallet_ffi_open(const char *config_path, const char *storage_path);

/**
* Create a new wallet at LEZ's canonical home, deriving the paths from the
* environment (`LEE_WALLET_HOME_DIR` or `~/.lee/wallet`) and creating the
* directory if needed.
*
* This is the path-free equivalent of [`wallet_ffi_create_new`]: callers that
* just want the default location don't have to reconstruct LEZ's path layout.
*
* # Parameters
* - `password`: Password for encrypting the wallet seed
*
* # Returns
* - Result, which contains opaque wallet handle and mnemonic words on success
* - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
*
* # Safety
* `password` must be a valid null-terminated UTF-8 string.
*/
struct FfiCreateWalletOutput wallet_ffi_create_new_default(const char *password);

/**
* Open the existing wallet at LEZ's canonical home, deriving the paths from the
* environment (`LEE_WALLET_HOME_DIR` or `~/.lee/wallet`).
*
* This is the path-free equivalent of [`wallet_ffi_open`].
*
* # Returns
* - Opaque wallet handle on success
* - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
*
* # Safety
* This function takes no pointer arguments and is always safe to call.
*/
struct WalletHandle *wallet_ffi_open_default(void);

/**
* Return LEZ's canonical wallet config path (`LEE_WALLET_HOME_DIR` or
* `~/.lee/wallet`, plus `wallet_config.json`).
*
* Lets callers display or inspect the default location without reconstructing
* LEZ's path layout themselves.
*
* # Returns
* - Pointer to null-terminated string on success (caller must free with
* `wallet_ffi_free_string()`)
* - Null pointer on error
*
* # Safety
* This function takes no pointer arguments and is always safe to call.
*/
char *wallet_ffi_default_config_path(void);

/**
* Return LEZ's canonical wallet storage path (`LEE_WALLET_HOME_DIR` or
* `~/.lee/wallet`, plus `storage.json`).
*
* # Returns
* - Pointer to null-terminated string on success (caller must free with
* `wallet_ffi_free_string()`)
* - Null pointer on error
*
* # Safety
* This function takes no pointer arguments and is always safe to call.
*/
char *wallet_ffi_default_storage_path(void);

/**
* Whether a wallet already exists at LEZ's canonical home (i.e. its
* `storage.json` is present). Lets callers decide between an open and a
* create flow without touching the filesystem or knowing the path.
*
* # Returns
* - `true` if the default storage file exists, `false` otherwise (including
* when the path can't be resolved)
*
* # Safety
* This function takes no pointer arguments and is always safe to call.
*/
bool wallet_ffi_wallet_exists_default(void);

/**
* Destroy a wallet handle and free its resources.
*
Expand Down
Loading