feat: Improve error handling and simplify async operations

This commit is contained in:
Sameh Abouelsaad 2025-05-11 22:37:02 +03:00
parent ae687f17f5
commit 27e5a6df3e
2 changed files with 76 additions and 156 deletions

View File

@ -73,7 +73,7 @@ pub async fn send_eth(
let tx = TransactionRequest::new()
.to(to)
.value(amount)
.gas(21000);
.gas(gas);
// Send the transaction
let pending_tx = client.send_transaction(tx, None)
@ -115,7 +115,7 @@ pub async fn send_eth_with_provider(
let tx = TransactionRequest::new()
.to(to)
.value(amount)
.gas(21000);
.gas(gas);
// Send the transaction
let pending_tx = client.send_transaction(tx, None)

View File

@ -3,8 +3,6 @@
use rhai::{Engine, Dynamic, EvalAltResult};
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
use std::fs;
use std::path::PathBuf;
use std::collections::HashMap;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
@ -12,7 +10,7 @@ use ethers::types::{Address, U256};
use std::str::FromStr;
use crate::hero_vault::{keypair, symmetric, ethereum, kvs};
use crate::hero_vault::kvs::{KVStore, DefaultStore};
use crate::hero_vault::kvs::DefaultStore;
use crate::hero_vault::ethereum::prepare_function_arguments;
// Global Tokio runtime for blocking async operations
@ -20,6 +18,16 @@ static RUNTIME: Lazy<Mutex<Runtime>> = Lazy::new(|| {
Mutex::new(Runtime::new().expect("Failed to create Tokio runtime"))
});
// Helper function to run async operations and handle errors consistently
fn run_async<F, T, E>(future: F) -> Result<T, String>
where
F: std::future::Future<Output = Result<T, E>>,
E: std::fmt::Display,
{
let rt = RUNTIME.lock().map_err(|e| format!("Failed to acquire runtime lock: {}", e))?;
rt.block_on(async { future.await.map_err(|e| e.to_string()) })
}
// Get a platform-specific DefaultStore implementation for Rhai bindings
#[cfg(not(target_arch = "wasm32"))]
fn get_key_store() -> DefaultStore {
@ -42,16 +50,16 @@ fn get_key_store() -> DefaultStore {
fn get_key_store() -> DefaultStore {
use once_cell::sync::Lazy;
static STORE: Lazy<DefaultStore> = Lazy::new(|| {
// In WASM we have to run this on the main thread the first time
// This works because the cache in IndexedDbStore handles subsequent synchronous operations
let rt = RUNTIME.lock().unwrap();
rt.block_on(async {
match kvs::open_default_store("rhai-vault", None).await {
Ok(store) => store,
Err(_) => kvs::create_default_store("rhai-vault", false, None).await
.expect("Failed to create store")
match run_async(async {
kvs::open_default_store("rhai-vault", None).await
.or_else(|_| kvs::create_default_store("rhai-vault", false, None).await)
}) {
Ok(store) => store,
Err(e) => {
log::error!("Failed to create key store: {}", e);
panic!("Could not initialize key store: {}", e);
}
})
}
});
STORE.clone()
@ -76,26 +84,13 @@ fn auto_save_key_space(password: &str) -> bool {
// Export the current key space to a JSON string
fn encrypt_key_space(password: &str) -> String {
match keypair::get_current_space() {
Ok(space) => {
match symmetric::encrypt_key_space(&space, password) {
Ok(encrypted_space) => {
match symmetric::serialize_encrypted_space(&encrypted_space) {
Ok(json) => json,
Err(e) => {
log::error!("Error serializing encrypted space: {}", e);
String::new()
}
}
},
Err(e) => {
log::error!("Error encrypting key space: {}", e);
String::new()
}
}
},
match keypair::get_current_space()
.and_then(|space| symmetric::encrypt_key_space(&space, password))
.and_then(|encrypted_space| symmetric::serialize_encrypted_space(&encrypted_space))
{
Ok(json) => json,
Err(e) => {
log::error!("Error getting current space: {}", e);
log::error!("Error encrypting key space: {}", e);
String::new()
}
}
@ -103,26 +98,13 @@ fn encrypt_key_space(password: &str) -> String {
// Import a key space from a JSON string
fn decrypt_key_space(encrypted: &str, password: &str) -> bool {
match symmetric::deserialize_encrypted_space(encrypted) {
Ok(encrypted_space) => {
match symmetric::decrypt_key_space(&encrypted_space, password) {
Ok(space) => {
match keypair::set_current_space(space) {
Ok(_) => true,
Err(e) => {
log::error!("Error setting current space: {}", e);
false
}
}
},
Err(e) => {
log::error!("Error decrypting key space: {}", e);
false
}
}
},
match symmetric::deserialize_encrypted_space(encrypted)
.and_then(|encrypted_space| symmetric::decrypt_key_space(&encrypted_space, password))
.and_then(|space| keypair::set_current_space(space))
{
Ok(_) => true,
Err(e) => {
log::error!("Error parsing encrypted space: {}", e);
log::error!("Error decrypting key space: {}", e);
false
}
}
@ -176,18 +158,14 @@ fn sign(message: &str) -> String {
fn verify(message: &str, signature: &str) -> bool {
let message_bytes = message.as_bytes();
match BASE64.decode(signature) {
Ok(signature_bytes) => {
match keypair::keypair_verify(message_bytes, &signature_bytes) {
Ok(is_valid) => is_valid,
Err(e) => {
log::error!("Error verifying signature: {}", e);
false
}
}
},
match BASE64.decode(signature)
.map_err(|e| e.to_string())
.and_then(|sig_bytes| keypair::keypair_verify(message_bytes, &sig_bytes)
.map_err(|e| e.to_string()))
{
Ok(is_valid) => is_valid,
Err(e) => {
log::error!("Error decoding signature: {}", e);
log::error!("Error verifying signature: {}", e);
false
}
}
@ -195,58 +173,44 @@ fn verify(message: &str, signature: &str) -> bool {
// Symmetric encryption
fn generate_key() -> String {
let key = symmetric::generate_symmetric_key();
BASE64.encode(key)
BASE64.encode(symmetric::generate_symmetric_key())
}
fn encrypt(key: &str, message: &str) -> String {
match BASE64.decode(key) {
Ok(key_bytes) => {
let message_bytes = message.as_bytes();
match symmetric::encrypt_symmetric(&key_bytes, message_bytes) {
Ok(ciphertext) => BASE64.encode(ciphertext),
Err(e) => {
log::error!("Error encrypting message: {}", e);
String::new()
}
}
},
match BASE64.decode(key)
.map_err(|e| format!("Error decoding key: {}", e))
.and_then(|key_bytes| {
symmetric::encrypt_symmetric(&key_bytes, message.as_bytes())
.map_err(|e| format!("Error encrypting message: {}", e))
})
{
Ok(ciphertext) => BASE64.encode(ciphertext),
Err(e) => {
log::error!("Error decoding key: {}", e);
log::error!("{}", e);
String::new()
}
}
}
fn decrypt(key: &str, ciphertext: &str) -> String {
match BASE64.decode(key) {
Ok(key_bytes) => {
match BASE64.decode(ciphertext) {
Ok(ciphertext_bytes) => {
match symmetric::decrypt_symmetric(&key_bytes, &ciphertext_bytes) {
Ok(plaintext) => {
match String::from_utf8(plaintext) {
Ok(text) => text,
Err(e) => {
log::error!("Error converting plaintext to string: {}", e);
String::new()
}
}
},
Err(e) => {
log::error!("Error decrypting ciphertext: {}", e);
String::new()
}
}
},
Err(e) => {
log::error!("Error decoding ciphertext: {}", e);
String::new()
}
}
},
match BASE64.decode(key)
.map_err(|e| format!("Error decoding key: {}", e))
.and_then(|key_bytes| {
BASE64.decode(ciphertext)
.map_err(|e| format!("Error decoding ciphertext: {}", e))
.and_then(|cipher_bytes| {
symmetric::decrypt_symmetric(&key_bytes, &cipher_bytes)
.map_err(|e| format!("Error decrypting ciphertext: {}", e))
})
})
.and_then(|plaintext| {
String::from_utf8(plaintext)
.map_err(|e| format!("Error converting plaintext to string: {}", e))
})
{
Ok(text) => text,
Err(e) => {
log::error!("Error decoding key: {}", e);
log::error!("{}", e);
String::new()
}
}
@ -374,15 +338,6 @@ fn get_network_explorer_url(network_name: &str) -> String {
// Get the balance of an address on a specific network
fn get_balance(network_name: &str, address: &str) -> String {
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
Err(e) => {
log::error!("Failed to acquire runtime lock: {}", e);
return String::new();
}
};
// Parse the address
let addr = match Address::from_str(address) {
Ok(addr) => addr,
@ -393,9 +348,7 @@ fn get_balance(network_name: &str, address: &str) -> String {
};
// Execute the balance query in a blocking manner
match rt.block_on(async {
ethereum::get_balance(network_name, addr).await
}) {
match run_async(ethereum::get_balance(network_name, addr)) {
Ok(balance) => {
// Format the balance with the network's token symbol
match ethereum::get_network_by_name(network_name) {
@ -412,15 +365,6 @@ fn get_balance(network_name: &str, address: &str) -> String {
// Send ETH from one address to another
fn send_eth(network_name: &str, to_address: &str, amount_str: &str) -> String {
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
Err(e) => {
log::error!("Failed to acquire runtime lock: {}", e);
return String::new();
}
};
// Parse the address
let to_addr = match Address::from_str(to_address) {
Ok(addr) => addr,
@ -449,9 +393,7 @@ fn send_eth(network_name: &str, to_address: &str, amount_str: &str) -> String {
};
// Execute the transaction in a blocking manner
match rt.block_on(async {
ethereum::send_eth(&wallet, network_name, to_addr, amount).await
}) {
match run_async(ethereum::send_eth(&wallet, network_name, to_addr, amount)) {
Ok(tx_hash) => format!("{:?}", tx_hash),
Err(e) => {
log::error!("Transaction failed: {}", e);
@ -538,15 +480,6 @@ fn call_contract_read(contract_json: &str, function_name: &str, args: rhai::Arra
}
};
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
Err(e) => {
log::error!("Failed to acquire runtime lock: {}", e);
return Dynamic::UNIT;
}
};
// Create a provider
let provider = match ethereum::create_provider(&contract.network.name) {
Ok(p) => p,
@ -557,9 +490,7 @@ fn call_contract_read(contract_json: &str, function_name: &str, args: rhai::Arra
};
// Execute the call in a blocking manner
match rt.block_on(async {
ethereum::call_read_function(&contract, &provider, function_name, tokens).await
}) {
match run_async(ethereum::call_read_function(&contract, &provider, function_name, tokens)) {
Ok(result) => ethereum::token_to_dynamic(&result),
Err(e) => {
log::error!("Failed to call contract function: {}", e);
@ -593,15 +524,6 @@ fn call_contract_write(contract_json: &str, function_name: &str, args: rhai::Arr
}
};
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
Err(e) => {
log::error!("Failed to acquire runtime lock: {}", e);
return String::new();
}
};
// Get the wallet
let wallet = match ethereum::get_current_ethereum_wallet() {
Ok(w) => w,
@ -621,9 +543,7 @@ fn call_contract_write(contract_json: &str, function_name: &str, args: rhai::Arr
};
// Execute the transaction in a blocking manner
match rt.block_on(async {
ethereum::call_write_function(&contract, &wallet, &provider, function_name, tokens).await
}) {
match run_async(ethereum::call_write_function(&contract, &wallet, &provider, function_name, tokens)) {
Ok(tx_hash) => format!("{:?}", tx_hash),
Err(e) => {
// Log the error details for debugging
@ -657,20 +577,20 @@ fn get_agung_address() -> String {
get_ethereum_address()
}
fn create_wallet_for_network(network_name: &str) -> bool {
fn create_wallet_for_network(_network_name: &str) -> bool {
create_ethereum_wallet()
}
fn get_wallet_address_for_network(network_name: &str) -> String {
fn get_wallet_address_for_network(_network_name: &str) -> String {
get_ethereum_address()
}
fn clear_wallets_for_network(network_name: &str) -> bool {
fn clear_wallets_for_network(_network_name: &str) -> bool {
ethereum::clear_ethereum_wallets();
true
}
fn create_wallet_from_private_key_for_network(private_key: &str, network_name: &str) -> bool {
fn create_wallet_from_private_key_for_network(private_key: &str, _network_name: &str) -> bool {
create_ethereum_wallet_from_private_key(private_key)
}