feat: Improve error handling and simplify async operations
This commit is contained in:
parent
ae687f17f5
commit
27e5a6df3e
@ -73,7 +73,7 @@ pub async fn send_eth(
|
|||||||
let tx = TransactionRequest::new()
|
let tx = TransactionRequest::new()
|
||||||
.to(to)
|
.to(to)
|
||||||
.value(amount)
|
.value(amount)
|
||||||
.gas(21000);
|
.gas(gas);
|
||||||
|
|
||||||
// Send the transaction
|
// Send the transaction
|
||||||
let pending_tx = client.send_transaction(tx, None)
|
let pending_tx = client.send_transaction(tx, None)
|
||||||
@ -115,7 +115,7 @@ pub async fn send_eth_with_provider(
|
|||||||
let tx = TransactionRequest::new()
|
let tx = TransactionRequest::new()
|
||||||
.to(to)
|
.to(to)
|
||||||
.value(amount)
|
.value(amount)
|
||||||
.gas(21000);
|
.gas(gas);
|
||||||
|
|
||||||
// Send the transaction
|
// Send the transaction
|
||||||
let pending_tx = client.send_transaction(tx, None)
|
let pending_tx = client.send_transaction(tx, None)
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
use rhai::{Engine, Dynamic, EvalAltResult};
|
use rhai::{Engine, Dynamic, EvalAltResult};
|
||||||
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
@ -12,7 +10,7 @@ use ethers::types::{Address, U256};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::hero_vault::{keypair, symmetric, ethereum, kvs};
|
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;
|
use crate::hero_vault::ethereum::prepare_function_arguments;
|
||||||
|
|
||||||
// Global Tokio runtime for blocking async operations
|
// 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"))
|
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
|
// Get a platform-specific DefaultStore implementation for Rhai bindings
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn get_key_store() -> DefaultStore {
|
fn get_key_store() -> DefaultStore {
|
||||||
@ -42,16 +50,16 @@ fn get_key_store() -> DefaultStore {
|
|||||||
fn get_key_store() -> DefaultStore {
|
fn get_key_store() -> DefaultStore {
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
static STORE: Lazy<DefaultStore> = Lazy::new(|| {
|
static STORE: Lazy<DefaultStore> = Lazy::new(|| {
|
||||||
// In WASM we have to run this on the main thread the first time
|
match run_async(async {
|
||||||
// This works because the cache in IndexedDbStore handles subsequent synchronous operations
|
kvs::open_default_store("rhai-vault", None).await
|
||||||
let rt = RUNTIME.lock().unwrap();
|
.or_else(|_| kvs::create_default_store("rhai-vault", false, None).await)
|
||||||
rt.block_on(async {
|
}) {
|
||||||
match kvs::open_default_store("rhai-vault", None).await {
|
|
||||||
Ok(store) => store,
|
Ok(store) => store,
|
||||||
Err(_) => kvs::create_default_store("rhai-vault", false, None).await
|
Err(e) => {
|
||||||
.expect("Failed to create store")
|
log::error!("Failed to create key store: {}", e);
|
||||||
|
panic!("Could not initialize key store: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
STORE.clone()
|
STORE.clone()
|
||||||
@ -76,56 +84,30 @@ fn auto_save_key_space(password: &str) -> bool {
|
|||||||
|
|
||||||
// Export the current key space to a JSON string
|
// Export the current key space to a JSON string
|
||||||
fn encrypt_key_space(password: &str) -> String {
|
fn encrypt_key_space(password: &str) -> String {
|
||||||
match keypair::get_current_space() {
|
match keypair::get_current_space()
|
||||||
Ok(space) => {
|
.and_then(|space| symmetric::encrypt_key_space(&space, password))
|
||||||
match symmetric::encrypt_key_space(&space, password) {
|
.and_then(|encrypted_space| symmetric::serialize_encrypted_space(&encrypted_space))
|
||||||
Ok(encrypted_space) => {
|
{
|
||||||
match symmetric::serialize_encrypted_space(&encrypted_space) {
|
|
||||||
Ok(json) => json,
|
Ok(json) => json,
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error serializing encrypted space: {}", e);
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error encrypting key space: {}", e);
|
log::error!("Error encrypting key space: {}", e);
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error getting current space: {}", e);
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import a key space from a JSON string
|
// Import a key space from a JSON string
|
||||||
fn decrypt_key_space(encrypted: &str, password: &str) -> bool {
|
fn decrypt_key_space(encrypted: &str, password: &str) -> bool {
|
||||||
match symmetric::deserialize_encrypted_space(encrypted) {
|
match symmetric::deserialize_encrypted_space(encrypted)
|
||||||
Ok(encrypted_space) => {
|
.and_then(|encrypted_space| symmetric::decrypt_key_space(&encrypted_space, password))
|
||||||
match symmetric::decrypt_key_space(&encrypted_space, password) {
|
.and_then(|space| keypair::set_current_space(space))
|
||||||
Ok(space) => {
|
{
|
||||||
match keypair::set_current_space(space) {
|
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error setting current space: {}", e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error decrypting key space: {}", e);
|
log::error!("Error decrypting key space: {}", e);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error parsing encrypted space: {}", e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keypair management functions
|
// Keypair management functions
|
||||||
@ -176,77 +158,59 @@ fn sign(message: &str) -> String {
|
|||||||
|
|
||||||
fn verify(message: &str, signature: &str) -> bool {
|
fn verify(message: &str, signature: &str) -> bool {
|
||||||
let message_bytes = message.as_bytes();
|
let message_bytes = message.as_bytes();
|
||||||
match BASE64.decode(signature) {
|
match BASE64.decode(signature)
|
||||||
Ok(signature_bytes) => {
|
.map_err(|e| e.to_string())
|
||||||
match keypair::keypair_verify(message_bytes, &signature_bytes) {
|
.and_then(|sig_bytes| keypair::keypair_verify(message_bytes, &sig_bytes)
|
||||||
|
.map_err(|e| e.to_string()))
|
||||||
|
{
|
||||||
Ok(is_valid) => is_valid,
|
Ok(is_valid) => is_valid,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error verifying signature: {}", e);
|
log::error!("Error verifying signature: {}", e);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error decoding signature: {}", e);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symmetric encryption
|
// Symmetric encryption
|
||||||
fn generate_key() -> String {
|
fn generate_key() -> String {
|
||||||
let key = symmetric::generate_symmetric_key();
|
BASE64.encode(symmetric::generate_symmetric_key())
|
||||||
BASE64.encode(key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encrypt(key: &str, message: &str) -> String {
|
fn encrypt(key: &str, message: &str) -> String {
|
||||||
match BASE64.decode(key) {
|
match BASE64.decode(key)
|
||||||
Ok(key_bytes) => {
|
.map_err(|e| format!("Error decoding key: {}", e))
|
||||||
let message_bytes = message.as_bytes();
|
.and_then(|key_bytes| {
|
||||||
match symmetric::encrypt_symmetric(&key_bytes, message_bytes) {
|
symmetric::encrypt_symmetric(&key_bytes, message.as_bytes())
|
||||||
|
.map_err(|e| format!("Error encrypting message: {}", e))
|
||||||
|
})
|
||||||
|
{
|
||||||
Ok(ciphertext) => BASE64.encode(ciphertext),
|
Ok(ciphertext) => BASE64.encode(ciphertext),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error encrypting message: {}", e);
|
log::error!("{}", e);
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error decoding key: {}", e);
|
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(key: &str, ciphertext: &str) -> String {
|
fn decrypt(key: &str, ciphertext: &str) -> String {
|
||||||
match BASE64.decode(key) {
|
match BASE64.decode(key)
|
||||||
Ok(key_bytes) => {
|
.map_err(|e| format!("Error decoding key: {}", e))
|
||||||
match BASE64.decode(ciphertext) {
|
.and_then(|key_bytes| {
|
||||||
Ok(ciphertext_bytes) => {
|
BASE64.decode(ciphertext)
|
||||||
match symmetric::decrypt_symmetric(&key_bytes, &ciphertext_bytes) {
|
.map_err(|e| format!("Error decoding ciphertext: {}", e))
|
||||||
Ok(plaintext) => {
|
.and_then(|cipher_bytes| {
|
||||||
match String::from_utf8(plaintext) {
|
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,
|
Ok(text) => text,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error converting plaintext to string: {}", e);
|
log::error!("{}", e);
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error decrypting ciphertext: {}", e);
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error decoding ciphertext: {}", e);
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Error decoding key: {}", e);
|
|
||||||
String::new()
|
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
|
// Get the balance of an address on a specific network
|
||||||
fn get_balance(network_name: &str, address: &str) -> String {
|
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
|
// Parse the address
|
||||||
let addr = match Address::from_str(address) {
|
let addr = match Address::from_str(address) {
|
||||||
Ok(addr) => addr,
|
Ok(addr) => addr,
|
||||||
@ -393,9 +348,7 @@ fn get_balance(network_name: &str, address: &str) -> String {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Execute the balance query in a blocking manner
|
// Execute the balance query in a blocking manner
|
||||||
match rt.block_on(async {
|
match run_async(ethereum::get_balance(network_name, addr)) {
|
||||||
ethereum::get_balance(network_name, addr).await
|
|
||||||
}) {
|
|
||||||
Ok(balance) => {
|
Ok(balance) => {
|
||||||
// Format the balance with the network's token symbol
|
// Format the balance with the network's token symbol
|
||||||
match ethereum::get_network_by_name(network_name) {
|
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
|
// Send ETH from one address to another
|
||||||
fn send_eth(network_name: &str, to_address: &str, amount_str: &str) -> String {
|
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
|
// Parse the address
|
||||||
let to_addr = match Address::from_str(to_address) {
|
let to_addr = match Address::from_str(to_address) {
|
||||||
Ok(addr) => addr,
|
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
|
// Execute the transaction in a blocking manner
|
||||||
match rt.block_on(async {
|
match run_async(ethereum::send_eth(&wallet, network_name, to_addr, amount)) {
|
||||||
ethereum::send_eth(&wallet, network_name, to_addr, amount).await
|
|
||||||
}) {
|
|
||||||
Ok(tx_hash) => format!("{:?}", tx_hash),
|
Ok(tx_hash) => format!("{:?}", tx_hash),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Transaction failed: {}", 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
|
// Create a provider
|
||||||
let provider = match ethereum::create_provider(&contract.network.name) {
|
let provider = match ethereum::create_provider(&contract.network.name) {
|
||||||
Ok(p) => p,
|
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
|
// Execute the call in a blocking manner
|
||||||
match rt.block_on(async {
|
match run_async(ethereum::call_read_function(&contract, &provider, function_name, tokens)) {
|
||||||
ethereum::call_read_function(&contract, &provider, function_name, tokens).await
|
|
||||||
}) {
|
|
||||||
Ok(result) => ethereum::token_to_dynamic(&result),
|
Ok(result) => ethereum::token_to_dynamic(&result),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to call contract function: {}", 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
|
// Get the wallet
|
||||||
let wallet = match ethereum::get_current_ethereum_wallet() {
|
let wallet = match ethereum::get_current_ethereum_wallet() {
|
||||||
Ok(w) => w,
|
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
|
// Execute the transaction in a blocking manner
|
||||||
match rt.block_on(async {
|
match run_async(ethereum::call_write_function(&contract, &wallet, &provider, function_name, tokens)) {
|
||||||
ethereum::call_write_function(&contract, &wallet, &provider, function_name, tokens).await
|
|
||||||
}) {
|
|
||||||
Ok(tx_hash) => format!("{:?}", tx_hash),
|
Ok(tx_hash) => format!("{:?}", tx_hash),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Log the error details for debugging
|
// Log the error details for debugging
|
||||||
@ -657,20 +577,20 @@ fn get_agung_address() -> String {
|
|||||||
get_ethereum_address()
|
get_ethereum_address()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_wallet_for_network(network_name: &str) -> bool {
|
fn create_wallet_for_network(_network_name: &str) -> bool {
|
||||||
create_ethereum_wallet()
|
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()
|
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();
|
ethereum::clear_ethereum_wallets();
|
||||||
true
|
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)
|
create_ethereum_wallet_from_private_key(private_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user