diff --git a/LEZ testnet v0.1 tutorials/custom-tokens.md b/LEZ testnet v0.1 tutorials/custom-tokens.md index ea647696..f99f29e5 100644 --- a/LEZ testnet v0.1 tutorials/custom-tokens.md +++ b/LEZ testnet v0.1 tutorials/custom-tokens.md @@ -92,7 +92,7 @@ wallet account new private # Output: Generated new account with account_id Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF With npk 6a2dfe433cf28e525aa0196d719be3c16146f7ee358ca39595323f94fde38f93 -With ipk 03d59abf4bee974cc12ddb44641c19f0b5441fef39191f047c988c29a77252a577 +With vpk 03d59abf4bee974cc12ddb44641c19f0b5441fef39191f047c988c29a77252a577 ``` 2. Create the token (Token B): diff --git a/LEZ testnet v0.1 tutorials/token-transfer.md b/LEZ testnet v0.1 tutorials/token-transfer.md index 8019ae56..156f0b1f 100644 --- a/LEZ testnet v0.1 tutorials/token-transfer.md +++ b/LEZ testnet v0.1 tutorials/token-transfer.md @@ -154,11 +154,11 @@ wallet account new private # Output: Generated new account with account_id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL With npk e6366f79d026c8bd64ae6b3d601f0506832ec682ab54897f205fffe64ec0d951 -With ipk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17 +With vpk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17 ``` > [!Tip] -> Focus on the account ID for now. The `npk` and `ipk` values are stored locally and used to build privacy-preserving transactions. The private account ID is derived from `npk`. +> Focus on the account ID for now. The `npk` and `vpk` values are stored locally and used to build privacy-preserving transactions. The private account ID is derived from `npk`. Just like public accounts, new private accounts start out uninitialized: @@ -228,17 +228,17 @@ wallet account new private # Output: Generated new account with account_id Private/AukXPRBmrYVqoqEW2HTs7N3hvTn3qdNFDcxDHVr5hMm5 With npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e -With ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 +With vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 ``` > [!Tip] -> Ignore the private account ID here and use the `npk` and `ipk` values to send to a foreign private account. +> Ignore the private account ID here and use the `npk` and `vpk` values to send to a foreign private account. ```bash wallet auth-transfer send \ --from Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \ --to-npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e \ - --to-ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \ + --to-vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \ --amount 3 ``` diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 2dd1d90d..3e6382c6 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -115,7 +115,7 @@ async fn create_and_transfer_public_token() -> Result<()> { from: format_public_account_id(&supply_account_id.to_string()), to: Some(format_public_account_id(&recipient_account_id.to_string())), to_npk: None, - to_ipk: None, + to_vpk: None, amount: transfer_amount, }; @@ -208,7 +208,7 @@ async fn create_and_transfer_public_token() -> Result<()> { definition: format_public_account_id(&definition_account_id.to_string()), holder: Some(format_public_account_id(&recipient_account_id.to_string())), holder_npk: None, - holder_ipk: None, + holder_vpk: None, amount: mint_amount, }; @@ -343,7 +343,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, - to_ipk: None, + to_vpk: None, amount: transfer_amount, }; @@ -527,7 +527,7 @@ async fn create_token_with_private_definition() -> Result<()> { &recipient_account_id_public.to_string(), )), holder_npk: None, - holder_ipk: None, + holder_vpk: None, amount: mint_amount_public, }; @@ -576,7 +576,7 @@ async fn create_token_with_private_definition() -> Result<()> { &recipient_account_id_private.to_string(), )), holder_npk: None, - holder_ipk: None, + holder_vpk: None, amount: mint_amount_private, }; @@ -705,7 +705,7 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, - to_ipk: None, + to_vpk: None, amount: transfer_amount, }; @@ -823,7 +823,7 @@ async fn shielded_token_transfer() -> Result<()> { from: format_public_account_id(&supply_account_id.to_string()), to: Some(format_private_account_id(&recipient_account_id.to_string())), to_npk: None, - to_ipk: None, + to_vpk: None, amount: transfer_amount, }; @@ -937,7 +937,7 @@ async fn deshielded_token_transfer() -> Result<()> { from: format_private_account_id(&supply_account_id.to_string()), to: Some(format_public_account_id(&recipient_account_id.to_string())), to_npk: None, - to_ipk: None, + to_vpk: None, amount: transfer_amount, }; @@ -1060,7 +1060,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { definition: format_private_account_id(&definition_account_id.to_string()), holder: None, holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)), - holder_ipk: Some(hex::encode(holder_keys.incoming_viewing_public_key.0)), + holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)), amount: mint_amount, }; diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index bb6b9805..88d4e186 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -451,7 +451,7 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> { .0; let expected_npk = &key_chain.nullifer_public_key; - let expected_ivk = &key_chain.incoming_viewing_public_key; + let expected_ivk = &key_chain.viewing_public_key; assert_eq!(&keys.npk(), expected_npk); assert_eq!(&keys.ivk().unwrap(), expected_ivk); diff --git a/wallet-ffi/src/keys.rs b/wallet-ffi/src/keys.rs index 08661a50..3876a22c 100644 --- a/wallet-ffi/src/keys.rs +++ b/wallet-ffi/src/keys.rs @@ -73,7 +73,7 @@ pub unsafe extern "C" fn wallet_ffi_get_public_account_key( /// Get keys for a private account. /// -/// Returns the nullifier public key (NPK) and incoming viewing public key (IPK) +/// Returns the nullifier public key (NPK) and viewing public key (VPK) /// for the specified private account. These keys are safe to share publicly. /// /// # Parameters @@ -130,17 +130,17 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys( // NPK is a 32-byte array let npk_bytes = key_chain.nullifer_public_key.0; - // IPK is a compressed secp256k1 point (33 bytes) - let ipk_bytes = key_chain.incoming_viewing_public_key.to_bytes(); - let ipk_len = ipk_bytes.len(); - let ipk_vec = ipk_bytes.to_vec(); - let ipk_boxed = ipk_vec.into_boxed_slice(); - let ipk_ptr = Box::into_raw(ipk_boxed) as *const u8; + // VPK is a compressed secp256k1 point (33 bytes) + let vpk_bytes = key_chain.viewing_public_key.to_bytes(); + let vpk_len = vpk_bytes.len(); + let vpk_vec = vpk_bytes.to_vec(); + let vpk_boxed = vpk_vec.into_boxed_slice(); + let vpk_ptr = Box::into_raw(vpk_boxed) as *const u8; unsafe { (*out_keys).nullifier_public_key.data = npk_bytes; - (*out_keys).incoming_viewing_public_key = ipk_ptr; - (*out_keys).incoming_viewing_public_key_len = ipk_len; + (*out_keys).viewing_public_key = vpk_ptr; + (*out_keys).viewing_public_key_len = vpk_len; } WalletFfiError::Success @@ -159,10 +159,10 @@ pub unsafe extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPriv unsafe { let keys = &*keys; - if !keys.incoming_viewing_public_key.is_null() && keys.incoming_viewing_public_key_len > 0 { + if !keys.viewing_public_key.is_null() && keys.viewing_public_key_len > 0 { let slice = std::slice::from_raw_parts_mut( - keys.incoming_viewing_public_key as *mut u8, - keys.incoming_viewing_public_key_len, + keys.viewing_public_key as *mut u8, + keys.viewing_public_key_len, ); drop(Box::from_raw(slice as *mut [u8])); } diff --git a/wallet-ffi/src/types.rs b/wallet-ffi/src/types.rs index a1d70181..4028586c 100644 --- a/wallet-ffi/src/types.rs +++ b/wallet-ffi/src/types.rs @@ -72,18 +72,18 @@ impl Default for FfiAccount { pub struct FfiPrivateAccountKeys { /// Nullifier public key (32 bytes) pub nullifier_public_key: FfiBytes32, - /// Incoming viewing public key (compressed secp256k1 point) - pub incoming_viewing_public_key: *const u8, - /// Length of incoming viewing public key (typically 33 bytes) - pub incoming_viewing_public_key_len: usize, + /// viewing public key (compressed secp256k1 point) + pub viewing_public_key: *const u8, + /// Length of viewing public key (typically 33 bytes) + pub viewing_public_key_len: usize, } impl Default for FfiPrivateAccountKeys { fn default() -> Self { Self { nullifier_public_key: FfiBytes32::default(), - incoming_viewing_public_key: std::ptr::null(), - incoming_viewing_public_key_len: 0, + viewing_public_key: std::ptr::null(), + viewing_public_key_len: 0, } } } @@ -156,12 +156,12 @@ impl FfiPrivateAccountKeys { nssa_core::NullifierPublicKey(self.nullifier_public_key.data) } - pub fn ivk(&self) -> Result { - if self.incoming_viewing_public_key_len == 33 { + pub fn ivk(&self) -> Result { + if self.viewing_public_key_len == 33 { let slice = unsafe { slice::from_raw_parts( - self.incoming_viewing_public_key, - self.incoming_viewing_public_key_len, + self.viewing_public_key, + self.viewing_public_key_len, ) }; Ok(Secp256k1Point(slice.to_vec())) diff --git a/wallet-ffi/wallet_ffi.h b/wallet-ffi/wallet_ffi.h new file mode 100644 index 00000000..0b2b0176 --- /dev/null +++ b/wallet-ffi/wallet_ffi.h @@ -0,0 +1,679 @@ +/** + * NSSA Wallet FFI Bindings + * + * Thread Safety: All functions are thread-safe. The wallet handle can be + * shared across threads, but operations are serialized internally. + * + * Memory Management: + * - Functions returning pointers allocate memory that must be freed + * - Use the corresponding wallet_ffi_free_* function to free memory + * - Never free memory returned by FFI using standard C free() + * + * Error Handling: + * - Functions return WalletFfiError codes + * - On error, call wallet_ffi_get_last_error() for detailed message + * - The error string must be freed with wallet_ffi_free_error_string() + * + * Initialization: + * 1. Call wallet_ffi_init_runtime() before any other function + * 2. Create wallet with wallet_ffi_create_new() or wallet_ffi_open() + * 3. Destroy wallet with wallet_ffi_destroy() when done + */ + + +#ifndef WALLET_FFI_H +#define WALLET_FFI_H + +/* Generated with cbindgen:0.29.2 */ + +#include +#include +#include +#include + +/** + * Error codes returned by FFI functions. + */ +typedef enum WalletFfiError { + /** + * Operation completed successfully + */ + SUCCESS = 0, + /** + * A null pointer was passed where a valid pointer was expected + */ + NULL_POINTER = 1, + /** + * Invalid UTF-8 string + */ + INVALID_UTF8 = 2, + /** + * Wallet handle is not initialized + */ + WALLET_NOT_INITIALIZED = 3, + /** + * Configuration error + */ + CONFIG_ERROR = 4, + /** + * Storage/persistence error + */ + STORAGE_ERROR = 5, + /** + * Network/RPC error + */ + NETWORK_ERROR = 6, + /** + * Account not found + */ + ACCOUNT_NOT_FOUND = 7, + /** + * Key not found for account + */ + KEY_NOT_FOUND = 8, + /** + * Insufficient funds for operation + */ + INSUFFICIENT_FUNDS = 9, + /** + * Invalid account ID format + */ + INVALID_ACCOUNT_ID = 10, + /** + * Tokio runtime error + */ + RUNTIME_ERROR = 11, + /** + * Password required but not provided + */ + PASSWORD_REQUIRED = 12, + /** + * Block synchronization error + */ + SYNC_ERROR = 13, + /** + * Serialization/deserialization error + */ + SERIALIZATION_ERROR = 14, + /** + * Invalid conversion from FFI types to NSSA types + */ + INVALID_TYPE_CONVERSION = 15, + /** + * Invalid Key value + */ + INVALID_KEY_VALUE = 16, + /** + * Internal error (catch-all) + */ + INTERNAL_ERROR = 99, +} WalletFfiError; + +/** + * Opaque pointer to the Wallet instance. + * + * This type is never instantiated directly - it's used as an opaque handle + * to hide the internal wallet structure from C code. + */ +typedef struct WalletHandle { + uint8_t _private[0]; +} WalletHandle; + +/** + * 32-byte array type for AccountId, keys, hashes, etc. + */ +typedef struct FfiBytes32 { + uint8_t data[32]; +} FfiBytes32; + +/** + * Single entry in the account list. + */ +typedef struct FfiAccountListEntry { + struct FfiBytes32 account_id; + bool is_public; +} FfiAccountListEntry; + +/** + * List of accounts returned by wallet_ffi_list_accounts. + */ +typedef struct FfiAccountList { + struct FfiAccountListEntry *entries; + uintptr_t count; +} FfiAccountList; + +/** + * Program ID - 8 u32 values (32 bytes total). + */ +typedef struct FfiProgramId { + uint32_t data[8]; +} FfiProgramId; + +/** + * U128 - 16 bytes little endian + */ +typedef struct FfiU128 { + uint8_t data[16]; +} FfiU128; + +/** + * Account data structure - C-compatible version of nssa Account. + * + * Note: `balance` and `nonce` are u128 values represented as little-endian + * byte arrays since C doesn't have native u128 support. + */ +typedef struct FfiAccount { + struct FfiProgramId program_owner; + /** + * Balance as little-endian [u8; 16] + */ + struct FfiU128 balance; + /** + * Pointer to account data bytes + */ + const uint8_t *data; + /** + * Length of account data + */ + uintptr_t data_len; + /** + * Nonce as little-endian [u8; 16] + */ + struct FfiU128 nonce; +} FfiAccount; + +/** + * Public key info for a public account. + */ +typedef struct FfiPublicAccountKey { + struct FfiBytes32 public_key; +} FfiPublicAccountKey; + +/** + * Public keys for a private account (safe to expose). + */ +typedef struct FfiPrivateAccountKeys { + /** + * Nullifier public key (32 bytes) + */ + struct FfiBytes32 nullifier_public_key; + /** + * viewing public key (compressed secp256k1 point) + */ + const uint8_t *viewing_public_key; + /** + * Length of viewing public key (typically 33 bytes) + */ + uintptr_t viewing_public_key_len; +} FfiPrivateAccountKeys; + +/** + * 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. + * + * Public accounts use standard transaction signing and are suitable for + * non-private operations. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_account_id`: Output pointer for the new account ID (32 bytes) + * + * # Returns + * - `Success` on successful creation + * - Error code on failure + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_account_id` must be a valid pointer to a `FfiBytes32` struct + */ +enum WalletFfiError wallet_ffi_create_account_public(struct WalletHandle *handle, + struct FfiBytes32 *out_account_id); + +/** + * Create a new private account. + * + * Private accounts use privacy-preserving transactions with nullifiers + * and commitments. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_account_id`: Output pointer for the new account ID (32 bytes) + * + * # Returns + * - `Success` on successful creation + * - Error code on failure + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_account_id` must be a valid pointer to a `FfiBytes32` struct + */ +enum WalletFfiError wallet_ffi_create_account_private(struct WalletHandle *handle, + struct FfiBytes32 *out_account_id); + +/** + * List all accounts in the wallet. + * + * Returns both public and private accounts managed by this wallet. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_list`: Output pointer for the account list + * + * # Returns + * - `Success` on successful listing + * - Error code on failure + * + * # Memory + * The returned list must be freed with `wallet_ffi_free_account_list()`. + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_list` must be a valid pointer to a `FfiAccountList` struct + */ +enum WalletFfiError wallet_ffi_list_accounts(struct WalletHandle *handle, + struct FfiAccountList *out_list); + +/** + * Free an account list returned by `wallet_ffi_list_accounts`. + * + * # Safety + * The list must be either null or a valid list returned by `wallet_ffi_list_accounts`. + */ +void wallet_ffi_free_account_list(struct FfiAccountList *list); + +/** + * Get account balance. + * + * For public accounts, this fetches the balance from the network. + * For private accounts, this returns the locally cached balance. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `account_id`: The account ID (32 bytes) + * - `is_public`: Whether this is a public account + * - `out_balance`: Output for balance as little-endian [u8; 16] + * + * # Returns + * - `Success` on successful query + * - Error code on failure + * + * # 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_balance` must be a valid pointer to a `[u8; 16]` array + */ +enum WalletFfiError wallet_ffi_get_balance(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + bool is_public, + uint8_t (*out_balance)[16]); + +/** + * Get full public account data from the network. + * + * # 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 + */ +enum WalletFfiError wallet_ffi_get_account_public(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiAccount *out_account); + +/** + * Free account data returned by `wallet_ffi_get_account_public`. + * + * # Safety + * The account must be either null or a valid account returned by + * `wallet_ffi_get_account_public`. + */ +void wallet_ffi_free_account_data(struct FfiAccount *account); + +/** + * Get the public key for a public account. + * + * This returns the public key derived from the account's signing key. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `account_id`: The account ID (32 bytes) + * - `out_public_key`: Output pointer for the public key + * + * # Returns + * - `Success` on successful retrieval + * - `KeyNotFound` if the account's key is not in this wallet + * - Error code on other failures + * + * # 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_public_key` must be a valid pointer to a `FfiPublicAccountKey` struct + */ +enum WalletFfiError wallet_ffi_get_public_account_key(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiPublicAccountKey *out_public_key); + +/** + * Get keys for a private account. + * + * Returns the nullifier public key (NPK) and viewing public key (VPK) + * for the specified private account. These keys are safe to share publicly. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `account_id`: The account ID (32 bytes) + * - `out_keys`: Output pointer for the key data + * + * # Returns + * - `Success` on successful retrieval + * - `AccountNotFound` if the private account is not in this wallet + * - Error code on other failures + * + * # Memory + * The keys structure must be freed with `wallet_ffi_free_private_account_keys()`. + * + * # 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_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct + */ +enum WalletFfiError wallet_ffi_get_private_account_keys(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiPrivateAccountKeys *out_keys); + +/** + * Free private account keys returned by `wallet_ffi_get_private_account_keys`. + * + * # Safety + * The keys must be either null or valid keys returned by + * `wallet_ffi_get_private_account_keys`. + */ +void wallet_ffi_free_private_account_keys(struct FfiPrivateAccountKeys *keys); + +/** + * Convert an account ID to a Base58 string. + * + * # Parameters + * - `account_id`: The account ID (32 bytes) + * + * # Returns + * - Pointer to null-terminated Base58 string on success + * - Null pointer on error + * + * # Memory + * The returned string must be freed with `wallet_ffi_free_string()`. + * + * # Safety + * - `account_id` must be a valid pointer to a `FfiBytes32` struct + */ +char *wallet_ffi_account_id_to_base58(const struct FfiBytes32 *account_id); + +/** + * Parse a Base58 string into an account ID. + * + * # Parameters + * - `base58_str`: Null-terminated Base58 string + * - `out_account_id`: Output pointer for the account ID (32 bytes) + * + * # Returns + * - `Success` on successful parsing + * - `InvalidAccountId` if the string is not valid Base58 + * - Error code on other failures + * + * # Safety + * - `base58_str` must be a valid pointer to a null-terminated C string + * - `out_account_id` must be a valid pointer to a `FfiBytes32` struct + */ +enum WalletFfiError wallet_ffi_account_id_from_base58(const char *base58_str, + struct FfiBytes32 *out_account_id); + +/** + * Synchronize private accounts to a specific block. + * + * This scans the blockchain from the last synced block to the specified block, + * updating private account balances based on any relevant transactions. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `block_id`: Target block number to sync to + * + * # Returns + * - `Success` if synchronization completed + * - `SyncError` if synchronization failed + * - Error code on other failures + * + * # Note + * This operation can take a while for large block ranges. The wallet + * internally uses a progress bar which may output to stdout. + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + */ +enum WalletFfiError wallet_ffi_sync_to_block(struct WalletHandle *handle, uint64_t block_id); + +/** + * Get the last synced block number. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_block_id`: Output pointer for the block number + * + * # Returns + * - `Success` on success + * - Error code on failure + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_block_id` must be a valid pointer to a `u64` + */ +enum WalletFfiError wallet_ffi_get_last_synced_block(struct WalletHandle *handle, + uint64_t *out_block_id); + +/** + * Get the current block height from the sequencer. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_block_height`: Output pointer for the current block height + * + * # Returns + * - `Success` on success + * - `NetworkError` if the sequencer is unreachable + * - Error code on other failures + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_block_height` must be a valid pointer to a `u64` + */ +enum WalletFfiError wallet_ffi_get_current_block_height(struct WalletHandle *handle, + uint64_t *out_block_height); + +/** + * Send a public token transfer. + * + * Transfers tokens from one public account to another on the network. + * + * # 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 + */ +enum WalletFfiError wallet_ffi_transfer_public(struct WalletHandle *handle, + const struct FfiBytes32 *from, + const struct FfiBytes32 *to, + const uint8_t (*amount)[16], + struct FfiTransferResult *out_result); + +/** + * Register a public account on the network. + * + * This initializes a public account on the blockchain. 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 + */ +enum WalletFfiError wallet_ffi_register_public_account(struct WalletHandle *handle, + const struct FfiBytes32 *account_id, + struct FfiTransferResult *out_result); + +/** + * Free a transfer result returned by `wallet_ffi_transfer_public` or + * `wallet_ffi_register_public_account`. + * + * # Safety + * The result must be either null or a valid result from a transfer function. + */ +void wallet_ffi_free_transfer_result(struct FfiTransferResult *result); + +/** + * Create a new wallet with fresh storage. + * + * This initializes a new wallet with a new seed derived from the password. + * Use this for first-time wallet creation. + * + * # Parameters + * - `config_path`: Path to the wallet configuration file (JSON) + * - `storage_path`: Path where wallet data will be stored + * - `password`: Password for encrypting the wallet seed + * + * # Returns + * - Opaque wallet handle on success + * - Null pointer on error (call `wallet_ffi_get_last_error()` for details) + * + * # Safety + * All string parameters must be valid null-terminated UTF-8 strings. + */ +struct WalletHandle *wallet_ffi_create_new(const char *config_path, + const char *storage_path, + const char *password); + +/** + * Open an existing wallet from storage. + * + * This loads a wallet that was previously created with `wallet_ffi_create_new()`. + * + * # Parameters + * - `config_path`: Path to the wallet configuration file (JSON) + * - `storage_path`: Path where wallet data is stored + * + * # Returns + * - Opaque wallet handle on success + * - Null pointer on error (call `wallet_ffi_get_last_error()` for details) + * + * # Safety + * All string parameters must be valid null-terminated UTF-8 strings. + */ +struct WalletHandle *wallet_ffi_open(const char *config_path, const char *storage_path); + +/** + * Destroy a wallet handle and free its resources. + * + * After calling this function, the handle is invalid and must not be used. + * + * # Safety + * - The handle must be either null or a valid handle from `wallet_ffi_create_new()` or + * `wallet_ffi_open()`. + * - The handle must not be used after this call. + */ +void wallet_ffi_destroy(struct WalletHandle *handle); + +/** + * Save wallet state to persistent storage. + * + * This should be called periodically or after important operations to ensure + * wallet data is persisted to disk. + * + * # Parameters + * - `handle`: Valid wallet handle + * + * # Returns + * - `Success` on successful save + * - Error code on failure + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + */ +enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle); + +/** + * Get the sequencer address from the wallet configuration. + * + * # Parameters + * - `handle`: Valid wallet handle + * + * # Returns + * - Pointer to null-terminated string on success (caller must free with + * `wallet_ffi_free_string()`) + * - Null pointer on error + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + */ +char *wallet_ffi_get_sequencer_addr(struct WalletHandle *handle); + +/** + * Free a string returned by wallet FFI functions. + * + * # Safety + * The pointer must be either null or a valid string returned by an FFI function. + */ +void wallet_ffi_free_string(char *ptr); + +#endif /* WALLET_FFI_H */ diff --git a/wallet/src/program_facades/token.rs b/wallet/src/program_facades/token.rs index 7d0ab020..9880931f 100644 --- a/wallet/src/program_facades/token.rs +++ b/wallet/src/program_facades/token.rs @@ -1,6 +1,6 @@ use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse}; use nssa::{AccountId, program::Program}; -use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey}; +use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use token_core::Instruction; use crate::{PrivacyPreservingAccount, WalletCore};