Support conatrcts call args in rhai bindings
Some checks failed
Rhai Tests / Run Rhai Tests (push) Has been cancelled

This commit is contained in:
2025-05-10 00:42:21 +03:00
parent 654f91b849
commit f669bdb84f
12 changed files with 542 additions and 38 deletions

View File

@@ -9,10 +9,10 @@ use std::sync::Mutex;
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
use ethers::types::{Address, U256};
use ethers::abi::Token;
use std::str::FromStr;
use crate::hero_vault::{keypair, symmetric, ethereum};
use crate::hero_vault::ethereum::{prepare_function_arguments, convert_token_to_rhai};
// Global Tokio runtime for blocking async operations
static RUNTIME: Lazy<Mutex<Runtime>> = Lazy::new(|| {
@@ -750,8 +750,15 @@ fn load_contract_abi_from_file(network_name: &str, address: &str, file_path: &st
}
}
// Call a read-only function on a contract
fn call_contract_read(contract_json: &str, function_name: &str) -> Dynamic {
// Use the utility functions from the ethereum module
// Call a read-only function on a contract (no arguments version)
fn call_contract_read_no_args(contract_json: &str, function_name: &str) -> Dynamic {
call_contract_read(contract_json, function_name, rhai::Array::new())
}
// Call a read-only function on a contract with arguments
fn call_contract_read(contract_json: &str, function_name: &str, args: rhai::Array) -> Dynamic {
// Deserialize the contract
let contract: ethereum::Contract = match serde_json::from_str(contract_json) {
Ok(contract) => contract,
@@ -761,6 +768,15 @@ fn call_contract_read(contract_json: &str, function_name: &str) -> Dynamic {
}
};
// Prepare the arguments
let tokens = match prepare_function_arguments(&contract.abi, function_name, &args) {
Ok(tokens) => tokens,
Err(e) => {
log::error!("Error preparing arguments: {}", e);
return Dynamic::UNIT;
}
};
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
@@ -779,32 +795,11 @@ fn call_contract_read(contract_json: &str, function_name: &str) -> Dynamic {
}
};
// For simplicity, we're not handling arguments in this implementation
let tokens: Vec<Token> = Vec::new();
// Execute the call in a blocking manner
match rt.block_on(async {
ethereum::call_read_function(&contract, &provider, function_name, tokens).await
}) {
Ok(result) => {
// Convert the result to a Rhai value
if result.is_empty() {
Dynamic::UNIT
} else {
// For simplicity, we'll just return the first value as a string
match &result[0] {
Token::String(s) => Dynamic::from(s.clone()),
Token::Uint(u) => Dynamic::from(u.to_string()),
Token::Int(i) => Dynamic::from(i.to_string()),
Token::Bool(b) => Dynamic::from(*b),
Token::Address(a) => Dynamic::from(format!("{:?}", a)),
_ => {
log::error!("Unsupported return type");
Dynamic::UNIT
}
}
}
},
Ok(result) => convert_token_to_rhai(&result),
Err(e) => {
log::error!("Failed to call contract function: {}", e);
Dynamic::UNIT
@@ -812,8 +807,13 @@ fn call_contract_read(contract_json: &str, function_name: &str) -> Dynamic {
}
}
// Call a state-changing function on a contract
fn call_contract_write(contract_json: &str, function_name: &str) -> String {
// Call a state-changing function on a contract (no arguments version)
fn call_contract_write_no_args(contract_json: &str, function_name: &str) -> String {
call_contract_write(contract_json, function_name, rhai::Array::new())
}
// Call a state-changing function on a contract with arguments
fn call_contract_write(contract_json: &str, function_name: &str, args: rhai::Array) -> String {
// Deserialize the contract
let contract: ethereum::Contract = match serde_json::from_str(contract_json) {
Ok(contract) => contract,
@@ -823,6 +823,15 @@ fn call_contract_write(contract_json: &str, function_name: &str) -> String {
}
};
// Prepare the arguments
let tokens = match prepare_function_arguments(&contract.abi, function_name, &args) {
Ok(tokens) => tokens,
Err(e) => {
log::error!("Error preparing arguments: {}", e);
return String::new();
}
};
// Get the runtime
let rt = match RUNTIME.lock() {
Ok(rt) => rt,
@@ -851,15 +860,19 @@ fn call_contract_write(contract_json: &str, function_name: &str) -> String {
}
};
// For simplicity, we're not handling arguments in this implementation
let tokens: Vec<Token> = Vec::new();
// Execute the transaction in a blocking manner
match rt.block_on(async {
ethereum::call_write_function(&contract, &wallet, &provider, function_name, tokens).await
}) {
Ok(tx_hash) => format!("{:?}", tx_hash),
Err(e) => {
// Log the error details for debugging
log::debug!("\nERROR DETAILS: Transaction failed: {}", e);
log::debug!("Contract address: {}", contract.address);
log::debug!("Function: {}", function_name);
log::debug!("Arguments: {:?}", args);
log::debug!("Wallet address: {}", wallet.address);
log::debug!("Network: {}", contract.network.name);
log::error!("Transaction failed: {}", e);
String::new()
}
@@ -917,7 +930,13 @@ pub fn register_crypto_module(engine: &mut Engine) -> Result<(), Box<EvalAltResu
// Register smart contract functions
engine.register_fn("load_contract_abi", load_contract_abi);
engine.register_fn("load_contract_abi_from_file", load_contract_abi_from_file);
// Register the read function with different arities
engine.register_fn("call_contract_read", call_contract_read_no_args);
engine.register_fn("call_contract_read", call_contract_read);
// Register the write function with different arities
engine.register_fn("call_contract_write", call_contract_write_no_args);
engine.register_fn("call_contract_write", call_contract_write);
Ok(())