113 lines
5.5 KiB
Rust
113 lines
5.5 KiB
Rust
//! acc_reserve - NAC 原生协议实现
|
|
//! 从 acc_remaining_protocols.rs 提取
|
|
use crate::primitives::{Address, Hash, Timestamp};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::HashMap;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub enum ACCReserveError {
|
|
ReserveNotFound(String),
|
|
InsufficientReserve { asset: String, available: u128, requested: u128 },
|
|
InvalidConstitutionalReceipt,
|
|
Unauthorized(Address),
|
|
ReserveRatioViolation { required: u8, actual: u8 },
|
|
}
|
|
impl std::fmt::Display for ACCReserveError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::ReserveNotFound(s) => write!(f, "储备资产不存在: {}", s),
|
|
Self::InsufficientReserve { asset, available, requested } => write!(f, "储备不足 {}: 可用 {},请求 {}", asset, available, requested),
|
|
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
|
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
|
Self::ReserveRatioViolation { required, actual } => write!(f, "储备率违规: 要求 {}%,实际 {}%", required, actual),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ReserveEntry {
|
|
pub asset_symbol: String,
|
|
pub amount: u128,
|
|
pub custodian: Address,
|
|
pub last_audited: Timestamp,
|
|
pub audit_hash: Hash,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub enum ReserveProtocolEvent {
|
|
ReserveDeposited { asset: String, amount: u128, custodian: Address, timestamp: Timestamp },
|
|
ReserveWithdrawn { asset: String, amount: u128, recipient: Address, constitutional_receipt: Hash, timestamp: Timestamp },
|
|
ReserveAudited { asset: String, audit_hash: Hash, timestamp: Timestamp },
|
|
}
|
|
|
|
/// ACC-Reserve 储备协议
|
|
/// UID: nac.acc.ACCReserveProtocol.v1
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ACCReserveProtocol {
|
|
pub protocol_uid: String,
|
|
pub lens_protocol_vector: String,
|
|
pub reserves: HashMap<String, ReserveEntry>,
|
|
/// 最低储备率(百分比)
|
|
pub min_reserve_ratio: u8,
|
|
pub pending_events: Vec<ReserveProtocolEvent>,
|
|
pub created_at: Timestamp,
|
|
pub updated_at: Timestamp,
|
|
}
|
|
impl ACCReserveProtocol {
|
|
pub fn new(min_reserve_ratio: u8) -> Self {
|
|
Self {
|
|
protocol_uid: "nac.acc.ACCReserveProtocol.v1".to_string(),
|
|
lens_protocol_vector: "ACC-Reserve".to_string(),
|
|
reserves: HashMap::new(),
|
|
min_reserve_ratio,
|
|
pending_events: Vec::new(),
|
|
created_at: Timestamp::now(),
|
|
updated_at: Timestamp::now(),
|
|
}
|
|
}
|
|
pub fn deposit(
|
|
&mut self, asset_symbol: String, amount: u128, custodian: Address,
|
|
constitutional_receipt: Hash, timestamp: Timestamp,
|
|
) -> Result<(), ACCReserveError> {
|
|
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
|
let entry = self.reserves.entry(asset_symbol.clone()).or_insert(ReserveEntry {
|
|
asset_symbol: asset_symbol.clone(), amount: 0,
|
|
custodian: custodian.clone(), last_audited: timestamp.clone(),
|
|
audit_hash: Hash::zero(),
|
|
});
|
|
entry.amount = entry.amount.saturating_add(amount);
|
|
entry.custodian = custodian.clone();
|
|
self.pending_events.push(ReserveProtocolEvent::ReserveDeposited { asset: asset_symbol, amount, custodian, timestamp });
|
|
self.updated_at = Timestamp::now();
|
|
Ok(())
|
|
}
|
|
pub fn withdraw(
|
|
&mut self, asset_symbol: String, amount: u128, recipient: Address,
|
|
constitutional_receipt: Hash, timestamp: Timestamp,
|
|
) -> Result<(), ACCReserveError> {
|
|
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
|
let entry = self.reserves.get_mut(&asset_symbol)
|
|
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
|
if entry.amount < amount {
|
|
return Err(ACCReserveError::InsufficientReserve { asset: asset_symbol.clone(), available: entry.amount, requested: amount });
|
|
}
|
|
entry.amount -= amount;
|
|
self.pending_events.push(ReserveProtocolEvent::ReserveWithdrawn { asset: asset_symbol, amount, recipient, constitutional_receipt, timestamp });
|
|
self.updated_at = Timestamp::now();
|
|
Ok(())
|
|
}
|
|
pub fn audit(
|
|
&mut self, asset_symbol: String, audit_hash: Hash, timestamp: Timestamp,
|
|
) -> Result<(), ACCReserveError> {
|
|
let entry = self.reserves.get_mut(&asset_symbol)
|
|
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
|
entry.last_audited = timestamp.clone();
|
|
entry.audit_hash = audit_hash;
|
|
self.pending_events.push(ReserveProtocolEvent::ReserveAudited { asset: asset_symbol, audit_hash, timestamp });
|
|
Ok(())
|
|
}
|
|
pub fn get_reserve(&self, asset: &str) -> Option<&ReserveEntry> { self.reserves.get(asset) }
|
|
pub fn total_reserve_count(&self) -> usize { self.reserves.len() }
|
|
pub fn drain_pending_events(&mut self) -> Vec<ReserveProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
|
}
|