621 lines
18 KiB
Rust
621 lines
18 KiB
Rust
// ACC-Insurance: 资产保险协议(Insurance Protocol)
|
||
//
|
||
// NAC原生的资产保险标准,用于风险管理和保险保障
|
||
// 100% NAC原生协议,不是任何现有标准的实现
|
||
|
||
use serde::{Deserialize, Serialize};
|
||
use std::collections::HashMap;
|
||
|
||
/// 保险状态
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum InsuranceStatus {
|
||
/// 活跃
|
||
Active,
|
||
/// 已暂停
|
||
Suspended,
|
||
/// 已过期
|
||
Expired,
|
||
/// 已终止
|
||
Terminated,
|
||
}
|
||
|
||
/// 理赔状态
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum ClaimStatus {
|
||
/// 待审核
|
||
Pending,
|
||
/// 审核中
|
||
UnderReview,
|
||
/// 已批准
|
||
Approved,
|
||
/// 已拒绝
|
||
Rejected,
|
||
/// 已支付
|
||
Paid,
|
||
}
|
||
|
||
/// 保险类型
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum InsuranceType {
|
||
/// 财产保险
|
||
Property,
|
||
/// 责任保险
|
||
Liability,
|
||
/// 信用保险
|
||
Credit,
|
||
/// 智能合约保险
|
||
SmartContract,
|
||
/// 其他
|
||
Other(String),
|
||
}
|
||
|
||
/// 保险策略
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct InsurancePolicy {
|
||
/// 保单ID
|
||
pub policy_id: String,
|
||
/// 资产ID
|
||
pub asset_id: String,
|
||
/// 被保险人地址
|
||
pub insured: String,
|
||
/// 保险公司地址
|
||
pub insurer: String,
|
||
/// 保险类型
|
||
pub insurance_type: InsuranceType,
|
||
/// 保险金额(USD,以分为单位)
|
||
pub coverage_amount: u128,
|
||
/// 保费(USD,以分为单位)
|
||
pub premium: u128,
|
||
/// 免赔额(USD,以分为单位)
|
||
pub deductible: u128,
|
||
/// 保险状态
|
||
pub status: InsuranceStatus,
|
||
/// 生效时间
|
||
pub effective_date: u64,
|
||
/// 到期时间
|
||
pub expiration_date: u64,
|
||
/// 创建时间
|
||
pub created_at: u64,
|
||
/// 更新时间
|
||
pub updated_at: u64,
|
||
/// 保险条款
|
||
pub terms: Vec<String>,
|
||
}
|
||
|
||
/// 理赔申请
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct ClaimRequest {
|
||
/// 理赔ID
|
||
pub claim_id: String,
|
||
/// 保单ID
|
||
pub policy_id: String,
|
||
/// 申请人地址
|
||
pub claimant: String,
|
||
/// 理赔金额(USD,以分为单位)
|
||
pub claim_amount: u128,
|
||
/// 理赔状态
|
||
pub status: ClaimStatus,
|
||
/// 申请时间
|
||
pub filed_at: u64,
|
||
/// 批准时间
|
||
pub approved_at: Option<u64>,
|
||
/// 支付时间
|
||
pub paid_at: Option<u64>,
|
||
/// 实际赔付金额
|
||
pub payout_amount: Option<u128>,
|
||
/// 理赔描述
|
||
pub description: String,
|
||
/// 证据哈希列表
|
||
pub evidence_hashes: Vec<[u8; 32]>,
|
||
/// 审核备注
|
||
pub notes: Vec<String>,
|
||
}
|
||
|
||
/// 保险错误类型
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum InsuranceError {
|
||
/// 保单不存在
|
||
PolicyNotFound,
|
||
/// 保单已存在
|
||
PolicyAlreadyExists,
|
||
/// 理赔申请不存在
|
||
ClaimNotFound,
|
||
/// 理赔申请已存在
|
||
ClaimAlreadyExists,
|
||
/// 保单已过期
|
||
PolicyExpired,
|
||
/// 保单已暂停
|
||
PolicySuspended,
|
||
/// 理赔金额超过保险金额
|
||
ClaimExceedsCoverage,
|
||
/// 未授权操作
|
||
Unauthorized,
|
||
/// 保费未支付
|
||
PremiumNotPaid,
|
||
}
|
||
|
||
/// 保险状态
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct InsuranceState {
|
||
/// 保单映射 (policy_id -> InsurancePolicy)
|
||
pub policies: HashMap<String, InsurancePolicy>,
|
||
/// 资产保单映射 (asset_id -> policy_id)
|
||
pub asset_policies: HashMap<String, String>,
|
||
/// 被保险人保单列表 (insured -> [policy_ids])
|
||
pub insured_policies: HashMap<String, Vec<String>>,
|
||
/// 理赔申请映射 (claim_id -> ClaimRequest)
|
||
pub claims: HashMap<String, ClaimRequest>,
|
||
/// 保单理赔列表 (policy_id -> [claim_ids])
|
||
pub policy_claims: HashMap<String, Vec<String>>,
|
||
}
|
||
|
||
/// ACC-Insurance接口
|
||
pub trait ACCInsurance {
|
||
/// 创建保单
|
||
fn create_policy(&mut self, policy: InsurancePolicy) -> Result<(), InsuranceError>;
|
||
|
||
/// 获取保单
|
||
fn get_policy(&self, policy_id: &str) -> Result<InsurancePolicy, InsuranceError>;
|
||
|
||
/// 获取资产的保单
|
||
fn get_asset_policy(&self, asset_id: &str) -> Result<InsurancePolicy, InsuranceError>;
|
||
|
||
/// 提交理赔申请
|
||
fn file_claim(&mut self, claim: ClaimRequest) -> Result<(), InsuranceError>;
|
||
|
||
/// 获取理赔申请
|
||
fn get_claim(&self, claim_id: &str) -> Result<ClaimRequest, InsuranceError>;
|
||
|
||
/// 批准理赔
|
||
fn approve_claim(&mut self, claim_id: &str, payout_amount: u128) -> Result<(), InsuranceError>;
|
||
|
||
/// 拒绝理赔
|
||
fn reject_claim(&mut self, claim_id: &str, reason: String) -> Result<(), InsuranceError>;
|
||
|
||
/// 支付理赔
|
||
fn pay_claim(&mut self, claim_id: &str) -> Result<(), InsuranceError>;
|
||
|
||
/// 续保
|
||
fn renew_policy(&mut self, policy_id: &str, new_expiration: u64) -> Result<(), InsuranceError>;
|
||
|
||
/// 暂停保单
|
||
fn suspend_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError>;
|
||
|
||
/// 恢复保单
|
||
fn resume_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError>;
|
||
|
||
/// 终止保单
|
||
fn terminate_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError>;
|
||
|
||
/// 获取被保险人的保单列表
|
||
fn get_insured_policies(&self, insured: &str) -> Vec<InsurancePolicy>;
|
||
|
||
/// 获取保单的理赔历史
|
||
fn get_policy_claims(&self, policy_id: &str) -> Vec<ClaimRequest>;
|
||
|
||
/// 检查保单是否有效
|
||
fn is_policy_valid(&self, policy_id: &str) -> bool;
|
||
}
|
||
|
||
/// ACC-Insurance标准实现
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct InsuranceToken {
|
||
state: InsuranceState,
|
||
}
|
||
|
||
impl InsuranceToken {
|
||
/// 创建新的保险管理器
|
||
pub fn new() -> Self {
|
||
Self {
|
||
state: InsuranceState {
|
||
policies: HashMap::new(),
|
||
asset_policies: HashMap::new(),
|
||
insured_policies: HashMap::new(),
|
||
claims: HashMap::new(),
|
||
policy_claims: HashMap::new(),
|
||
},
|
||
}
|
||
}
|
||
|
||
/// 获取状态的可变引用
|
||
pub fn state_mut(&mut self) -> &mut InsuranceState {
|
||
&mut self.state
|
||
}
|
||
|
||
/// 获取状态的不可变引用
|
||
pub fn state(&self) -> &InsuranceState {
|
||
&self.state
|
||
}
|
||
|
||
/// 检查保单状态
|
||
fn check_policy_status(&self, policy: &InsurancePolicy) -> Result<(), InsuranceError> {
|
||
match policy.status {
|
||
InsuranceStatus::Expired => Err(InsuranceError::PolicyExpired),
|
||
InsuranceStatus::Suspended => Err(InsuranceError::PolicySuspended),
|
||
InsuranceStatus::Terminated => Err(InsuranceError::PolicyExpired),
|
||
_ => Ok(()),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Default for InsuranceToken {
|
||
fn default() -> Self {
|
||
Self::new()
|
||
}
|
||
}
|
||
|
||
impl ACCInsurance for InsuranceToken {
|
||
fn create_policy(&mut self, mut policy: InsurancePolicy) -> Result<(), InsuranceError> {
|
||
// 检查保单是否已存在
|
||
if self.state.policies.contains_key(&policy.policy_id) {
|
||
return Err(InsuranceError::PolicyAlreadyExists);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
policy.created_at = now;
|
||
policy.updated_at = now;
|
||
policy.status = InsuranceStatus::Active;
|
||
|
||
let policy_id = policy.policy_id.clone();
|
||
let asset_id = policy.asset_id.clone();
|
||
let insured = policy.insured.clone();
|
||
|
||
// 保存保单
|
||
self.state.policies.insert(policy_id.clone(), policy);
|
||
|
||
// 更新资产保单映射
|
||
self.state
|
||
.asset_policies
|
||
.insert(asset_id, policy_id.clone());
|
||
|
||
// 更新被保险人保单列表
|
||
self.state
|
||
.insured_policies
|
||
.entry(insured)
|
||
.or_insert_with(Vec::new)
|
||
.push(policy_id);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn get_policy(&self, policy_id: &str) -> Result<InsurancePolicy, InsuranceError> {
|
||
self.state
|
||
.policies
|
||
.get(policy_id)
|
||
.cloned()
|
||
.ok_or(InsuranceError::PolicyNotFound)
|
||
}
|
||
|
||
fn get_asset_policy(&self, asset_id: &str) -> Result<InsurancePolicy, InsuranceError> {
|
||
let policy_id = self
|
||
.state
|
||
.asset_policies
|
||
.get(asset_id)
|
||
.ok_or(InsuranceError::PolicyNotFound)?;
|
||
self.get_policy(policy_id)
|
||
}
|
||
|
||
fn file_claim(&mut self, mut claim: ClaimRequest) -> Result<(), InsuranceError> {
|
||
// 检查理赔申请是否已存在
|
||
if self.state.claims.contains_key(&claim.claim_id) {
|
||
return Err(InsuranceError::ClaimAlreadyExists);
|
||
}
|
||
|
||
// 获取保单并检查状态
|
||
let policy = self.get_policy(&claim.policy_id)?;
|
||
self.check_policy_status(&policy)?;
|
||
|
||
// 检查理赔金额
|
||
if claim.claim_amount > policy.coverage_amount {
|
||
return Err(InsuranceError::ClaimExceedsCoverage);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
claim.filed_at = now;
|
||
claim.status = ClaimStatus::Pending;
|
||
|
||
let claim_id = claim.claim_id.clone();
|
||
let policy_id = claim.policy_id.clone();
|
||
|
||
// 保存理赔申请
|
||
self.state.claims.insert(claim_id.clone(), claim);
|
||
|
||
// 更新保单理赔列表
|
||
self.state
|
||
.policy_claims
|
||
.entry(policy_id)
|
||
.or_insert_with(Vec::new)
|
||
.push(claim_id);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn get_claim(&self, claim_id: &str) -> Result<ClaimRequest, InsuranceError> {
|
||
self.state
|
||
.claims
|
||
.get(claim_id)
|
||
.cloned()
|
||
.ok_or(InsuranceError::ClaimNotFound)
|
||
}
|
||
|
||
fn approve_claim(&mut self, claim_id: &str, payout_amount: u128) -> Result<(), InsuranceError> {
|
||
let mut claim = self.get_claim(claim_id)?;
|
||
|
||
if claim.status != ClaimStatus::Pending && claim.status != ClaimStatus::UnderReview {
|
||
return Err(InsuranceError::Unauthorized);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
claim.status = ClaimStatus::Approved;
|
||
claim.approved_at = Some(now);
|
||
claim.payout_amount = Some(payout_amount);
|
||
|
||
self.state.claims.insert(claim_id.to_string(), claim);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn reject_claim(&mut self, claim_id: &str, reason: String) -> Result<(), InsuranceError> {
|
||
let mut claim = self.get_claim(claim_id)?;
|
||
|
||
if claim.status != ClaimStatus::Pending && claim.status != ClaimStatus::UnderReview {
|
||
return Err(InsuranceError::Unauthorized);
|
||
}
|
||
|
||
claim.status = ClaimStatus::Rejected;
|
||
claim.notes.push(format!("Rejected: {}", reason));
|
||
|
||
self.state.claims.insert(claim_id.to_string(), claim);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn pay_claim(&mut self, claim_id: &str) -> Result<(), InsuranceError> {
|
||
let mut claim = self.get_claim(claim_id)?;
|
||
|
||
if claim.status != ClaimStatus::Approved {
|
||
return Err(InsuranceError::Unauthorized);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
claim.status = ClaimStatus::Paid;
|
||
claim.paid_at = Some(now);
|
||
|
||
self.state.claims.insert(claim_id.to_string(), claim);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn renew_policy(&mut self, policy_id: &str, new_expiration: u64) -> Result<(), InsuranceError> {
|
||
let mut policy = self.get_policy(policy_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
policy.expiration_date = new_expiration;
|
||
policy.status = InsuranceStatus::Active;
|
||
policy.updated_at = now;
|
||
|
||
self.state.policies.insert(policy_id.to_string(), policy);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn suspend_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError> {
|
||
let mut policy = self.get_policy(policy_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
policy.status = InsuranceStatus::Suspended;
|
||
policy.updated_at = now;
|
||
|
||
self.state.policies.insert(policy_id.to_string(), policy);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn resume_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError> {
|
||
let mut policy = self.get_policy(policy_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
policy.status = InsuranceStatus::Active;
|
||
policy.updated_at = now;
|
||
|
||
self.state.policies.insert(policy_id.to_string(), policy);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn terminate_policy(&mut self, policy_id: &str) -> Result<(), InsuranceError> {
|
||
let mut policy = self.get_policy(policy_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
|
||
policy.status = InsuranceStatus::Terminated;
|
||
policy.updated_at = now;
|
||
|
||
self.state.policies.insert(policy_id.to_string(), policy);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn get_insured_policies(&self, insured: &str) -> Vec<InsurancePolicy> {
|
||
self.state
|
||
.insured_policies
|
||
.get(insured)
|
||
.map(|policy_ids| {
|
||
policy_ids
|
||
.iter()
|
||
.filter_map(|id| self.state.policies.get(id).cloned())
|
||
.collect()
|
||
})
|
||
.unwrap_or_default()
|
||
}
|
||
|
||
fn get_policy_claims(&self, policy_id: &str) -> Vec<ClaimRequest> {
|
||
self.state
|
||
.policy_claims
|
||
.get(policy_id)
|
||
.map(|claim_ids| {
|
||
claim_ids
|
||
.iter()
|
||
.filter_map(|id| self.state.claims.get(id).cloned())
|
||
.collect()
|
||
})
|
||
.unwrap_or_default()
|
||
}
|
||
|
||
fn is_policy_valid(&self, policy_id: &str) -> bool {
|
||
if let Ok(policy) = self.get_policy(policy_id) {
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.expect("mainnet: handle error")
|
||
.as_secs();
|
||
policy.status == InsuranceStatus::Active && now < policy.expiration_date
|
||
} else {
|
||
false
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
fn create_test_policy() -> InsurancePolicy {
|
||
InsurancePolicy {
|
||
policy_id: "POL-001".to_string(),
|
||
asset_id: "RWA-001".to_string(),
|
||
insured: "alice".to_string(),
|
||
insurer: "insurer1".to_string(),
|
||
insurance_type: InsuranceType::Property,
|
||
coverage_amount: 1000000_00,
|
||
premium: 10000_00,
|
||
deductible: 5000_00,
|
||
status: InsuranceStatus::Active,
|
||
effective_date: 1234567890,
|
||
expiration_date: 1234567890 + 31536000,
|
||
created_at: 0,
|
||
updated_at: 0,
|
||
terms: vec!["Term 1".to_string(), "Term 2".to_string()],
|
||
}
|
||
}
|
||
|
||
fn create_test_claim() -> ClaimRequest {
|
||
ClaimRequest {
|
||
claim_id: "CLAIM-001".to_string(),
|
||
policy_id: "POL-001".to_string(),
|
||
claimant: "alice".to_string(),
|
||
claim_amount: 50000_00,
|
||
status: ClaimStatus::Pending,
|
||
filed_at: 0,
|
||
approved_at: None,
|
||
paid_at: None,
|
||
payout_amount: None,
|
||
description: "Test claim".to_string(),
|
||
evidence_hashes: vec![[1u8; 32]],
|
||
notes: Vec::new(),
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_create_policy() {
|
||
let mut insurance = InsuranceToken::new();
|
||
let policy = create_test_policy();
|
||
assert!(insurance.create_policy(policy).is_ok());
|
||
}
|
||
|
||
#[test]
|
||
fn test_file_claim() {
|
||
let mut insurance = InsuranceToken::new();
|
||
let policy = create_test_policy();
|
||
insurance.create_policy(policy).expect("mainnet: handle error");
|
||
|
||
let claim = create_test_claim();
|
||
assert!(insurance.file_claim(claim).is_ok());
|
||
}
|
||
|
||
#[test]
|
||
fn test_approve_and_pay_claim() {
|
||
let mut insurance = InsuranceToken::new();
|
||
let policy = create_test_policy();
|
||
insurance.create_policy(policy).expect("mainnet: handle error");
|
||
|
||
let claim = create_test_claim();
|
||
insurance.file_claim(claim).expect("mainnet: handle error");
|
||
|
||
assert!(insurance.approve_claim("CLAIM-001", 45000_00).is_ok());
|
||
assert_eq!(
|
||
insurance.get_claim("CLAIM-001").expect("mainnet: handle error").status,
|
||
ClaimStatus::Approved
|
||
);
|
||
|
||
assert!(insurance.pay_claim("CLAIM-001").is_ok());
|
||
assert_eq!(
|
||
insurance.get_claim("CLAIM-001").expect("mainnet: handle error").status,
|
||
ClaimStatus::Paid
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn test_renew_policy() {
|
||
let mut insurance = InsuranceToken::new();
|
||
let policy = create_test_policy();
|
||
insurance.create_policy(policy).expect("mainnet: handle error");
|
||
|
||
let new_expiration = 1234567890 + 63072000; // 2 years
|
||
assert!(insurance.renew_policy("POL-001", new_expiration).is_ok());
|
||
assert_eq!(
|
||
insurance.get_policy("POL-001").expect("mainnet: handle error").expiration_date,
|
||
new_expiration
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn test_suspend_and_resume_policy() {
|
||
let mut insurance = InsuranceToken::new();
|
||
let policy = create_test_policy();
|
||
insurance.create_policy(policy).expect("mainnet: handle error");
|
||
|
||
assert!(insurance.suspend_policy("POL-001").is_ok());
|
||
assert_eq!(
|
||
insurance.get_policy("POL-001").expect("mainnet: handle error").status,
|
||
InsuranceStatus::Suspended
|
||
);
|
||
|
||
assert!(insurance.resume_policy("POL-001").is_ok());
|
||
assert_eq!(
|
||
insurance.get_policy("POL-001").expect("mainnet: handle error").status,
|
||
InsuranceStatus::Active
|
||
);
|
||
}
|
||
}
|