436 lines
11 KiB
Rust
436 lines
11 KiB
Rust
//! L5应用层适配器
|
||
//!
|
||
//! 提供NAC公链L5层的核心功能:
|
||
//! - 钱包接口:创建、导入、发送交易、查询余额
|
||
//! - DApp接口:合约调用、事件订阅、批量调用
|
||
//! - 浏览器接口:交易查询、链上统计、地址搜索
|
||
//! - 交易所接口:代币上架、交易对创建、订单管理
|
||
//!
|
||
//! # 示例
|
||
//!
|
||
//! ```rust
|
||
//! use nac_sdk::adapters::{L5ApplicationAdapter, config::L5Config};
|
||
//!
|
||
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
|
||
//! // 创建L5适配器
|
||
//! let config = L5Config {
|
||
//! wallet_url: "http://localhost:8552".to_string(),
|
||
//! dapp_url: "http://localhost:8553".to_string(),
|
||
//! explorer_url: "http://localhost:8554".to_string(),
|
||
//! exchange_url: "http://localhost:8555".to_string(),
|
||
//! };
|
||
//! let l5 = L5ApplicationAdapter::new(&config).await?;
|
||
//!
|
||
//! // 查询余额
|
||
//! let balance = l5.get_balance(&address).await?;
|
||
//! println!("Balance: {}", balance.total);
|
||
//!
|
||
//! # Ok(())
|
||
//! # }
|
||
//! ```
|
||
|
||
use crate::error::{NACError, Result};
|
||
use super::config::L5Config;
|
||
use nac_udm::primitives::{Address, Hash, Decimal};
|
||
use nac_udm::types::{
|
||
Wallet, BalanceInfo, TransactionInfo, TransactionReceipt,
|
||
ChainStatistics, AddressInfo, TokenMetadata, TradingPair,
|
||
OrderBook, Value, ContractCall,
|
||
};
|
||
use nac_nrpc4::client::NRPC4Client;
|
||
use std::time::Duration;
|
||
|
||
/// 列表ID类型
|
||
pub type ListingId = u64;
|
||
|
||
/// 事件流(简化实现)
|
||
pub struct EventStream {
|
||
// 实际实现应该是一个异步流
|
||
}
|
||
|
||
/// L5应用层适配器
|
||
///
|
||
/// 统一封装钱包、DApp、浏览器、交易所四个子系统
|
||
#[derive(Debug, Clone)]
|
||
pub struct L5ApplicationAdapter {
|
||
/// 钱包客户端
|
||
wallet_client: NRPC4Client,
|
||
/// DApp客户端
|
||
dapp_client: NRPC4Client,
|
||
/// 浏览器客户端
|
||
explorer_client: NRPC4Client,
|
||
/// 交易所客户端
|
||
exchange_client: NRPC4Client,
|
||
}
|
||
|
||
impl L5ApplicationAdapter {
|
||
/// 创建新的L5适配器
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `config` - L5层配置
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回初始化完成的L5适配器实例
|
||
pub async fn new(config: &L5Config) -> Result<Self> {
|
||
let wallet_client = NRPC4Client::new(&config.wallet_url, Duration::from_secs(30))
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to create wallet client: {}", e)))?;
|
||
|
||
let dapp_client = NRPC4Client::new(&config.dapp_url, Duration::from_secs(30))
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to create dapp client: {}", e)))?;
|
||
|
||
let explorer_client = NRPC4Client::new(&config.explorer_url, Duration::from_secs(30))
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to create explorer client: {}", e)))?;
|
||
|
||
let exchange_client = NRPC4Client::new(&config.exchange_url, Duration::from_secs(30))
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to create exchange client: {}", e)))?;
|
||
|
||
Ok(Self {
|
||
wallet_client,
|
||
dapp_client,
|
||
explorer_client,
|
||
exchange_client,
|
||
})
|
||
}
|
||
|
||
// ===== 钱包接口 =====
|
||
|
||
/// 创建钱包
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `password` - 钱包密码
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回新创建的钱包
|
||
pub async fn create_wallet(
|
||
&self,
|
||
password: &str,
|
||
) -> Result<Wallet> {
|
||
self.wallet_client
|
||
.create_wallet(password)
|
||
.await
|
||
.map_err(|e| NACError::WalletError(format!("Failed to create wallet: {}", e)))
|
||
}
|
||
|
||
/// 导入钱包
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `mnemonic` - 助记词
|
||
/// * `password` - 钱包密码
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回导入的钱包
|
||
pub async fn import_wallet(
|
||
&self,
|
||
mnemonic: &str,
|
||
password: &str,
|
||
) -> Result<Wallet> {
|
||
self.wallet_client
|
||
.import_wallet(mnemonic, password)
|
||
.await
|
||
.map_err(|e| NACError::WalletError(format!("Failed to import wallet: {}", e)))
|
||
}
|
||
|
||
/// 发送交易
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `from` - 发送者地址
|
||
/// * `to` - 接收者地址
|
||
/// * `amount` - 转账金额
|
||
/// * `asset` - 资产地址(可选,None表示原生币)
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回交易哈希
|
||
pub async fn send_transaction(
|
||
&self,
|
||
from: &Address,
|
||
to: &Address,
|
||
amount: Decimal,
|
||
asset: Option<&Address>,
|
||
) -> Result<Hash> {
|
||
self.wallet_client
|
||
.send_transaction(from, to, amount, asset)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to send transaction: {}", e)))
|
||
}
|
||
|
||
/// 查询余额
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `address` - 账户地址
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回余额信息
|
||
pub async fn get_balance(
|
||
&self,
|
||
address: &Address,
|
||
) -> Result<BalanceInfo> {
|
||
self.wallet_client
|
||
.get_balance(address)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to get balance: {}", e)))
|
||
}
|
||
|
||
/// 查询交易历史
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `address` - 账户地址
|
||
/// * `limit` - 返回数量限制
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回交易历史列表
|
||
pub async fn get_transaction_history(
|
||
&self,
|
||
address: &Address,
|
||
limit: u32,
|
||
) -> Result<Vec<TransactionInfo>> {
|
||
self.wallet_client
|
||
.get_transaction_history(address, limit)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to get transaction history: {}", e)))
|
||
}
|
||
|
||
// ===== DApp接口 =====
|
||
|
||
/// 调用合约方法
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `contract` - 合约地址
|
||
/// * `method` - 方法名
|
||
/// * `params` - 参数列表
|
||
/// * `caller` - 调用者地址
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回方法调用结果
|
||
pub async fn call_contract_method(
|
||
&self,
|
||
contract: &Address,
|
||
method: &str,
|
||
params: &[Value],
|
||
caller: &Address,
|
||
) -> Result<Value> {
|
||
self.dapp_client
|
||
.call_contract_method(contract, method, params, caller)
|
||
.await
|
||
.map_err(|e| NACError::ContractError(format!("Failed to call contract method: {}", e)))
|
||
}
|
||
|
||
/// 订阅合约事件
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `contract` - 合约地址
|
||
/// * `event_name` - 事件名称
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回事件流
|
||
pub async fn subscribe_event(
|
||
&self,
|
||
contract: &Address,
|
||
event_name: &str,
|
||
) -> Result<EventStream> {
|
||
self.dapp_client
|
||
.subscribe_event(contract, event_name)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to subscribe event: {}", e)))?;
|
||
|
||
Ok(EventStream {})
|
||
}
|
||
|
||
/// 批量调用
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `calls` - 调用列表
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回调用结果列表
|
||
pub async fn batch_call(
|
||
&self,
|
||
calls: &[ContractCall],
|
||
) -> Result<Vec<Value>> {
|
||
self.dapp_client
|
||
.batch_call(calls)
|
||
.await
|
||
.map_err(|e| NACError::ContractError(format!("Failed to batch call: {}", e)))
|
||
}
|
||
|
||
// ===== 浏览器接口 =====
|
||
|
||
/// 获取交易收据
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `tx_hash` - 交易哈希
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回交易收据
|
||
pub async fn get_transaction_receipt(
|
||
&self,
|
||
tx_hash: &Hash,
|
||
) -> Result<TransactionReceipt> {
|
||
self.explorer_client
|
||
.get_transaction_receipt(tx_hash)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to get transaction receipt: {}", e)))
|
||
}
|
||
|
||
/// 获取链上统计
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回链上统计数据
|
||
pub async fn get_chain_stats(&self) -> Result<ChainStatistics> {
|
||
self.explorer_client
|
||
.get_chain_stats()
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to get chain stats: {}", e)))
|
||
}
|
||
|
||
/// 搜索地址
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `query` - 搜索查询
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回地址信息列表
|
||
pub async fn search_address(
|
||
&self,
|
||
query: &str,
|
||
) -> Result<Vec<AddressInfo>> {
|
||
self.explorer_client
|
||
.search_address(query)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to search address: {}", e)))
|
||
}
|
||
|
||
// ===== 交易所接口 =====
|
||
|
||
/// 在交易所上架代币
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `token` - 代币地址
|
||
/// * `metadata` - 代币元数据
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回上架ID
|
||
pub async fn list_token_on_exchange(
|
||
&self,
|
||
token: &Address,
|
||
metadata: &TokenMetadata,
|
||
) -> Result<ListingId> {
|
||
self.exchange_client
|
||
.list_token(token, metadata)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to list token: {}", e)))
|
||
}
|
||
|
||
/// 创建交易对
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `base_token` - 基础代币地址
|
||
/// * `quote_token` - 报价代币地址
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回交易对信息
|
||
pub async fn create_trading_pair(
|
||
&self,
|
||
base_token: &Address,
|
||
quote_token: &Address,
|
||
) -> Result<TradingPair> {
|
||
self.exchange_client
|
||
.create_trading_pair(base_token, quote_token)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to create trading pair: {}", e)))
|
||
}
|
||
|
||
/// 获取订单簿
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `pair_id` - 交易对ID
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回订单簿
|
||
pub async fn get_order_book(
|
||
&self,
|
||
pair_id: u64,
|
||
) -> Result<OrderBook> {
|
||
self.exchange_client
|
||
.get_order_book(pair_id)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to get order book: {}", e)))
|
||
}
|
||
|
||
/// 下单
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `pair_id` - 交易对ID
|
||
/// * `is_buy` - 是否为买单
|
||
/// * `price` - 价格
|
||
/// * `amount` - 数量
|
||
/// * `trader` - 交易者地址
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 返回订单ID
|
||
pub async fn place_order(
|
||
&self,
|
||
pair_id: u64,
|
||
is_buy: bool,
|
||
price: Decimal,
|
||
amount: Decimal,
|
||
trader: &Address,
|
||
) -> Result<u64> {
|
||
self.exchange_client
|
||
.place_order(pair_id, is_buy, price, amount, trader)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to place order: {}", e)))
|
||
}
|
||
|
||
/// 取消订单
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `order_id` - 订单ID
|
||
/// * `trader` - 交易者地址
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// 成功返回Ok(())
|
||
pub async fn cancel_order(
|
||
&self,
|
||
order_id: u64,
|
||
trader: &Address,
|
||
) -> Result<()> {
|
||
self.exchange_client
|
||
.cancel_order(order_id, trader)
|
||
.await
|
||
.map_err(|e| NACError::NetworkError(format!("Failed to cancel order: {}", e)))
|
||
}
|
||
}
|