NAC_Blockchain/nac-acc-1400/src/dividend.rs

409 lines
12 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 std::collections::HashMap;
use serde::{Serialize, Deserialize};
/// 股息分配记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DividendRecord {
/// 分配ID
pub id: String,
/// 证券分区ID
pub security_id: [u8; 32],
/// 分配时间戳
pub timestamp: u64,
/// 每股股息金额
pub amount_per_share: u64,
/// 总分配金额
pub total_amount: u64,
/// 受益人数量
pub beneficiary_count: usize,
/// 分配状态
pub status: DividendStatus,
/// 税率百分比例如15表示15%
pub tax_rate: u8,
}
/// 股息分配状态
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DividendStatus {
/// 待分配
Pending,
/// 分配中
Distributing,
/// 已完成
Completed,
/// 已取消
Cancelled,
}
/// 个人股息记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersonalDividend {
/// 分配ID
pub dividend_id: String,
/// 账户地址
pub account: String,
/// 持股数量
pub shares: u64,
/// 税前金额
pub gross_amount: u64,
/// 税额
pub tax_amount: u64,
/// 税后金额(实际到账)
pub net_amount: u64,
/// 领取状态
pub claimed: bool,
/// 领取时间
pub claim_time: Option<u64>,
}
/// 股息分配引擎
#[derive(Debug)]
pub struct DividendEngine {
/// 股息分配记录
records: HashMap<String, DividendRecord>,
/// 个人股息记录
personal_dividends: HashMap<String, Vec<PersonalDividend>>,
/// 下一个分配ID
next_id: u64,
}
impl DividendEngine {
/// 创建新的股息分配引擎
pub fn new() -> Self {
Self {
records: HashMap::new(),
personal_dividends: HashMap::new(),
next_id: 1,
}
}
/// 声明股息分配
///
/// # 参数
/// - security_id: 证券分区ID
/// - amount_per_share: 每股股息金额
/// - tax_rate: 税率(百分比)
/// - holders: 持有人及其持股数量
pub fn declare_dividend(
&mut self,
security_id: [u8; 32],
amount_per_share: u64,
tax_rate: u8,
holders: &HashMap<String, u64>,
) -> Result<String, String> {
// 验证参数
if amount_per_share == 0 {
return Err("Amount per share must be greater than zero".to_string());
}
if tax_rate > 100 {
return Err("Tax rate must be between 0 and 100".to_string());
}
if holders.is_empty() {
return Err("No holders specified".to_string());
}
// 生成分配ID
let dividend_id = format!("DIV-{:08}", self.next_id);
self.next_id += 1;
// 计算总金额
let total_shares: u64 = holders.values().sum();
let total_amount = total_shares * amount_per_share;
// 创建分配记录
let record = DividendRecord {
id: dividend_id.clone(),
security_id,
timestamp: Self::current_timestamp(),
amount_per_share,
total_amount,
beneficiary_count: holders.len(),
status: DividendStatus::Pending,
tax_rate,
};
self.records.insert(dividend_id.clone(), record);
// 为每个持有人创建个人股息记录
for (account, shares) in holders {
let gross_amount = shares * amount_per_share;
let tax_amount = (gross_amount * tax_rate as u64) / 100;
let net_amount = gross_amount - tax_amount;
let personal_dividend = PersonalDividend {
dividend_id: dividend_id.clone(),
account: account.clone(),
shares: *shares,
gross_amount,
tax_amount,
net_amount,
claimed: false,
claim_time: None,
};
self.personal_dividends
.entry(account.clone())
.or_insert_with(Vec::new)
.push(personal_dividend);
}
Ok(dividend_id)
}
/// 执行股息分配
pub fn distribute_dividend(&mut self, dividend_id: &str) -> Result<(), String> {
let record = self.records.get_mut(dividend_id)
.ok_or_else(|| "Dividend not found".to_string())?;
if record.status != DividendStatus::Pending {
return Err(format!("Dividend is not in pending status: {:?}", record.status));
}
// 更新状态为分配中
record.status = DividendStatus::Distributing;
// 实际分配逻辑(这里简化为标记为已分配)
// 在真实实现中,这里会调用转账功能将资金分配给持有人
// 更新状态为已完成
record.status = DividendStatus::Completed;
Ok(())
}
/// 领取股息
pub fn claim_dividend(&mut self, account: &str, dividend_id: &str) -> Result<u64, String> {
let personal_dividends = self.personal_dividends.get_mut(account)
.ok_or_else(|| "No dividends for this account".to_string())?;
let dividend = personal_dividends.iter_mut()
.find(|d| d.dividend_id == dividend_id)
.ok_or_else(|| "Dividend not found for this account".to_string())?;
if dividend.claimed {
return Err("Dividend already claimed".to_string());
}
// 检查分配记录状态
let record = self.records.get(dividend_id)
.ok_or_else(|| "Dividend record not found".to_string())?;
if record.status != DividendStatus::Completed {
return Err("Dividend distribution not completed yet".to_string());
}
// 标记为已领取
dividend.claimed = true;
dividend.claim_time = Some(Self::current_timestamp());
Ok(dividend.net_amount)
}
/// 获取账户的所有股息记录
pub fn get_dividends(&self, account: &str) -> Vec<PersonalDividend> {
self.personal_dividends
.get(account)
.cloned()
.unwrap_or_default()
}
/// 获取账户的未领取股息
pub fn get_unclaimed_dividends(&self, account: &str) -> Vec<PersonalDividend> {
self.get_dividends(account)
.into_iter()
.filter(|d| !d.claimed)
.collect()
}
/// 获取账户的总未领取股息金额
pub fn get_total_unclaimed_amount(&self, account: &str) -> u64 {
self.get_unclaimed_dividends(account)
.iter()
.map(|d| d.net_amount)
.sum()
}
/// 获取分配记录
pub fn get_dividend_record(&self, dividend_id: &str) -> Option<&DividendRecord> {
self.records.get(dividend_id)
}
/// 取消股息分配
pub fn cancel_dividend(&mut self, dividend_id: &str) -> Result<(), String> {
let record = self.records.get_mut(dividend_id)
.ok_or_else(|| "Dividend not found".to_string())?;
if record.status != DividendStatus::Pending {
return Err("Can only cancel pending dividends".to_string());
}
record.status = DividendStatus::Cancelled;
Ok(())
}
/// 获取证券的所有股息记录
pub fn get_security_dividends(&self, security_id: &[u8; 32]) -> Vec<DividendRecord> {
self.records
.values()
.filter(|r| &r.security_id == security_id)
.cloned()
.collect()
}
/// 计算账户的累计股息收入
pub fn calculate_total_dividend_income(&self, account: &str) -> (u64, u64, u64) {
let dividends = self.get_dividends(account);
let total_gross: u64 = dividends.iter().map(|d| d.gross_amount).sum();
let total_tax: u64 = dividends.iter().map(|d| d.tax_amount).sum();
let total_net: u64 = dividends.iter().map(|d| d.net_amount).sum();
(total_gross, total_tax, total_net)
}
/// 获取当前时间戳
fn current_timestamp() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
}
}
impl Default for DividendEngine {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_declare_dividend() {
let mut engine = DividendEngine::new();
let security_id = [1u8; 32];
let mut holders = HashMap::new();
holders.insert("investor1".to_string(), 1000);
holders.insert("investor2".to_string(), 500);
let result = engine.declare_dividend(security_id, 10, 15, &holders);
assert!(result.is_ok());
let dividend_id = result.unwrap();
let record = engine.get_dividend_record(&dividend_id).unwrap();
assert_eq!(record.amount_per_share, 10);
assert_eq!(record.total_amount, 15000); // (1000 + 500) * 10
assert_eq!(record.beneficiary_count, 2);
assert_eq!(record.tax_rate, 15);
}
#[test]
fn test_distribute_and_claim_dividend() {
let mut engine = DividendEngine::new();
let security_id = [1u8; 32];
let mut holders = HashMap::new();
holders.insert("investor1".to_string(), 1000);
let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap();
// 分配股息
engine.distribute_dividend(&dividend_id).unwrap();
// 领取股息
let amount = engine.claim_dividend("investor1", &dividend_id).unwrap();
// 税前: 1000 * 10 = 10000
// 税额: 10000 * 15% = 1500
// 税后: 10000 - 1500 = 8500
assert_eq!(amount, 8500);
// 再次领取应该失败
let result = engine.claim_dividend("investor1", &dividend_id);
assert!(result.is_err());
}
#[test]
fn test_unclaimed_dividends() {
let mut engine = DividendEngine::new();
let security_id = [1u8; 32];
let mut holders = HashMap::new();
holders.insert("investor1".to_string(), 1000);
let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap();
engine.distribute_dividend(&dividend_id).unwrap();
let unclaimed = engine.get_unclaimed_dividends("investor1");
assert_eq!(unclaimed.len(), 1);
assert_eq!(unclaimed[0].net_amount, 8500);
let total = engine.get_total_unclaimed_amount("investor1");
assert_eq!(total, 8500);
// 领取后应该没有未领取股息
engine.claim_dividend("investor1", &dividend_id).unwrap();
let unclaimed = engine.get_unclaimed_dividends("investor1");
assert_eq!(unclaimed.len(), 0);
}
#[test]
fn test_cancel_dividend() {
let mut engine = DividendEngine::new();
let security_id = [1u8; 32];
let mut holders = HashMap::new();
holders.insert("investor1".to_string(), 1000);
let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap();
// 取消分配
engine.cancel_dividend(&dividend_id).unwrap();
let record = engine.get_dividend_record(&dividend_id).unwrap();
assert_eq!(record.status, DividendStatus::Cancelled);
// 已取消的分配不能执行
let result = engine.distribute_dividend(&dividend_id);
assert!(result.is_err());
}
#[test]
fn test_total_dividend_income() {
let mut engine = DividendEngine::new();
let security_id = [1u8; 32];
let mut holders = HashMap::new();
holders.insert("investor1".to_string(), 1000);
// 第一次分配
let div1 = engine.declare_dividend(security_id, 10, 15, &holders).unwrap();
engine.distribute_dividend(&div1).unwrap();
engine.claim_dividend("investor1", &div1).unwrap();
// 第二次分配
let div2 = engine.declare_dividend(security_id, 20, 15, &holders).unwrap();
engine.distribute_dividend(&div2).unwrap();
engine.claim_dividend("investor1", &div2).unwrap();
let (gross, tax, net) = engine.calculate_total_dividend_income("investor1");
// 第一次: 10000税前, 1500税, 8500税后
// 第二次: 20000税前, 3000税, 17000税后
// 总计: 30000税前, 4500税, 25500税后
assert_eq!(gross, 30000);
assert_eq!(tax, 4500);
assert_eq!(net, 25500);
}
}