214 lines
6.1 KiB
Rust
214 lines
6.1 KiB
Rust
// NAC钱包CLI工具 - 简化版
|
||
// 提供基本的命令行钱包功能
|
||
|
||
use clap::{Parser, Subcommand};
|
||
use nac_wallet_core::{
|
||
key_manager::{KeyPair, SignatureAlgorithm},
|
||
address::{StructuredAddress, AccountType, WalletKYCLevel},
|
||
storage::KeyStore,
|
||
nac_lens_wrapper::NacLensWrapper,
|
||
};
|
||
use std::path::PathBuf;
|
||
|
||
#[derive(Parser)]
|
||
#[command(name = "nac-wallet")]
|
||
#[command(about = "NAC公链命令行钱包", long_about = None)]
|
||
struct Cli {
|
||
#[command(subcommand)]
|
||
command: Commands,
|
||
}
|
||
|
||
#[derive(Subcommand)]
|
||
enum Commands {
|
||
/// 创建新钱包
|
||
Create {
|
||
/// 密码
|
||
#[arg(long)]
|
||
password: String,
|
||
|
||
/// 钱包文件路径
|
||
#[arg(long, default_value = "./wallet.json")]
|
||
output: PathBuf,
|
||
},
|
||
|
||
/// 查询余额
|
||
Balance {
|
||
/// 钱包文件路径
|
||
#[arg(long, default_value = "./wallet.json")]
|
||
wallet: PathBuf,
|
||
|
||
/// RPC端点
|
||
#[arg(long, default_value = "https://rpc.newassetchain.io")]
|
||
rpc: String,
|
||
},
|
||
|
||
/// 查看钱包信息
|
||
Info {
|
||
/// 钱包文件路径
|
||
#[arg(long, default_value = "./wallet.json")]
|
||
wallet: PathBuf,
|
||
},
|
||
|
||
/// 列出所有钱包
|
||
List {
|
||
/// 钱包目录
|
||
#[arg(long, default_value = ".")]
|
||
dir: PathBuf,
|
||
},
|
||
}
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
let cli = Cli::parse();
|
||
|
||
match cli.command {
|
||
Commands::Create { password, output } => {
|
||
if let Err(e) = create_wallet(&password, &output).await {
|
||
eprintln!("❌ 创建钱包失败: {}", e);
|
||
std::process::exit(1);
|
||
}
|
||
}
|
||
|
||
Commands::Balance { wallet, rpc } => {
|
||
if let Err(e) = query_balance(&wallet, &rpc).await {
|
||
eprintln!("❌ 查询余额失败: {}", e);
|
||
std::process::exit(1);
|
||
}
|
||
}
|
||
|
||
Commands::Info { wallet } => {
|
||
if let Err(e) = show_wallet_info(&wallet).await {
|
||
eprintln!("❌ 查看钱包信息失败: {}", e);
|
||
std::process::exit(1);
|
||
}
|
||
}
|
||
|
||
Commands::List { dir } => {
|
||
if let Err(e) = list_wallets(&dir).await {
|
||
eprintln!("❌ 列出钱包失败: {}", e);
|
||
std::process::exit(1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
async fn create_wallet(
|
||
password: &str,
|
||
output: &PathBuf,
|
||
) -> Result<(), Box<dyn std::error::Error>> {
|
||
println!("🔐 正在创建NAC钱包...");
|
||
|
||
// 生成密钥对
|
||
let keypair = KeyPair::generate(SignatureAlgorithm::Ed25519)
|
||
.map_err(|e| format!("Failed to generate keypair: {}", e))?;
|
||
|
||
// 计算公钥哈希
|
||
let pubkey_hash = keypair.public_key_hash();
|
||
|
||
// 创建结构化地址
|
||
let address = StructuredAddress::new(
|
||
AccountType::Personal,
|
||
WalletKYCLevel::None,
|
||
156, // 中国
|
||
pubkey_hash,
|
||
);
|
||
|
||
println!("✅ 地址: {}", hex::encode(address.to_bytes()));
|
||
println!("📝 账户类型: Personal");
|
||
println!("🔒 KYC等级: None");
|
||
println!("🌍 区域代码: 156 (中国)");
|
||
println!("🔑 签名算法: Ed25519");
|
||
|
||
// 保存密钥库
|
||
let keystore = KeyStore::encrypt(&keypair, password)?;
|
||
keystore.save_to_file(output)?;
|
||
|
||
println!("💾 钱包已保存到: {}", output.display());
|
||
println!("\n⚠️ 请妥善保管密码,密码丢失将无法恢复钱包!");
|
||
|
||
Ok(())
|
||
}
|
||
|
||
async fn query_balance(
|
||
wallet_path: &PathBuf,
|
||
rpc_url: &str,
|
||
) -> Result<(), Box<dyn std::error::Error>> {
|
||
println!("💰 正在查询余额...");
|
||
|
||
// 读取钱包文件
|
||
let keystore = KeyStore::load_from_file(wallet_path)?;
|
||
let address_bytes = keystore.address;
|
||
|
||
// 创建NAC Lens客户端
|
||
let client = NacLensWrapper::new(rpc_url);
|
||
|
||
// 查询XTZH余额
|
||
match client.get_balance(&address_bytes, Some("xtzh")).await {
|
||
Ok(balance) => {
|
||
println!("✅ 地址: {}", hex::encode(address_bytes));
|
||
println!("💵 XTZH余额: {}", balance);
|
||
}
|
||
Err(e) => {
|
||
println!("⚠️ 无法连接到RPC节点: {}", e);
|
||
println!("💡 请确保RPC端点正确且节点正在运行");
|
||
}
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
async fn show_wallet_info(
|
||
wallet_path: &PathBuf,
|
||
) -> Result<(), Box<dyn std::error::Error>> {
|
||
println!("ℹ️ 正在查看钱包信息...");
|
||
|
||
// 读取钱包文件
|
||
let keystore = KeyStore::load_from_file(wallet_path)?;
|
||
|
||
println!("\n💼 钱包信息");
|
||
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||
println!("📁 文件路径: {}", wallet_path.display());
|
||
println!("📍 地址: {}", hex::encode(keystore.address));
|
||
println!("🔐 加密算法: AES-256-GCM");
|
||
println!("🔑 密钥派生: PBKDF2-SHA256 (100,000次迭代)");
|
||
|
||
Ok(())
|
||
}
|
||
|
||
async fn list_wallets(
|
||
dir: &PathBuf,
|
||
) -> Result<(), Box<dyn std::error::Error>> {
|
||
println!("📂 正在列出钱包...");
|
||
|
||
let mut count = 0;
|
||
|
||
// 遍历目录查找.json文件
|
||
if let Ok(entries) = std::fs::read_dir(dir) {
|
||
for entry in entries.flatten() {
|
||
if let Ok(file_type) = entry.file_type() {
|
||
if file_type.is_file() {
|
||
if let Some(ext) = entry.path().extension() {
|
||
if ext == "json" {
|
||
// 尝试读取为KeyStore
|
||
if let Ok(keystore) = KeyStore::load_from_file(&entry.path()) {
|
||
count += 1;
|
||
println!("\n💼 钱包 #{}", count);
|
||
println!(" 文件: {}", entry.path().display());
|
||
println!(" 地址: {}", hex::encode(keystore.address));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if count == 0 {
|
||
println!("❌ 未找到钱包文件");
|
||
} else {
|
||
println!("\n✅ 共找到 {} 个钱包", count);
|
||
}
|
||
|
||
Ok(())
|
||
}
|