NAC_Blockchain/nac-cli/src/commands/contract.rs

265 lines
8.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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(())
}