265 lines
8.0 KiB
Rust
265 lines
8.0 KiB
Rust
use crate::cli::*;
|
||
use crate::client::nac_lens::NrpcClient;
|
||
use crate::config::Config;
|
||
use crate::error::{CliError, Result};
|
||
use crate::utils::*;
|
||
use colored::Colorize;
|
||
use dialoguer::Password;
|
||
use std::fs;
|
||
|
||
pub async fn execute(cmd: &ContractCommands, _cli: &Cli) -> Result<()> {
|
||
match cmd {
|
||
ContractCommands::Deploy { wasm_file, from, init_args } => {
|
||
deploy_contract(wasm_file, from, init_args.as_deref()).await
|
||
}
|
||
ContractCommands::Call { address, method, args, from } => {
|
||
call_contract(address, method, args.as_deref(), from).await
|
||
}
|
||
ContractCommands::Query { address, method, args } => {
|
||
query_contract(address, method, args.as_deref()).await
|
||
}
|
||
ContractCommands::Code { address } => {
|
||
show_contract_code(address).await
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 部署Charter合约
|
||
async fn deploy_contract(
|
||
wasm_file: &str,
|
||
from: &str,
|
||
init_args: Option<&str>,
|
||
) -> Result<()> {
|
||
// 验证地址格式
|
||
validate_address(from)?;
|
||
|
||
// 读取WASM文件(或字节码)
|
||
print_info(&format!("读取合约文件: {}", wasm_file));
|
||
|
||
let bytecode = fs::read_to_string(wasm_file)
|
||
.map_err(|e| CliError::Io(format!("读取合约文件失败: {}", e)))?;
|
||
|
||
let bytecode = bytecode.trim();
|
||
|
||
// 验证字节码格式
|
||
if !bytecode.starts_with("0x") {
|
||
return Err(CliError::InvalidInput("字节码必须以0x开头".to_string()));
|
||
}
|
||
|
||
println!();
|
||
println!("{}", "部署Charter合约".bold());
|
||
println!("{}", "=".repeat(80));
|
||
println!();
|
||
println!("{:12} {}", "部署者:".bold(), from.green());
|
||
println!("{:12} {} 字节", "字节码:".bold(), bytecode.len() / 2 - 1);
|
||
if let Some(args) = init_args {
|
||
println!("{:12} {}", "初始化参数:".bold(), args);
|
||
}
|
||
println!();
|
||
|
||
// 获取密码
|
||
let password = Password::new()
|
||
.with_prompt("请输入账户密码")
|
||
.interact()
|
||
.map_err(|e| CliError::Io(format!("读取密码失败: {}", e)))?;
|
||
|
||
// 验证密码
|
||
let manager = KeystoreManager::default()?;
|
||
if !manager.verify_password(from, &password)? {
|
||
return Err(CliError::Crypto("密码错误".to_string()));
|
||
}
|
||
|
||
// 加载配置
|
||
let config = Config::load()
|
||
.map_err(|_| CliError::Config("未找到配置文件,请先运行 'nac config init'".to_string()))?;
|
||
|
||
// 创建RPC客户端
|
||
let client = NrpcClient::new(config.get_current_rpc_url());
|
||
|
||
// 解析参数
|
||
let args_json: Vec<serde_json::Value> = if let Some(args_str) = init_args {
|
||
serde_json::from_str(args_str)
|
||
.map_err(|e| CliError::InvalidInput(format!("解析参数失败: {}", e)))?
|
||
} else {
|
||
Vec::new()
|
||
};
|
||
|
||
// 部署合约
|
||
print_info("部署合约到网络...");
|
||
let contract_address = client.deploy_contract(bytecode, args_json).await?;
|
||
|
||
print_success("合约部署成功!");
|
||
println!();
|
||
println!("{}", "合约地址:".bold());
|
||
println!(" {}", contract_address.green());
|
||
println!();
|
||
println!("提示: 使用 'nac contract code {}' 查询合约信息", contract_address);
|
||
println!();
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 调用合约方法(状态变更)
|
||
async fn call_contract(
|
||
address: &str,
|
||
method: &str,
|
||
args: Option<&str>,
|
||
from: &str,
|
||
) -> Result<()> {
|
||
// 验证地址格式
|
||
validate_address(address)?;
|
||
validate_address(from)?;
|
||
|
||
println!();
|
||
println!("{}", "调用合约方法".bold());
|
||
println!("{}", "=".repeat(80));
|
||
println!();
|
||
println!("{:12} {}", "合约:".bold(), address.green());
|
||
println!("{:12} {}", "方法:".bold(), method.cyan());
|
||
println!("{:12} {}", "调用者:".bold(), from.green());
|
||
if let Some(a) = args {
|
||
println!("{:12} {}", "参数:".bold(), a);
|
||
}
|
||
println!();
|
||
|
||
// 获取密码
|
||
let password = Password::new()
|
||
.with_prompt("请输入账户密码")
|
||
.interact()
|
||
.map_err(|e| CliError::Io(format!("读取密码失败: {}", e)))?;
|
||
|
||
// 验证密码
|
||
let manager = KeystoreManager::default()?;
|
||
if !manager.verify_password(from, &password)? {
|
||
return Err(CliError::Crypto("密码错误".to_string()));
|
||
}
|
||
|
||
// 加载配置
|
||
let config = Config::load()
|
||
.map_err(|_| CliError::Config("未找到配置文件,请先运行 'nac config init'".to_string()))?;
|
||
|
||
// 创建RPC客户端
|
||
let client = NrpcClient::new(config.get_current_rpc_url());
|
||
|
||
// 解析参数
|
||
let args_json: Vec<serde_json::Value> = if let Some(args_str) = args {
|
||
serde_json::from_str(args_str)
|
||
.map_err(|e| CliError::InvalidInput(format!("解析参数失败: {}", e)))?
|
||
} else {
|
||
Vec::new()
|
||
};
|
||
|
||
// 发送交易
|
||
print_info("发送合约交易到网络...");
|
||
let tx_hash = client.send_contract_tx(address, method, args_json).await?;
|
||
|
||
print_success("交易已发送!");
|
||
println!();
|
||
println!("{}", "交易哈希:".bold());
|
||
println!(" {}", tx_hash.cyan());
|
||
println!();
|
||
println!("提示: 使用 'nac tx show {}' 查询交易状态", tx_hash);
|
||
println!();
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 查询合约状态(只读)
|
||
async fn query_contract(
|
||
address: &str,
|
||
method: &str,
|
||
args: Option<&str>,
|
||
) -> Result<()> {
|
||
// 验证地址格式
|
||
validate_address(address)?;
|
||
|
||
// 加载配置
|
||
let config = Config::load()
|
||
.map_err(|_| CliError::Config("未找到配置文件,请先运行 'nac config init'".to_string()))?;
|
||
|
||
// 创建RPC客户端
|
||
let client = NrpcClient::new(config.get_current_rpc_url());
|
||
|
||
// 解析参数
|
||
let args_json: Vec<serde_json::Value> = if let Some(args_str) = args {
|
||
serde_json::from_str(args_str)
|
||
.map_err(|e| CliError::InvalidInput(format!("解析参数失败: {}", e)))?
|
||
} else {
|
||
Vec::new()
|
||
};
|
||
|
||
print_info(&format!("查询合约方法: {}...", method));
|
||
|
||
// 调用合约
|
||
let result = client.call_contract(address, method, args_json).await?;
|
||
|
||
println!();
|
||
println!("{}", "查询结果".bold());
|
||
println!("{}", "=".repeat(80));
|
||
println!();
|
||
println!("{}", serde_json::to_string_pretty(&result).unwrap_or_default());
|
||
println!();
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 查看合约代码
|
||
async fn show_contract_code(address: &str) -> Result<()> {
|
||
// 验证地址格式
|
||
validate_address(address)?;
|
||
|
||
// 加载配置
|
||
let config = Config::load()
|
||
.map_err(|_| CliError::Config("未找到配置文件,请先运行 'nac config init'".to_string()))?;
|
||
|
||
// 创建RPC客户端
|
||
let client = NrpcClient::new(config.get_current_rpc_url());
|
||
|
||
print_info(&format!("查询合约: {}...", address));
|
||
|
||
println!();
|
||
println!("{}", "合约信息".bold());
|
||
println!("{}", "=".repeat(80));
|
||
println!();
|
||
println!("{:12} {}", "地址:".bold(), address.green());
|
||
|
||
// 查询字节码
|
||
match client.get_contract_code(address).await {
|
||
Ok(code) => {
|
||
let code_size = if code.starts_with("0x") {
|
||
(code.len() - 2) / 2
|
||
} else {
|
||
code.len() / 2
|
||
};
|
||
println!("{:12} {} 字节", "字节码:".bold(), code_size);
|
||
|
||
if code_size > 0 {
|
||
println!("{:12} {}", "类型:".bold(), "Charter智能合约".cyan());
|
||
println!();
|
||
println!("{}", "字节码:".bold());
|
||
println!("{}", code);
|
||
} else {
|
||
println!("{:12} {}", "类型:".bold(), "普通账户".yellow());
|
||
}
|
||
}
|
||
Err(e) => {
|
||
print_warning(&format!("查询字节码失败: {}", e));
|
||
}
|
||
}
|
||
|
||
// 查询余额
|
||
match client.get_balance(address).await {
|
||
Ok(balance) => {
|
||
println!();
|
||
println!("{:12} {} NAC", "余额:".bold(), balance.cyan());
|
||
}
|
||
Err(e) => {
|
||
print_warning(&format!("查询余额失败: {}", e));
|
||
}
|
||
}
|
||
|
||
println!();
|
||
|
||
Ok(())
|
||
}
|