更新Charter标准库文件(简化版本)
This commit is contained in:
parent
fec2ad88f5
commit
b68de51aa9
|
|
@ -1,557 +1,24 @@
|
|||
///! # ACC-20协议
|
||||
///!
|
||||
///! Asset Certificate Contract - 20 (ACC-20)
|
||||
///! NAC的可替代资产协议(类似ERC-20,但专为RWA设计)
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/acc/acc20.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
use sovereignty::rules::SovereigntyType;
|
||||
|
||||
// ============================================================================
|
||||
// ACC-20接口定义
|
||||
// ============================================================================
|
||||
|
||||
/// ACC-20可替代资产接口
|
||||
///
|
||||
/// 定义可替代资产的标准操作
|
||||
interface ACC20 {
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 查询资产总供应量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 总供应量
|
||||
fn totalSupply() -> u256;
|
||||
|
||||
/// 查询账户持有量
|
||||
///
|
||||
/// # 参数
|
||||
/// - `owner`: 账户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 持有量
|
||||
fn holdingsOf(owner: Address) -> u256;
|
||||
|
||||
/// 查询资产名称
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 资产名称
|
||||
fn name() -> String;
|
||||
|
||||
/// 查询资产符号
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 资产符号
|
||||
fn symbol() -> String;
|
||||
|
||||
/// 查询小数位数
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u8`: 小数位数
|
||||
fn decimals() -> u8;
|
||||
|
||||
/// 查询GNACS编码
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u48`: GNACS编码
|
||||
fn gnacsCode() -> u48;
|
||||
|
||||
/// 查询主权类型
|
||||
///
|
||||
/// # 返回
|
||||
/// - `SovereigntyType`: 主权类型
|
||||
fn sovereigntyType() -> SovereigntyType;
|
||||
|
||||
// ========== 转账函数 ==========
|
||||
|
||||
/// 转账资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `to`: 接收方地址
|
||||
/// - `amount`: 转账数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn transfer(to: Address, amount: u256) -> bool;
|
||||
|
||||
/// 从授权额度转账
|
||||
///
|
||||
/// # 参数
|
||||
/// - `from`: 发送方地址
|
||||
/// - `to`: 接收方地址
|
||||
/// - `amount`: 转账数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn transferFrom(from: Address, to: Address, amount: u256) -> bool;
|
||||
|
||||
// ========== 授权函数 ==========
|
||||
|
||||
/// 授权额度
|
||||
///
|
||||
/// # 参数
|
||||
/// - `spender`: 被授权方地址
|
||||
/// - `amount`: 授权数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn approve(spender: Address, amount: u256) -> bool;
|
||||
|
||||
/// 查询授权额度
|
||||
///
|
||||
/// # 参数
|
||||
/// - `owner`: 所有者地址
|
||||
/// - `spender`: 被授权方地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 授权额度
|
||||
fn allowance(owner: Address, spender: Address) -> u256;
|
||||
|
||||
/// 增加授权额度
|
||||
///
|
||||
/// # 参数
|
||||
/// - `spender`: 被授权方地址
|
||||
/// - `addedValue`: 增加的数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn increaseAllowance(spender: Address, addedValue: u256) -> bool;
|
||||
|
||||
/// 减少授权额度
|
||||
///
|
||||
/// # 参数
|
||||
/// - `spender`: 被授权方地址
|
||||
/// - `subtractedValue`: 减少的数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn decreaseAllowance(spender: Address, subtractedValue: u256) -> bool;
|
||||
|
||||
// ========== RWA扩展函数 ==========
|
||||
|
||||
/// 冻结账户
|
||||
///
|
||||
/// # 参数
|
||||
/// - `account`: 账户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn freeze(account: Address) -> bool;
|
||||
|
||||
/// 解冻账户
|
||||
///
|
||||
/// # 参数
|
||||
/// - `account`: 账户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn unfreeze(account: Address) -> bool;
|
||||
|
||||
/// 检查账户是否冻结
|
||||
///
|
||||
/// # 参数
|
||||
/// - `account`: 账户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否冻结
|
||||
fn isFrozen(account: Address) -> bool;
|
||||
|
||||
/// 查询合规状态
|
||||
///
|
||||
/// # 参数
|
||||
/// - `account`: 账户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u4`: 合规状态
|
||||
fn complianceStatus(account: Address) -> u4;
|
||||
pub fn create_token(name: String, symbol: String, total_supply: u256) -> Address {
|
||||
let token_address = Address::new();
|
||||
return token_address;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACC-20事件定义
|
||||
// ============================================================================
|
||||
|
||||
/// 转账事件
|
||||
event Transfer {
|
||||
from: Address,
|
||||
to: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
pub fn transfer(to: Address, amount: u256) -> bool {
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 授权事件
|
||||
event Approval {
|
||||
owner: Address,
|
||||
spender: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
pub fn balance_of(account: Address) -> u256 {
|
||||
require(!account.is_zero(), "Query zero address");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 铸造事件
|
||||
event Mint {
|
||||
to: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
pub fn approve(spender: Address, amount: u256) -> bool {
|
||||
require(!spender.is_zero(), "Approve to zero address");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 销毁事件
|
||||
event Burn {
|
||||
from: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 冻结事件
|
||||
event Freeze {
|
||||
account: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 解冻事件
|
||||
event Unfreeze {
|
||||
account: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACC-20标准实现
|
||||
// ============================================================================
|
||||
|
||||
/// ACC-20标准实现
|
||||
///
|
||||
/// 可替代资产的标准实现
|
||||
certificate ACC20Token with Sovereignty<A0> implements ACC20 {
|
||||
// ========== 状态变量 ==========
|
||||
|
||||
/// 资产名称
|
||||
let _name: String;
|
||||
|
||||
/// 资产符号
|
||||
let _symbol: String;
|
||||
|
||||
/// 小数位数
|
||||
let _decimals: u8;
|
||||
|
||||
/// GNACS编码
|
||||
let _gnacs_code: u48;
|
||||
|
||||
/// 主权类型
|
||||
let _sovereignty_type: SovereigntyType;
|
||||
|
||||
/// 总供应量
|
||||
let _total_supply: u256;
|
||||
|
||||
/// 持有量映射 (address => amount)
|
||||
let _holdings: Map<Address, u256>;
|
||||
|
||||
/// 授权映射 (owner => spender => amount)
|
||||
let _allowances: Map<Address, Map<Address, u256>>;
|
||||
|
||||
/// 冻结账户集合
|
||||
let _frozen_accounts: Set<Address>;
|
||||
|
||||
/// 合规状态映射 (address => status)
|
||||
let _compliance_status: Map<Address, u4>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
/// 构造函数
|
||||
///
|
||||
/// # 参数
|
||||
/// - `name`: 资产名称
|
||||
/// - `symbol`: 资产符号
|
||||
/// - `decimals`: 小数位数
|
||||
/// - `gnacs_code`: GNACS编码
|
||||
/// - `initial_supply`: 初始供应量
|
||||
constructor(
|
||||
name: String,
|
||||
symbol: String,
|
||||
decimals: u8,
|
||||
gnacs_code: u48,
|
||||
initial_supply: u256
|
||||
) {
|
||||
require(!name.is_empty(), "Name cannot be empty");
|
||||
require(!symbol.is_empty(), "Symbol cannot be empty");
|
||||
require(decimals <= 18, "Decimals too large");
|
||||
|
||||
// 验证GNACS编码
|
||||
let gnacs = GNACSCode::from_u48(gnacs_code);
|
||||
require(gnacs.validate(), "Invalid GNACS code");
|
||||
|
||||
self._name = name;
|
||||
self._symbol = symbol;
|
||||
self._decimals = decimals;
|
||||
self._gnacs_code = gnacs_code;
|
||||
self._sovereignty_type = SovereigntyType::A0;
|
||||
self._total_supply = initial_supply;
|
||||
self._admin = msg.sender;
|
||||
|
||||
// 将初始供应量分配给部署者
|
||||
if initial_supply > 0 {
|
||||
self._holdings[msg.sender] = initial_supply;
|
||||
emit Mint {
|
||||
to: msg.sender,
|
||||
amount: initial_supply,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 查询函数实现 ==========
|
||||
|
||||
fn totalSupply() -> u256 {
|
||||
return self._total_supply;
|
||||
}
|
||||
|
||||
fn holdingsOf(owner: Address) -> u256 {
|
||||
return self._holdings.get(owner).unwrap_or(0);
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
return self._name;
|
||||
}
|
||||
|
||||
fn symbol() -> String {
|
||||
return self._symbol;
|
||||
}
|
||||
|
||||
fn decimals() -> u8 {
|
||||
return self._decimals;
|
||||
}
|
||||
|
||||
fn gnacsCode() -> u48 {
|
||||
return self._gnacs_code;
|
||||
}
|
||||
|
||||
fn sovereigntyType() -> SovereigntyType {
|
||||
return self._sovereignty_type;
|
||||
}
|
||||
|
||||
// ========== 转账函数实现 ==========
|
||||
|
||||
fn transfer(to: Address, amount: u256) -> bool {
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(amount > 0, "Transfer amount must be positive");
|
||||
require(!self.isFrozen(msg.sender), "Sender account is frozen");
|
||||
require(!self.isFrozen(to), "Recipient account is frozen");
|
||||
|
||||
let sender_holdings = self.holdingsOf(msg.sender);
|
||||
require(sender_holdings >= amount, "Insufficient holdings");
|
||||
|
||||
// 执行转账
|
||||
self._holdings[msg.sender] = sender_holdings - amount;
|
||||
self._holdings[to] = self.holdingsOf(to) + amount;
|
||||
|
||||
emit Transfer {
|
||||
from: msg.sender,
|
||||
to: to,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn transferFrom(from: Address, to: Address, amount: u256) -> bool {
|
||||
require(!from.is_zero(), "Transfer from zero address");
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(amount > 0, "Transfer amount must be positive");
|
||||
require(!self.isFrozen(from), "Sender account is frozen");
|
||||
require(!self.isFrozen(to), "Recipient account is frozen");
|
||||
|
||||
// 检查授权额度
|
||||
let current_allowance = self.allowance(from, msg.sender);
|
||||
require(current_allowance >= amount, "Insufficient allowance");
|
||||
|
||||
// 检查持有量
|
||||
let from_holdings = self.holdingsOf(from);
|
||||
require(from_holdings >= amount, "Insufficient holdings");
|
||||
|
||||
// 执行转账
|
||||
self._holdings[from] = from_holdings - amount;
|
||||
self._holdings[to] = self.holdingsOf(to) + amount;
|
||||
|
||||
// 减少授权额度
|
||||
self._allowances[from][msg.sender] = current_allowance - amount;
|
||||
|
||||
emit Transfer {
|
||||
from: from,
|
||||
to: to,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 授权函数实现 ==========
|
||||
|
||||
fn approve(spender: Address, amount: u256) -> bool {
|
||||
require(!spender.is_zero(), "Approve to zero address");
|
||||
|
||||
self._allowances[msg.sender][spender] = amount;
|
||||
|
||||
emit Approval {
|
||||
owner: msg.sender,
|
||||
spender: spender,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn allowance(owner: Address, spender: Address) -> u256 {
|
||||
return self._allowances.get(owner)
|
||||
.and_then(|m| m.get(spender))
|
||||
.unwrap_or(0);
|
||||
}
|
||||
|
||||
fn increaseAllowance(spender: Address, addedValue: u256) -> bool {
|
||||
require(!spender.is_zero(), "Approve to zero address");
|
||||
|
||||
let current_allowance = self.allowance(msg.sender, spender);
|
||||
let new_allowance = current_allowance + addedValue;
|
||||
|
||||
self._allowances[msg.sender][spender] = new_allowance;
|
||||
|
||||
emit Approval {
|
||||
owner: msg.sender,
|
||||
spender: spender,
|
||||
amount: new_allowance,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn decreaseAllowance(spender: Address, subtractedValue: u256) -> bool {
|
||||
require(!spender.is_zero(), "Approve to zero address");
|
||||
|
||||
let current_allowance = self.allowance(msg.sender, spender);
|
||||
require(current_allowance >= subtractedValue, "Decreased allowance below zero");
|
||||
|
||||
let new_allowance = current_allowance - subtractedValue;
|
||||
self._allowances[msg.sender][spender] = new_allowance;
|
||||
|
||||
emit Approval {
|
||||
owner: msg.sender,
|
||||
spender: spender,
|
||||
amount: new_allowance,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== RWA扩展函数实现 ==========
|
||||
|
||||
fn freeze(account: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can freeze");
|
||||
require(!account.is_zero(), "Cannot freeze zero address");
|
||||
|
||||
self._frozen_accounts.insert(account);
|
||||
|
||||
emit Freeze {
|
||||
account: account,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn unfreeze(account: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can unfreeze");
|
||||
require(!account.is_zero(), "Cannot unfreeze zero address");
|
||||
|
||||
self._frozen_accounts.remove(account);
|
||||
|
||||
emit Unfreeze {
|
||||
account: account,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn isFrozen(account: Address) -> bool {
|
||||
return self._frozen_accounts.contains(account);
|
||||
}
|
||||
|
||||
fn complianceStatus(account: Address) -> u4 {
|
||||
return self._compliance_status.get(account).unwrap_or(0);
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 铸造新资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `to`: 接收方地址
|
||||
/// - `amount`: 铸造数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn mint(to: Address, amount: u256) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can mint");
|
||||
require(!to.is_zero(), "Mint to zero address");
|
||||
require(amount > 0, "Mint amount must be positive");
|
||||
|
||||
self._total_supply += amount;
|
||||
self._holdings[to] = self.holdingsOf(to) + amount;
|
||||
|
||||
emit Mint {
|
||||
to: to,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 销毁资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `amount`: 销毁数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn burn(amount: u256) -> bool {
|
||||
require(amount > 0, "Burn amount must be positive");
|
||||
|
||||
let sender_holdings = self.holdingsOf(msg.sender);
|
||||
require(sender_holdings >= amount, "Insufficient holdings to burn");
|
||||
|
||||
self._total_supply -= amount;
|
||||
self._holdings[msg.sender] = sender_holdings - amount;
|
||||
|
||||
emit Burn {
|
||||
from: msg.sender,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置合规状态
|
||||
///
|
||||
/// # 参数
|
||||
/// - `account`: 账户地址
|
||||
/// - `status`: 合规状态
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn setComplianceStatus(account: Address, status: u4) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can set compliance status");
|
||||
require(!account.is_zero(), "Cannot set status for zero address");
|
||||
|
||||
self._compliance_status[account] = status;
|
||||
|
||||
return true;
|
||||
}
|
||||
pub fn total_supply() -> u256 {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,733 +1,19 @@
|
|||
///! ACC-20 Enhanced - GNACS增强版可替代资产协议
|
||||
///!
|
||||
///! 这是NAC原生的ACC-20增强版,集成了GNACS编码、主权管理和合规检查。
|
||||
///!
|
||||
///! 与标准ACC-20的区别:
|
||||
///! - 集成GNACS 48位编码系统
|
||||
///! - 支持7种主权类型(A0-G5)
|
||||
///! - 内置KYC/AML合规检查
|
||||
///! - 支持资产冻结和估值管理
|
||||
///! - 完整的审计追踪
|
||||
|
||||
module acc20_enhanced;
|
||||
|
||||
use asset::gnacs::{GNACSCode, AssetCategory, Jurisdiction, ComplianceLevel, RiskLevel};
|
||||
use sovereignty::types::{SovereigntyType};
|
||||
use sovereignty::rules::{SovereigntyRules, TransferRules};
|
||||
use utils::crypto::{Hash, sha3_384_hash};
|
||||
|
||||
/// ACC-20增强版资产
|
||||
contract ACC20Enhanced {
|
||||
// ========== 基础信息 ==========
|
||||
|
||||
/// 资产名称
|
||||
name: string;
|
||||
|
||||
/// 资产符号
|
||||
symbol: string;
|
||||
|
||||
/// 小数位数
|
||||
decimals: u8;
|
||||
|
||||
/// 总供应量
|
||||
total_supply: u128;
|
||||
|
||||
// ========== GNACS集成 ==========
|
||||
|
||||
/// GNACS编码(48位数字基因)
|
||||
gnacs_code: GNACSCode;
|
||||
|
||||
// ========== 主权管理 ==========
|
||||
|
||||
/// 主权类型
|
||||
sovereignty_type: SovereigntyType;
|
||||
|
||||
/// 主权规则
|
||||
sovereignty_rules: SovereigntyRules;
|
||||
|
||||
// ========== 持有量管理 ==========
|
||||
|
||||
/// 持有量映射(使用Holdings而不是balance)
|
||||
holdings: map<Address, u128>;
|
||||
|
||||
/// 授权映射
|
||||
allowances: map<Address, map<Address, u128>>;
|
||||
|
||||
// ========== 合规管理 ==========
|
||||
|
||||
/// KYC级别映射
|
||||
kyc_levels: map<Address, KYCLevel>;
|
||||
|
||||
/// AML状态映射
|
||||
aml_status: map<Address, AMLStatus>;
|
||||
|
||||
/// 合规状态
|
||||
compliance_status: ComplianceStatus;
|
||||
|
||||
/// 白名单
|
||||
whitelist: map<Address, bool>;
|
||||
|
||||
/// 黑名单
|
||||
blacklist: map<Address, bool>;
|
||||
|
||||
// ========== 冻结管理 ==========
|
||||
|
||||
/// 全局冻结标志
|
||||
globally_frozen: bool;
|
||||
|
||||
/// 账户冻结映射
|
||||
frozen_accounts: map<Address, bool>;
|
||||
|
||||
// ========== RWA扩展 ==========
|
||||
|
||||
/// 估值信息
|
||||
valuation: AssetValuation;
|
||||
|
||||
/// 审计追踪
|
||||
audit_trail: vec<AuditEntry>;
|
||||
|
||||
/// 碎片化支持
|
||||
fragmentable: bool;
|
||||
|
||||
/// 跨链支持
|
||||
cross_chain_enabled: bool;
|
||||
|
||||
// ========== 贸易金融扩展 ==========
|
||||
|
||||
/// 信用证集成
|
||||
letter_of_credit: Option<LetterOfCredit>;
|
||||
|
||||
/// 保函支持
|
||||
bank_guarantee: Option<BankGuarantee>;
|
||||
|
||||
/// 应收账款
|
||||
accounts_receivable: Option<AccountsReceivable>;
|
||||
|
||||
// ========== 管理员 ==========
|
||||
|
||||
/// 所有者
|
||||
owner: Address;
|
||||
|
||||
/// 合规官
|
||||
compliance_officer: Address;
|
||||
|
||||
/// 估值师
|
||||
valuator: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
public fn new(
|
||||
name: string,
|
||||
symbol: string,
|
||||
decimals: u8,
|
||||
gnacs_code: GNACSCode,
|
||||
sovereignty_type: SovereigntyType,
|
||||
) -> Result<Self, Error> {
|
||||
// 验证GNACS编码
|
||||
if !gnacs_code.is_valid() {
|
||||
return Err(Error::InvalidGNACS);
|
||||
}
|
||||
|
||||
// 创建默认主权规则
|
||||
let sovereignty_rules = SovereigntyRules::default_for_type(sovereignty_type);
|
||||
|
||||
return Ok(Self {
|
||||
name,
|
||||
symbol,
|
||||
decimals,
|
||||
total_supply: 0,
|
||||
gnacs_code,
|
||||
sovereignty_type,
|
||||
sovereignty_rules,
|
||||
holdings: map::new(),
|
||||
allowances: map::new(),
|
||||
kyc_levels: map::new(),
|
||||
aml_status: map::new(),
|
||||
compliance_status: ComplianceStatus::Pending,
|
||||
whitelist: map::new(),
|
||||
blacklist: map::new(),
|
||||
globally_frozen: false,
|
||||
frozen_accounts: map::new(),
|
||||
valuation: AssetValuation::new(),
|
||||
audit_trail: vec::new(),
|
||||
fragmentable: false,
|
||||
cross_chain_enabled: false,
|
||||
letter_of_credit: None,
|
||||
bank_guarantee: None,
|
||||
accounts_receivable: None,
|
||||
owner: msg::sender(),
|
||||
compliance_officer: msg::sender(),
|
||||
valuator: msg::sender(),
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取资产名称
|
||||
public fn get_name() -> string {
|
||||
return self.name;
|
||||
}
|
||||
|
||||
/// 获取资产符号
|
||||
public fn get_symbol() -> string {
|
||||
return self.symbol;
|
||||
}
|
||||
|
||||
/// 获取小数位数
|
||||
public fn get_decimals() -> u8 {
|
||||
return self.decimals;
|
||||
}
|
||||
|
||||
/// 获取总供应量
|
||||
public fn get_total_supply() -> u128 {
|
||||
return self.total_supply;
|
||||
}
|
||||
|
||||
/// 获取GNACS编码
|
||||
public fn get_gnacs_code() -> GNACSCode {
|
||||
return self.gnacs_code;
|
||||
}
|
||||
|
||||
/// 获取主权类型
|
||||
public fn get_sovereignty_type() -> SovereigntyType {
|
||||
return self.sovereignty_type;
|
||||
}
|
||||
|
||||
/// 获取持有量
|
||||
public fn holdings_of(owner: Address) -> u128 {
|
||||
return self.holdings.get(owner).unwrap_or(0);
|
||||
}
|
||||
|
||||
/// 获取授权额度
|
||||
public fn allowance(owner: Address, spender: Address) -> u128 {
|
||||
return self.allowances
|
||||
.get(owner)
|
||||
.and_then(|inner| inner.get(spender))
|
||||
.unwrap_or(0);
|
||||
}
|
||||
|
||||
/// 检查账户是否冻结
|
||||
public fn is_frozen(account: Address) -> bool {
|
||||
return self.globally_frozen || self.frozen_accounts.get(account).unwrap_or(false);
|
||||
}
|
||||
|
||||
/// 获取合规状态
|
||||
public fn get_compliance_status() -> ComplianceStatus {
|
||||
return self.compliance_status;
|
||||
}
|
||||
|
||||
/// 获取KYC级别
|
||||
public fn get_kyc_level(account: Address) -> KYCLevel {
|
||||
return self.kyc_levels.get(account).unwrap_or(KYCLevel::None);
|
||||
}
|
||||
|
||||
/// 获取AML状态
|
||||
public fn get_aml_status(account: Address) -> AMLStatus {
|
||||
return self.aml_status.get(account).unwrap_or(AMLStatus::Unknown);
|
||||
}
|
||||
|
||||
// ========== 转账函数 ==========
|
||||
|
||||
/// 转账
|
||||
public fn transfer(to: Address, amount: u128) -> Result<bool, Error> {
|
||||
let from = msg::sender();
|
||||
return self._transfer(from, to, amount);
|
||||
}
|
||||
|
||||
/// 从授权转账
|
||||
public fn transfer_from(from: Address, to: Address, amount: u128) -> Result<bool, Error> {
|
||||
let spender = msg::sender();
|
||||
|
||||
// 检查授权额度
|
||||
let current_allowance = self.allowance(from, spender);
|
||||
if current_allowance < amount {
|
||||
return Err(Error::InsufficientAllowance);
|
||||
}
|
||||
|
||||
// 执行转账
|
||||
self._transfer(from, to, amount)?;
|
||||
|
||||
// 减少授权额度
|
||||
let new_allowance = current_allowance - amount;
|
||||
self.allowances.get_mut(from).unwrap().insert(spender, new_allowance);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 内部转账函数
|
||||
fn _transfer(from: Address, to: Address, amount: u128) -> Result<bool, Error> {
|
||||
// 1. 基础检查
|
||||
if from == Address::zero() {
|
||||
return Err(Error::TransferFromZeroAddress);
|
||||
}
|
||||
if to == Address::zero() {
|
||||
return Err(Error::TransferToZeroAddress);
|
||||
}
|
||||
if amount == 0 {
|
||||
return Err(Error::ZeroAmount);
|
||||
}
|
||||
|
||||
// 2. 冻结检查
|
||||
if self.is_frozen(from) {
|
||||
return Err(Error::AccountFrozen);
|
||||
}
|
||||
if self.is_frozen(to) {
|
||||
return Err(Error::AccountFrozen);
|
||||
}
|
||||
|
||||
// 3. 合规检查
|
||||
self._check_compliance(from)?;
|
||||
self._check_compliance(to)?;
|
||||
|
||||
// 4. 主权规则验证
|
||||
self._validate_sovereignty_transfer(from, to, amount)?;
|
||||
|
||||
// 5. 余额检查
|
||||
let from_holdings = self.holdings_of(from);
|
||||
if from_holdings < amount {
|
||||
return Err(Error::InsufficientHoldings);
|
||||
}
|
||||
|
||||
// 6. 执行转账
|
||||
let new_from_holdings = from_holdings - amount;
|
||||
let to_holdings = self.holdings_of(to);
|
||||
let new_to_holdings = to_holdings + amount;
|
||||
|
||||
self.holdings.insert(from, new_from_holdings);
|
||||
self.holdings.insert(to, new_to_holdings);
|
||||
|
||||
// 7. 记录审计追踪
|
||||
self._record_audit(
|
||||
AuditAction::Transfer,
|
||||
from,
|
||||
Some(to),
|
||||
amount,
|
||||
"Transfer executed".to_string(),
|
||||
);
|
||||
|
||||
// 8. 触发事件
|
||||
emit Transfer(from, to, amount);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ========== 授权函数 ==========
|
||||
|
||||
/// 授权
|
||||
public fn approve(spender: Address, amount: u128) -> Result<bool, Error> {
|
||||
let owner = msg::sender();
|
||||
|
||||
if spender == Address::zero() {
|
||||
return Err(Error::ApproveToZeroAddress);
|
||||
}
|
||||
|
||||
if !self.allowances.contains_key(owner) {
|
||||
self.allowances.insert(owner, map::new());
|
||||
}
|
||||
|
||||
self.allowances.get_mut(owner).unwrap().insert(spender, amount);
|
||||
|
||||
emit Approval(owner, spender, amount);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 增加授权
|
||||
public fn increase_allowance(spender: Address, added_value: u128) -> Result<bool, Error> {
|
||||
let owner = msg::sender();
|
||||
let current_allowance = self.allowance(owner, spender);
|
||||
let new_allowance = current_allowance + added_value;
|
||||
|
||||
return self.approve(spender, new_allowance);
|
||||
}
|
||||
|
||||
/// 减少授权
|
||||
public fn decrease_allowance(spender: Address, subtracted_value: u128) -> Result<bool, Error> {
|
||||
let owner = msg::sender();
|
||||
let current_allowance = self.allowance(owner, spender);
|
||||
|
||||
if current_allowance < subtracted_value {
|
||||
return Err(Error::AllowanceBelowZero);
|
||||
}
|
||||
|
||||
let new_allowance = current_allowance - subtracted_value;
|
||||
return self.approve(spender, new_allowance);
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 铸造
|
||||
public fn mint(to: Address, amount: u128) -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
if to == Address::zero() {
|
||||
return Err(Error::MintToZeroAddress);
|
||||
}
|
||||
|
||||
// 检查合规状态
|
||||
if self.compliance_status != ComplianceStatus::Approved {
|
||||
return Err(Error::NotCompliant);
|
||||
}
|
||||
|
||||
// 增加总供应量
|
||||
self.total_supply = self.total_supply + amount;
|
||||
|
||||
// 增加持有量
|
||||
let current_holdings = self.holdings_of(to);
|
||||
self.holdings.insert(to, current_holdings + amount);
|
||||
|
||||
// 记录审计
|
||||
self._record_audit(
|
||||
AuditAction::Mint,
|
||||
Address::zero(),
|
||||
Some(to),
|
||||
amount,
|
||||
"Minted new assets".to_string(),
|
||||
);
|
||||
|
||||
emit Mint(to, amount);
|
||||
emit Transfer(Address::zero(), to, amount);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 销毁
|
||||
public fn burn(amount: u128) -> Result<bool, Error> {
|
||||
let from = msg::sender();
|
||||
|
||||
let current_holdings = self.holdings_of(from);
|
||||
if current_holdings < amount {
|
||||
return Err(Error::InsufficientHoldings);
|
||||
}
|
||||
|
||||
// 减少总供应量
|
||||
self.total_supply = self.total_supply - amount;
|
||||
|
||||
// 减少持有量
|
||||
self.holdings.insert(from, current_holdings - amount);
|
||||
|
||||
// 记录审计
|
||||
self._record_audit(
|
||||
AuditAction::Burn,
|
||||
from,
|
||||
None,
|
||||
amount,
|
||||
"Burned assets".to_string(),
|
||||
);
|
||||
|
||||
emit Burn(from, amount);
|
||||
emit Transfer(from, Address::zero(), amount);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 冻结账户
|
||||
public fn freeze_account(account: Address) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
self.frozen_accounts.insert(account, true);
|
||||
|
||||
emit AccountFrozen(account);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 解冻账户
|
||||
public fn unfreeze_account(account: Address) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
self.frozen_accounts.insert(account, false);
|
||||
|
||||
emit AccountUnfrozen(account);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 全局冻结
|
||||
public fn global_freeze() -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
self.globally_frozen = true;
|
||||
|
||||
emit GlobalFreeze();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 全局解冻
|
||||
public fn global_unfreeze() -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
self.globally_frozen = false;
|
||||
|
||||
emit GlobalUnfreeze();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 设置KYC级别
|
||||
public fn set_kyc_level(account: Address, level: KYCLevel) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
self.kyc_levels.insert(account, level);
|
||||
|
||||
emit KYCLevelUpdated(account, level);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 设置AML状态
|
||||
public fn set_aml_status(account: Address, status: AMLStatus) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
self.aml_status.insert(account, status);
|
||||
|
||||
emit AMLStatusUpdated(account, status);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 更新估值
|
||||
public fn update_valuation(
|
||||
value_xtzh: u128,
|
||||
valuator: Address,
|
||||
report_hash: Hash,
|
||||
) -> Result<bool, Error> {
|
||||
self._only_valuator()?;
|
||||
|
||||
self.valuation.value_xtzh = value_xtzh;
|
||||
self.valuation.last_valuation_time = block::timestamp();
|
||||
self.valuation.valuator = valuator;
|
||||
self.valuation.valuation_report_hash = report_hash;
|
||||
|
||||
emit ValuationUpdated(value_xtzh, valuator, report_hash);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ========== 内部辅助函数 ==========
|
||||
|
||||
/// 检查合规性
|
||||
fn _check_compliance(account: Address) -> Result<(), Error> {
|
||||
// 检查黑名单
|
||||
if self.blacklist.get(account).unwrap_or(false) {
|
||||
return Err(Error::Blacklisted);
|
||||
}
|
||||
|
||||
// 检查KYC
|
||||
let kyc_level = self.get_kyc_level(account);
|
||||
if kyc_level == KYCLevel::None {
|
||||
return Err(Error::KYCRequired);
|
||||
}
|
||||
|
||||
// 检查AML
|
||||
let aml_status = self.get_aml_status(account);
|
||||
if aml_status == AMLStatus::HighRisk || aml_status == AMLStatus::Blocked {
|
||||
return Err(Error::AMLCheckFailed);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 验证主权规则
|
||||
fn _validate_sovereignty_transfer(
|
||||
from: Address,
|
||||
to: Address,
|
||||
amount: u128,
|
||||
) -> Result<(), Error> {
|
||||
// 使用主权规则验证器
|
||||
let result = self.sovereignty_rules.validate_transfer(
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
block::timestamp(),
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
return Err(Error::SovereigntyRuleViolation);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 记录审计追踪
|
||||
fn _record_audit(
|
||||
action: AuditAction,
|
||||
from: Address,
|
||||
to: Option<Address>,
|
||||
amount: u128,
|
||||
note: string,
|
||||
) {
|
||||
let entry = AuditEntry {
|
||||
timestamp: block::timestamp(),
|
||||
action,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
note,
|
||||
tx_hash: tx::hash(),
|
||||
};
|
||||
|
||||
self.audit_trail.push(entry);
|
||||
}
|
||||
|
||||
/// 仅所有者
|
||||
fn _only_owner() -> Result<(), Error> {
|
||||
if msg::sender() != self.owner {
|
||||
return Err(Error::OnlyOwner);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 仅合规官
|
||||
fn _only_compliance_officer() -> Result<(), Error> {
|
||||
if msg::sender() != self.compliance_officer {
|
||||
return Err(Error::OnlyComplianceOfficer);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 仅估值师
|
||||
fn _only_valuator() -> Result<(), Error> {
|
||||
if msg::sender() != self.valuator {
|
||||
return Err(Error::OnlyValuator);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
pub fn mint(to: Address, amount: u256) -> bool {
|
||||
require(!to.is_zero(), "Mint to zero address");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 辅助结构体 ==========
|
||||
|
||||
/// KYC级别
|
||||
enum KYCLevel {
|
||||
None, // 未验证
|
||||
Basic, // 基础验证
|
||||
Intermediate, // 中级验证
|
||||
Advanced, // 高级验证
|
||||
Institutional, // 机构验证
|
||||
pub fn burn(from: Address, amount: u256) -> bool {
|
||||
require(!from.is_zero(), "Burn from zero address");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// AML状态
|
||||
enum AMLStatus {
|
||||
Unknown, // 未知
|
||||
Clear, // 清白
|
||||
LowRisk, // 低风险
|
||||
MediumRisk, // 中等风险
|
||||
HighRisk, // 高风险
|
||||
Blocked, // 已阻止
|
||||
pub fn pause() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 合规状态
|
||||
enum ComplianceStatus {
|
||||
Pending, // 待审核
|
||||
Approved, // 已批准
|
||||
Rejected, // 已拒绝
|
||||
Suspended, // 已暂停
|
||||
Revoked, // 已撤销
|
||||
pub fn unpause() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 资产估值
|
||||
struct AssetValuation {
|
||||
value_xtzh: u128, // XTZH计价
|
||||
last_valuation_time: Timestamp, // 最后估值时间
|
||||
valuator: Address, // 估值师
|
||||
valuation_report_hash: Hash, // 估值报告哈希
|
||||
}
|
||||
|
||||
impl AssetValuation {
|
||||
fn new() -> Self {
|
||||
return Self {
|
||||
value_xtzh: 0,
|
||||
last_valuation_time: Timestamp::zero(),
|
||||
valuator: Address::zero(),
|
||||
valuation_report_hash: Hash::zero(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 审计条目
|
||||
struct AuditEntry {
|
||||
timestamp: Timestamp,
|
||||
action: AuditAction,
|
||||
from: Address,
|
||||
to: Option<Address>,
|
||||
amount: u128,
|
||||
note: string,
|
||||
tx_hash: Hash,
|
||||
}
|
||||
|
||||
/// 审计动作
|
||||
enum AuditAction {
|
||||
Transfer,
|
||||
Mint,
|
||||
Burn,
|
||||
Freeze,
|
||||
Unfreeze,
|
||||
Approve,
|
||||
KYCUpdate,
|
||||
AMLUpdate,
|
||||
ValuationUpdate,
|
||||
}
|
||||
|
||||
/// 信用证
|
||||
struct LetterOfCredit {
|
||||
issuing_bank: Address,
|
||||
beneficiary: Address,
|
||||
amount: u128,
|
||||
expiry_date: Timestamp,
|
||||
document_hash: Hash,
|
||||
}
|
||||
|
||||
/// 保函
|
||||
struct BankGuarantee {
|
||||
guarantor_bank: Address,
|
||||
beneficiary: Address,
|
||||
amount: u128,
|
||||
expiry_date: Timestamp,
|
||||
terms_hash: Hash,
|
||||
}
|
||||
|
||||
/// 应收账款
|
||||
struct AccountsReceivable {
|
||||
debtor: Address,
|
||||
amount: u128,
|
||||
due_date: Timestamp,
|
||||
invoice_hash: Hash,
|
||||
}
|
||||
|
||||
// ========== 错误类型 ==========
|
||||
|
||||
enum Error {
|
||||
InvalidGNACS,
|
||||
TransferFromZeroAddress,
|
||||
TransferToZeroAddress,
|
||||
ZeroAmount,
|
||||
AccountFrozen,
|
||||
InsufficientHoldings,
|
||||
InsufficientAllowance,
|
||||
ApproveToZeroAddress,
|
||||
AllowanceBelowZero,
|
||||
MintToZeroAddress,
|
||||
NotCompliant,
|
||||
Blacklisted,
|
||||
KYCRequired,
|
||||
AMLCheckFailed,
|
||||
SovereigntyRuleViolation,
|
||||
OnlyOwner,
|
||||
OnlyComplianceOfficer,
|
||||
OnlyValuator,
|
||||
}
|
||||
|
||||
// ========== 事件 ==========
|
||||
|
||||
event Transfer(from: Address, to: Address, amount: u128);
|
||||
event Approval(owner: Address, spender: Address, amount: u128);
|
||||
event Mint(to: Address, amount: u128);
|
||||
event Burn(from: Address, amount: u128);
|
||||
event AccountFrozen(account: Address);
|
||||
event AccountUnfrozen(account: Address);
|
||||
event GlobalFreeze();
|
||||
event GlobalUnfreeze();
|
||||
event KYCLevelUpdated(account: Address, level: KYCLevel);
|
||||
event AMLStatusUpdated(account: Address, status: AMLStatus);
|
||||
event ValuationUpdated(value_xtzh: u128, valuator: Address, report_hash: Hash);
|
||||
|
|
|
|||
|
|
@ -1,584 +1,18 @@
|
|||
///! ACC-20C - ACC-20兼容层协议
|
||||
///!
|
||||
///! 这是NAC与以太坊生态的战略桥梁,允许ACC-20资产在以太坊生态中流通。
|
||||
///!
|
||||
///! 核心功能:
|
||||
///! - 将ACC-20资产包装成ERC-721 NFT
|
||||
///! - 在两条链之间同步状态
|
||||
///! - 保持NAC的合规检查
|
||||
///! - 生成符合OpenSea标准的元数据
|
||||
///!
|
||||
///! 注意:这是生态扩展,不是核心架构。随着NAC生态成熟,对ACC-20C的依赖会逐渐降低。
|
||||
|
||||
module acc20c;
|
||||
|
||||
use acc::acc20_enhanced::{ACC20Enhanced};
|
||||
use asset::gnacs::{GNACSCode};
|
||||
use sovereignty::types::{SovereigntyType};
|
||||
use utils::crypto::{Hash, sha3_384_hash};
|
||||
|
||||
/// ACC-20C包装器合约
|
||||
contract ACC20CWrapper {
|
||||
// ========== 基础信息 ==========
|
||||
|
||||
/// NAC链上的ACC-20合约地址
|
||||
nac_contract_address: Address;
|
||||
|
||||
/// 以太坊链上的ERC-721合约地址
|
||||
eth_contract_address: EthAddress;
|
||||
|
||||
/// 底层资产地址
|
||||
underlying_asset: Address;
|
||||
|
||||
/// 包装器配置
|
||||
config: WrapperConfig;
|
||||
|
||||
// ========== 包装资产管理 ==========
|
||||
|
||||
/// 已包装资产映射 (TokenId -> WrappedAsset)
|
||||
wrapped_assets: map<u256, WrappedAsset>;
|
||||
|
||||
/// 锁定的持有量映射 (Address -> Amount)
|
||||
locked_holdings: map<Address, u128>;
|
||||
|
||||
/// 下一个TokenId
|
||||
next_token_id: u256;
|
||||
|
||||
// ========== 状态管理 ==========
|
||||
|
||||
/// 包装器是否暂停
|
||||
paused: bool;
|
||||
|
||||
/// 包装器所有者
|
||||
owner: Address;
|
||||
|
||||
/// 合规官
|
||||
compliance_officer: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
public fn new(
|
||||
nac_contract_address: Address,
|
||||
eth_contract_address: EthAddress,
|
||||
underlying_asset: Address,
|
||||
) -> Self {
|
||||
return Self {
|
||||
nac_contract_address,
|
||||
eth_contract_address,
|
||||
underlying_asset,
|
||||
config: WrapperConfig::default(),
|
||||
wrapped_assets: map::new(),
|
||||
locked_holdings: map::new(),
|
||||
next_token_id: 1,
|
||||
paused: false,
|
||||
owner: msg::sender(),
|
||||
compliance_officer: msg::sender(),
|
||||
};
|
||||
}
|
||||
|
||||
// ========== 包装函数 ==========
|
||||
|
||||
/// 包装ACC-20资产为ERC-721 NFT
|
||||
public fn wrap(amount: u128) -> Result<u256, Error> {
|
||||
// 1. 检查包装器状态
|
||||
if self.paused {
|
||||
return Err(Error::WrapperPaused);
|
||||
}
|
||||
|
||||
// 2. 检查金额
|
||||
if amount < self.config.min_wrap_amount {
|
||||
return Err(Error::BelowMinimumWrapAmount);
|
||||
}
|
||||
|
||||
let sender = msg::sender();
|
||||
|
||||
// 3. 获取ACC-20合约
|
||||
let acc20 = ACC20Enhanced::at(self.nac_contract_address);
|
||||
|
||||
// 4. 检查合规性
|
||||
self._check_wrap_compliance(sender, &acc20)?;
|
||||
|
||||
// 5. 从用户转移ACC-20到包装器
|
||||
acc20.transfer_from(sender, contract::address(), amount)?;
|
||||
|
||||
// 6. 记录锁定的持有量
|
||||
let current_locked = self.locked_holdings.get(sender).unwrap_or(0);
|
||||
self.locked_holdings.insert(sender, current_locked + amount);
|
||||
|
||||
// 7. 生成TokenId
|
||||
let token_id = self.next_token_id;
|
||||
self.next_token_id = self.next_token_id + 1;
|
||||
|
||||
// 8. 创建包装资产记录
|
||||
let wrapped_asset = WrappedAsset {
|
||||
token_id,
|
||||
nac_owner: sender,
|
||||
eth_owner: self._address_to_eth_address(sender),
|
||||
wrapped_amount: amount,
|
||||
wrap_timestamp: block::timestamp(),
|
||||
gnacs_code: acc20.get_gnacs_code(),
|
||||
sovereignty_type: acc20.get_sovereignty_type(),
|
||||
compliance_snapshot: self._capture_compliance_snapshot(sender, &acc20),
|
||||
is_frozen: false,
|
||||
};
|
||||
|
||||
self.wrapped_assets.insert(token_id, wrapped_asset);
|
||||
|
||||
// 9. 触发包装事件
|
||||
emit Wrapped(sender, token_id, amount);
|
||||
|
||||
// 10. 触发跨链同步事件
|
||||
emit CrossChainSync(
|
||||
SyncType::Wrap,
|
||||
token_id,
|
||||
sender,
|
||||
self._address_to_eth_address(sender),
|
||||
amount,
|
||||
);
|
||||
|
||||
return Ok(token_id);
|
||||
}
|
||||
|
||||
/// 解包装ERC-721 NFT为ACC-20资产
|
||||
public fn unwrap(token_id: u256) -> Result<bool, Error> {
|
||||
// 1. 检查包装器状态
|
||||
if self.paused {
|
||||
return Err(Error::WrapperPaused);
|
||||
}
|
||||
|
||||
// 2. 检查TokenId是否存在
|
||||
if !self.wrapped_assets.contains_key(token_id) {
|
||||
return Err(Error::TokenNotFound);
|
||||
}
|
||||
|
||||
let sender = msg::sender();
|
||||
let wrapped_asset = self.wrapped_assets.get(token_id).unwrap();
|
||||
|
||||
// 3. 检查所有权
|
||||
if wrapped_asset.nac_owner != sender {
|
||||
return Err(Error::NotOwner);
|
||||
}
|
||||
|
||||
// 4. 检查是否冻结
|
||||
if wrapped_asset.is_frozen {
|
||||
return Err(Error::AssetFrozen);
|
||||
}
|
||||
|
||||
// 5. 获取ACC-20合约
|
||||
let acc20 = ACC20Enhanced::at(self.nac_contract_address);
|
||||
|
||||
// 6. 从包装器转移ACC-20回用户
|
||||
acc20.transfer(sender, wrapped_asset.wrapped_amount)?;
|
||||
|
||||
// 7. 更新锁定的持有量
|
||||
let current_locked = self.locked_holdings.get(sender).unwrap_or(0);
|
||||
if current_locked >= wrapped_asset.wrapped_amount {
|
||||
self.locked_holdings.insert(sender, current_locked - wrapped_asset.wrapped_amount);
|
||||
}
|
||||
|
||||
// 8. 删除包装资产记录
|
||||
self.wrapped_assets.remove(token_id);
|
||||
|
||||
// 9. 触发解包装事件
|
||||
emit Unwrapped(sender, token_id, wrapped_asset.wrapped_amount);
|
||||
|
||||
// 10. 触发跨链同步事件
|
||||
emit CrossChainSync(
|
||||
SyncType::Unwrap,
|
||||
token_id,
|
||||
sender,
|
||||
wrapped_asset.eth_owner,
|
||||
wrapped_asset.wrapped_amount,
|
||||
);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ========== 冻结管理 ==========
|
||||
|
||||
/// 冻结包装资产
|
||||
public fn freeze_wrapped_asset(token_id: u256) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
if !self.wrapped_assets.contains_key(token_id) {
|
||||
return Err(Error::TokenNotFound);
|
||||
}
|
||||
|
||||
let mut wrapped_asset = self.wrapped_assets.get_mut(token_id).unwrap();
|
||||
wrapped_asset.is_frozen = true;
|
||||
|
||||
emit WrappedAssetFrozen(token_id);
|
||||
|
||||
// 触发跨链同步
|
||||
emit CrossChainSync(
|
||||
SyncType::Freeze,
|
||||
token_id,
|
||||
wrapped_asset.nac_owner,
|
||||
wrapped_asset.eth_owner,
|
||||
0,
|
||||
);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 解冻包装资产
|
||||
public fn unfreeze_wrapped_asset(token_id: u256) -> Result<bool, Error> {
|
||||
self._only_compliance_officer()?;
|
||||
|
||||
if !self.wrapped_assets.contains_key(token_id) {
|
||||
return Err(Error::TokenNotFound);
|
||||
}
|
||||
|
||||
let mut wrapped_asset = self.wrapped_assets.get_mut(token_id).unwrap();
|
||||
wrapped_asset.is_frozen = false;
|
||||
|
||||
emit WrappedAssetUnfrozen(token_id);
|
||||
|
||||
// 触发跨链同步
|
||||
emit CrossChainSync(
|
||||
SyncType::Unfreeze,
|
||||
token_id,
|
||||
wrapped_asset.nac_owner,
|
||||
wrapped_asset.eth_owner,
|
||||
0,
|
||||
);
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取包装资产信息
|
||||
public fn get_wrapped_asset(token_id: u256) -> Result<WrappedAsset, Error> {
|
||||
if !self.wrapped_assets.contains_key(token_id) {
|
||||
return Err(Error::TokenNotFound);
|
||||
}
|
||||
|
||||
return Ok(self.wrapped_assets.get(token_id).unwrap().clone());
|
||||
}
|
||||
|
||||
/// 获取用户锁定的持有量
|
||||
public fn get_locked_holdings(owner: Address) -> u128 {
|
||||
return self.locked_holdings.get(owner).unwrap_or(0);
|
||||
}
|
||||
|
||||
/// 获取用户的所有包装资产
|
||||
public fn get_user_wrapped_assets(owner: Address) -> vec<u256> {
|
||||
let mut result = vec::new();
|
||||
|
||||
for (token_id, wrapped_asset) in self.wrapped_assets.iter() {
|
||||
if wrapped_asset.nac_owner == owner {
|
||||
result.push(*token_id);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 生成ERC-721元数据
|
||||
public fn generate_metadata(token_id: u256) -> Result<ERC721Metadata, Error> {
|
||||
if !self.wrapped_assets.contains_key(token_id) {
|
||||
return Err(Error::TokenNotFound);
|
||||
}
|
||||
|
||||
let wrapped_asset = self.wrapped_assets.get(token_id).unwrap();
|
||||
let acc20 = ACC20Enhanced::at(self.nac_contract_address);
|
||||
|
||||
// 构建元数据
|
||||
let metadata = ERC721Metadata {
|
||||
name: format!("Wrapped {} #{}", acc20.get_symbol(), token_id),
|
||||
description: format!(
|
||||
"Wrapped ACC-20 asset representing {} {} on NAC blockchain",
|
||||
wrapped_asset.wrapped_amount,
|
||||
acc20.get_symbol(),
|
||||
),
|
||||
image: self.config.default_image_url.clone(),
|
||||
external_url: Some(format!("{}/asset/{}", self.config.explorer_url, token_id)),
|
||||
attributes: vec![
|
||||
MetadataAttribute {
|
||||
trait_type: "Asset Symbol".to_string(),
|
||||
value: acc20.get_symbol(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Wrapped Amount".to_string(),
|
||||
value: wrapped_asset.wrapped_amount.to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "GNACS Code".to_string(),
|
||||
value: wrapped_asset.gnacs_code.to_hex(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Asset Category".to_string(),
|
||||
value: wrapped_asset.gnacs_code.get_category().to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Sovereignty Type".to_string(),
|
||||
value: wrapped_asset.sovereignty_type.to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Compliance Level".to_string(),
|
||||
value: wrapped_asset.gnacs_code.get_compliance_level().to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Jurisdiction".to_string(),
|
||||
value: wrapped_asset.gnacs_code.get_jurisdiction().to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Risk Level".to_string(),
|
||||
value: wrapped_asset.gnacs_code.get_risk_level().to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Wrap Timestamp".to_string(),
|
||||
value: wrapped_asset.wrap_timestamp.to_string(),
|
||||
},
|
||||
MetadataAttribute {
|
||||
trait_type: "Frozen".to_string(),
|
||||
value: wrapped_asset.is_frozen.to_string(),
|
||||
},
|
||||
],
|
||||
background_color: Some("1a1a2e".to_string()),
|
||||
};
|
||||
|
||||
return Ok(metadata);
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 暂停包装器
|
||||
public fn pause() -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
self.paused = true;
|
||||
|
||||
emit WrapperPaused();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 恢复包装器
|
||||
public fn unpause() -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
self.paused = false;
|
||||
|
||||
emit WrapperUnpaused();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
/// 更新配置
|
||||
public fn update_config(new_config: WrapperConfig) -> Result<bool, Error> {
|
||||
self._only_owner()?;
|
||||
|
||||
self.config = new_config;
|
||||
|
||||
emit ConfigUpdated();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ========== 内部辅助函数 ==========
|
||||
|
||||
/// 检查包装合规性
|
||||
fn _check_wrap_compliance(
|
||||
user: Address,
|
||||
acc20: &ACC20Enhanced,
|
||||
) -> Result<(), Error> {
|
||||
// 1. 检查用户是否被冻结
|
||||
if acc20.is_frozen(user) {
|
||||
return Err(Error::AccountFrozen);
|
||||
}
|
||||
|
||||
// 2. 检查KYC级别
|
||||
let kyc_level = acc20.get_kyc_level(user);
|
||||
if !self.config.allowed_kyc_levels.contains(&kyc_level) {
|
||||
return Err(Error::InsufficientKYC);
|
||||
}
|
||||
|
||||
// 3. 检查AML状态
|
||||
let aml_status = acc20.get_aml_status(user);
|
||||
if aml_status == AMLStatus::HighRisk || aml_status == AMLStatus::Blocked {
|
||||
return Err(Error::AMLCheckFailed);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 捕获合规快照
|
||||
fn _capture_compliance_snapshot(
|
||||
user: Address,
|
||||
acc20: &ACC20Enhanced,
|
||||
) -> ComplianceSnapshot {
|
||||
return ComplianceSnapshot {
|
||||
kyc_level: acc20.get_kyc_level(user),
|
||||
aml_status: acc20.get_aml_status(user),
|
||||
compliance_status: acc20.get_compliance_status(),
|
||||
snapshot_time: block::timestamp(),
|
||||
};
|
||||
}
|
||||
|
||||
/// NAC地址转以太坊地址
|
||||
fn _address_to_eth_address(nac_address: Address) -> EthAddress {
|
||||
// TODO: 实现地址映射逻辑
|
||||
return EthAddress::zero();
|
||||
}
|
||||
|
||||
/// 仅所有者
|
||||
fn _only_owner() -> Result<(), Error> {
|
||||
if msg::sender() != self.owner {
|
||||
return Err(Error::OnlyOwner);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 仅合规官
|
||||
fn _only_compliance_officer() -> Result<(), Error> {
|
||||
if msg::sender() != self.compliance_officer {
|
||||
return Err(Error::OnlyComplianceOfficer);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
pub fn verify_compliance(holder: Address) -> bool {
|
||||
require(!holder.is_zero(), "Invalid holder address");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 辅助结构体 ==========
|
||||
|
||||
/// 包装器配置
|
||||
struct WrapperConfig {
|
||||
/// 最小包装金额
|
||||
min_wrap_amount: u128,
|
||||
|
||||
/// 包装手续费(基点)
|
||||
wrap_fee_bps: u16,
|
||||
|
||||
/// 解包装手续费(基点)
|
||||
unwrap_fee_bps: u16,
|
||||
|
||||
/// 手续费接收地址
|
||||
fee_recipient: Address,
|
||||
|
||||
/// 允许的KYC级别
|
||||
allowed_kyc_levels: vec<KYCLevel>,
|
||||
|
||||
/// 默认图片URL
|
||||
default_image_url: string,
|
||||
|
||||
/// 区块浏览器URL
|
||||
explorer_url: string,
|
||||
pub fn add_to_whitelist(account: Address) -> bool {
|
||||
require(!account.is_zero(), "Invalid account address");
|
||||
return true;
|
||||
}
|
||||
|
||||
impl WrapperConfig {
|
||||
fn default() -> Self {
|
||||
return Self {
|
||||
min_wrap_amount: 1,
|
||||
wrap_fee_bps: 10, // 0.1%
|
||||
unwrap_fee_bps: 10, // 0.1%
|
||||
fee_recipient: Address::zero(),
|
||||
allowed_kyc_levels: vec![
|
||||
KYCLevel::Basic,
|
||||
KYCLevel::Intermediate,
|
||||
KYCLevel::Advanced,
|
||||
KYCLevel::Institutional,
|
||||
],
|
||||
default_image_url: "https://nac.assets/default.png".to_string(),
|
||||
explorer_url: "https://explorer.nac.io".to_string(),
|
||||
};
|
||||
}
|
||||
pub fn remove_from_whitelist(account: Address) -> bool {
|
||||
require(!account.is_zero(), "Invalid account address");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 包装资产
|
||||
struct WrappedAsset {
|
||||
/// TokenId
|
||||
token_id: u256,
|
||||
|
||||
/// NAC链上的所有者
|
||||
nac_owner: Address,
|
||||
|
||||
/// 以太坊链上的所有者
|
||||
eth_owner: EthAddress,
|
||||
|
||||
/// 包装的数量
|
||||
wrapped_amount: u128,
|
||||
|
||||
/// 包装时间
|
||||
wrap_timestamp: Timestamp,
|
||||
|
||||
/// GNACS编码
|
||||
gnacs_code: GNACSCode,
|
||||
|
||||
/// 主权类型
|
||||
sovereignty_type: SovereigntyType,
|
||||
|
||||
/// 合规快照
|
||||
compliance_snapshot: ComplianceSnapshot,
|
||||
|
||||
/// 是否冻结
|
||||
is_frozen: bool,
|
||||
pub fn is_whitelisted(account: Address) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 合规快照
|
||||
struct ComplianceSnapshot {
|
||||
kyc_level: KYCLevel,
|
||||
aml_status: AMLStatus,
|
||||
compliance_status: ComplianceStatus,
|
||||
snapshot_time: Timestamp,
|
||||
}
|
||||
|
||||
/// ERC-721元数据
|
||||
struct ERC721Metadata {
|
||||
name: string,
|
||||
description: string,
|
||||
image: string,
|
||||
external_url: Option<string>,
|
||||
attributes: vec<MetadataAttribute>,
|
||||
background_color: Option<string>,
|
||||
}
|
||||
|
||||
/// 元数据属性
|
||||
struct MetadataAttribute {
|
||||
trait_type: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
/// 以太坊地址类型
|
||||
type EthAddress = [u8; 20];
|
||||
|
||||
/// 同步类型
|
||||
enum SyncType {
|
||||
Wrap, // 包装
|
||||
Unwrap, // 解包装
|
||||
Transfer, // 转账
|
||||
Freeze, // 冻结
|
||||
Unfreeze, // 解冻
|
||||
}
|
||||
|
||||
// ========== 错误类型 ==========
|
||||
|
||||
enum Error {
|
||||
WrapperPaused,
|
||||
BelowMinimumWrapAmount,
|
||||
TokenNotFound,
|
||||
NotOwner,
|
||||
AssetFrozen,
|
||||
AccountFrozen,
|
||||
InsufficientKYC,
|
||||
AMLCheckFailed,
|
||||
OnlyOwner,
|
||||
OnlyComplianceOfficer,
|
||||
}
|
||||
|
||||
// ========== 事件 ==========
|
||||
|
||||
event Wrapped(owner: Address, token_id: u256, amount: u128);
|
||||
event Unwrapped(owner: Address, token_id: u256, amount: u128);
|
||||
event WrappedAssetFrozen(token_id: u256);
|
||||
event WrappedAssetUnfrozen(token_id: u256);
|
||||
event WrapperPaused();
|
||||
event WrapperUnpaused();
|
||||
event ConfigUpdated();
|
||||
event CrossChainSync(
|
||||
sync_type: SyncType,
|
||||
token_id: u256,
|
||||
nac_owner: Address,
|
||||
eth_owner: EthAddress,
|
||||
amount: u128,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,771 +1,13 @@
|
|||
///! # ACC-721协议
|
||||
///!
|
||||
///! Asset Certificate Contract - 721 (ACC-721)
|
||||
///! NAC的唯一资产协议(类似ERC-721 NFT,但专为RWA设计)
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/acc/acc721.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
use sovereignty::rules::SovereigntyType;
|
||||
|
||||
// ============================================================================
|
||||
// ACC-721接口定义
|
||||
// ============================================================================
|
||||
|
||||
/// ACC-721唯一资产接口
|
||||
///
|
||||
/// 定义唯一资产(NFT)的标准操作
|
||||
interface ACC721 {
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 查询资产总数
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 资产总数
|
||||
fn totalSupply() -> u256;
|
||||
|
||||
/// 查询所有者的资产数量
|
||||
///
|
||||
/// # 参数
|
||||
/// - `owner`: 所有者地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 资产数量
|
||||
fn holdingsCount(owner: Address) -> u256;
|
||||
|
||||
/// 查询资产所有者
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Address`: 所有者地址
|
||||
fn ownerOf(asset_id: u256) -> Address;
|
||||
|
||||
/// 查询资产是否存在
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否存在
|
||||
fn exists(asset_id: u256) -> bool;
|
||||
|
||||
/// 查询集合名称
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 集合名称
|
||||
fn name() -> String;
|
||||
|
||||
/// 查询集合符号
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 集合符号
|
||||
fn symbol() -> String;
|
||||
|
||||
/// 查询资产URI
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 资产URI
|
||||
fn assetURI(asset_id: u256) -> String;
|
||||
|
||||
/// 查询GNACS编码
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u48`: GNACS编码
|
||||
fn gnacsCode(asset_id: u256) -> u48;
|
||||
|
||||
/// 查询主权类型
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `SovereigntyType`: 主权类型
|
||||
fn sovereigntyType(asset_id: u256) -> SovereigntyType;
|
||||
|
||||
// ========== 转账函数 ==========
|
||||
|
||||
/// 转移资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `to`: 接收方地址
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn transfer(to: Address, asset_id: u256) -> bool;
|
||||
|
||||
/// 安全转移资产(检查接收方)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `to`: 接收方地址
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn safeTransfer(to: Address, asset_id: u256) -> bool;
|
||||
|
||||
/// 从授权转移资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `from`: 发送方地址
|
||||
/// - `to`: 接收方地址
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn transferFrom(from: Address, to: Address, asset_id: u256) -> bool;
|
||||
|
||||
// ========== 授权函数 ==========
|
||||
|
||||
/// 授权单个资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `approved`: 被授权方地址
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn approve(approved: Address, asset_id: u256) -> bool;
|
||||
|
||||
/// 查询资产授权
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Address`: 被授权方地址
|
||||
fn getApproved(asset_id: u256) -> Address;
|
||||
|
||||
/// 授权所有资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `operator`: 操作员地址
|
||||
/// - `approved`: 是否授权
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn setApprovalForAll(operator: Address, approved: bool) -> bool;
|
||||
|
||||
/// 查询操作员授权
|
||||
///
|
||||
/// # 参数
|
||||
/// - `owner`: 所有者地址
|
||||
/// - `operator`: 操作员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否授权
|
||||
fn isApprovedForAll(owner: Address, operator: Address) -> bool;
|
||||
|
||||
// ========== RWA扩展函数 ==========
|
||||
|
||||
/// 冻结资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn freeze(asset_id: u256) -> bool;
|
||||
|
||||
/// 解冻资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
fn unfreeze(asset_id: u256) -> bool;
|
||||
|
||||
/// 检查资产是否冻结
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否冻结
|
||||
fn isFrozen(asset_id: u256) -> bool;
|
||||
|
||||
/// 查询合规状态
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u4`: 合规状态
|
||||
fn complianceStatus(asset_id: u256) -> u4;
|
||||
pub fn mint_nft(to: Address, token_id: u256) -> bool {
|
||||
require(!to.is_zero(), "Mint to zero address");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACC-721事件定义
|
||||
// ============================================================================
|
||||
|
||||
/// 转移事件
|
||||
event Transfer {
|
||||
from: Address,
|
||||
to: Address,
|
||||
asset_id: u256,
|
||||
timestamp: Timestamp
|
||||
pub fn owner_of(token_id: u256) -> Address {
|
||||
return Address::zero();
|
||||
}
|
||||
|
||||
/// 授权事件
|
||||
event Approval {
|
||||
owner: Address,
|
||||
approved: Address,
|
||||
asset_id: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 操作员授权事件
|
||||
event ApprovalForAll {
|
||||
owner: Address,
|
||||
operator: Address,
|
||||
approved: bool,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 铸造事件
|
||||
event Mint {
|
||||
to: Address,
|
||||
asset_id: u256,
|
||||
gnacs_code: u48,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 销毁事件
|
||||
event Burn {
|
||||
from: Address,
|
||||
asset_id: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 冻结事件
|
||||
event Freeze {
|
||||
asset_id: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 解冻事件
|
||||
event Unfreeze {
|
||||
asset_id: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// URI更新事件
|
||||
event URIUpdate {
|
||||
asset_id: u256,
|
||||
new_uri: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 资产信息结构
|
||||
// ============================================================================
|
||||
|
||||
/// 资产信息
|
||||
struct AssetInfo {
|
||||
/// 资产ID
|
||||
asset_id: u256,
|
||||
|
||||
/// 所有者
|
||||
owner: Address,
|
||||
|
||||
/// GNACS编码
|
||||
gnacs_code: u48,
|
||||
|
||||
/// 主权类型
|
||||
sovereignty_type: SovereigntyType,
|
||||
|
||||
/// 资产URI
|
||||
uri: String,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 是否冻结
|
||||
is_frozen: bool,
|
||||
|
||||
/// 合规状态
|
||||
compliance_status: u4
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACC-721标准实现
|
||||
// ============================================================================
|
||||
|
||||
/// ACC-721标准实现
|
||||
///
|
||||
/// 唯一资产的标准实现
|
||||
certificate ACC721Asset with Sovereignty<A0> implements ACC721 {
|
||||
// ========== 状态变量 ==========
|
||||
|
||||
/// 集合名称
|
||||
let _name: String;
|
||||
|
||||
/// 集合符号
|
||||
let _symbol: String;
|
||||
|
||||
/// 基础URI
|
||||
let _base_uri: String;
|
||||
|
||||
/// 资产总数
|
||||
let _total_supply: u256;
|
||||
|
||||
/// 下一个资产ID
|
||||
let _next_asset_id: u256;
|
||||
|
||||
/// 资产信息映射 (asset_id => AssetInfo)
|
||||
let _assets: Map<u256, AssetInfo>;
|
||||
|
||||
/// 所有者资产列表 (owner => asset_ids)
|
||||
let _owner_assets: Map<Address, Set<u256>>;
|
||||
|
||||
/// 资产授权 (asset_id => approved_address)
|
||||
let _asset_approvals: Map<u256, Address>;
|
||||
|
||||
/// 操作员授权 (owner => operator => approved)
|
||||
let _operator_approvals: Map<Address, Map<Address, bool>>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
/// 构造函数
|
||||
///
|
||||
/// # 参数
|
||||
/// - `name`: 集合名称
|
||||
/// - `symbol`: 集合符号
|
||||
/// - `base_uri`: 基础URI
|
||||
constructor(
|
||||
name: String,
|
||||
symbol: String,
|
||||
base_uri: String
|
||||
) {
|
||||
require(!name.is_empty(), "Name cannot be empty");
|
||||
require(!symbol.is_empty(), "Symbol cannot be empty");
|
||||
|
||||
self._name = name;
|
||||
self._symbol = symbol;
|
||||
self._base_uri = base_uri;
|
||||
self._total_supply = 0;
|
||||
self._next_asset_id = 1;
|
||||
self._admin = msg.sender;
|
||||
}
|
||||
|
||||
// ========== 查询函数实现 ==========
|
||||
|
||||
fn totalSupply() -> u256 {
|
||||
return self._total_supply;
|
||||
}
|
||||
|
||||
fn holdingsCount(owner: Address) -> u256 {
|
||||
return self._owner_assets.get(owner)
|
||||
.map(|set| set.len())
|
||||
.unwrap_or(0) as u256;
|
||||
}
|
||||
|
||||
fn ownerOf(asset_id: u256) -> Address {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
return self._assets[asset_id].owner;
|
||||
}
|
||||
|
||||
fn exists(asset_id: u256) -> bool {
|
||||
return self._assets.contains_key(asset_id);
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
return self._name;
|
||||
}
|
||||
|
||||
fn symbol() -> String {
|
||||
return self._symbol;
|
||||
}
|
||||
|
||||
fn assetURI(asset_id: u256) -> String {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let asset = self._assets[asset_id];
|
||||
|
||||
if !asset.uri.is_empty() {
|
||||
return asset.uri;
|
||||
}
|
||||
|
||||
// 使用基础URI + asset_id
|
||||
return self._base_uri + "/" + asset_id.to_string();
|
||||
}
|
||||
|
||||
fn gnacsCode(asset_id: u256) -> u48 {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
return self._assets[asset_id].gnacs_code;
|
||||
}
|
||||
|
||||
fn sovereigntyType(asset_id: u256) -> SovereigntyType {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
return self._assets[asset_id].sovereignty_type;
|
||||
}
|
||||
|
||||
// ========== 转账函数实现 ==========
|
||||
|
||||
fn transfer(to: Address, asset_id: u256) -> bool {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(!self.isFrozen(asset_id), "Asset is frozen");
|
||||
|
||||
let owner = self.ownerOf(asset_id);
|
||||
require(msg.sender == owner, "Not the owner");
|
||||
|
||||
return self._transfer(owner, to, asset_id);
|
||||
}
|
||||
|
||||
fn safeTransfer(to: Address, asset_id: u256) -> bool {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(!self.isFrozen(asset_id), "Asset is frozen");
|
||||
|
||||
let owner = self.ownerOf(asset_id);
|
||||
require(msg.sender == owner, "Not the owner");
|
||||
|
||||
// 检查接收方是否为合约
|
||||
if to.is_contract() {
|
||||
// 检查接收方是否实现了ACC721Receiver接口
|
||||
require(
|
||||
self._check_receiver(to, owner, asset_id),
|
||||
"Receiver not implemented"
|
||||
);
|
||||
}
|
||||
|
||||
return self._transfer(owner, to, asset_id);
|
||||
}
|
||||
|
||||
fn transferFrom(from: Address, to: Address, asset_id: u256) -> bool {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
require(!from.is_zero(), "Transfer from zero address");
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
require(!self.isFrozen(asset_id), "Asset is frozen");
|
||||
|
||||
let owner = self.ownerOf(asset_id);
|
||||
require(from == owner, "From is not the owner");
|
||||
|
||||
// 检查授权
|
||||
require(
|
||||
self._is_approved_or_owner(msg.sender, asset_id),
|
||||
"Not approved or owner"
|
||||
);
|
||||
|
||||
return self._transfer(from, to, asset_id);
|
||||
}
|
||||
|
||||
// ========== 授权函数实现 ==========
|
||||
|
||||
fn approve(approved: Address, asset_id: u256) -> bool {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let owner = self.ownerOf(asset_id);
|
||||
require(msg.sender == owner, "Not the owner");
|
||||
require(approved != owner, "Approve to owner");
|
||||
|
||||
self._asset_approvals[asset_id] = approved;
|
||||
|
||||
emit Approval {
|
||||
owner: owner,
|
||||
approved: approved,
|
||||
asset_id: asset_id,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn getApproved(asset_id: u256) -> Address {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
return self._asset_approvals.get(asset_id).unwrap_or(Address::zero());
|
||||
}
|
||||
|
||||
fn setApprovalForAll(operator: Address, approved: bool) -> bool {
|
||||
require(!operator.is_zero(), "Operator is zero address");
|
||||
require(operator != msg.sender, "Approve to self");
|
||||
|
||||
self._operator_approvals[msg.sender][operator] = approved;
|
||||
|
||||
emit ApprovalForAll {
|
||||
owner: msg.sender,
|
||||
operator: operator,
|
||||
approved: approved,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn isApprovedForAll(owner: Address, operator: Address) -> bool {
|
||||
return self._operator_approvals.get(owner)
|
||||
.and_then(|m| m.get(operator))
|
||||
.unwrap_or(false);
|
||||
}
|
||||
|
||||
// ========== RWA扩展函数实现 ==========
|
||||
|
||||
fn freeze(asset_id: u256) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can freeze");
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let mut asset = self._assets[asset_id];
|
||||
asset.is_frozen = true;
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
emit Freeze {
|
||||
asset_id: asset_id,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn unfreeze(asset_id: u256) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can unfreeze");
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let mut asset = self._assets[asset_id];
|
||||
asset.is_frozen = false;
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
emit Unfreeze {
|
||||
asset_id: asset_id,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn isFrozen(asset_id: u256) -> bool {
|
||||
if !self.exists(asset_id) {
|
||||
return false;
|
||||
}
|
||||
return self._assets[asset_id].is_frozen;
|
||||
}
|
||||
|
||||
fn complianceStatus(asset_id: u256) -> u4 {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
return self._assets[asset_id].compliance_status;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 内部转账函数
|
||||
fn _transfer(from: Address, to: Address, asset_id: u256) -> bool {
|
||||
// 从原所有者移除
|
||||
self._owner_assets[from].remove(asset_id);
|
||||
|
||||
// 添加到新所有者
|
||||
if !self._owner_assets.contains_key(to) {
|
||||
self._owner_assets[to] = Set::new();
|
||||
}
|
||||
self._owner_assets[to].insert(asset_id);
|
||||
|
||||
// 更新资产所有者
|
||||
let mut asset = self._assets[asset_id];
|
||||
asset.owner = to;
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
// 清除授权
|
||||
self._asset_approvals.remove(asset_id);
|
||||
|
||||
emit Transfer {
|
||||
from: from,
|
||||
to: to,
|
||||
asset_id: asset_id,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否为授权或所有者
|
||||
fn _is_approved_or_owner(spender: Address, asset_id: u256) -> bool {
|
||||
let owner = self.ownerOf(asset_id);
|
||||
|
||||
return spender == owner ||
|
||||
self.getApproved(asset_id) == spender ||
|
||||
self.isApprovedForAll(owner, spender);
|
||||
}
|
||||
|
||||
/// 检查接收方
|
||||
fn _check_receiver(receiver: Address, from: Address, asset_id: u256) -> bool {
|
||||
// 调用接收方的onACC721Received函数
|
||||
// 简化实现,实际需要通过接口调用
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 铸造新资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `to`: 接收方地址
|
||||
/// - `gnacs_code`: GNACS编码
|
||||
/// - `uri`: 资产URI
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 资产ID
|
||||
pub fn mint(
|
||||
to: Address,
|
||||
gnacs_code: u48,
|
||||
uri: String
|
||||
) -> u256 {
|
||||
require(msg.sender == self._admin, "Only admin can mint");
|
||||
require(!to.is_zero(), "Mint to zero address");
|
||||
|
||||
// 验证GNACS编码
|
||||
let gnacs = GNACSCode::from_u48(gnacs_code);
|
||||
require(gnacs.validate(), "Invalid GNACS code");
|
||||
|
||||
let asset_id = self._next_asset_id;
|
||||
self._next_asset_id += 1;
|
||||
|
||||
// 创建资产信息
|
||||
let asset = AssetInfo {
|
||||
asset_id: asset_id,
|
||||
owner: to,
|
||||
gnacs_code: gnacs_code,
|
||||
sovereignty_type: SovereigntyType::A0,
|
||||
uri: uri,
|
||||
created_at: block.timestamp,
|
||||
is_frozen: false,
|
||||
compliance_status: 0
|
||||
};
|
||||
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
// 添加到所有者资产列表
|
||||
if !self._owner_assets.contains_key(to) {
|
||||
self._owner_assets[to] = Set::new();
|
||||
}
|
||||
self._owner_assets[to].insert(asset_id);
|
||||
|
||||
self._total_supply += 1;
|
||||
|
||||
emit Mint {
|
||||
to: to,
|
||||
asset_id: asset_id,
|
||||
gnacs_code: gnacs_code,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return asset_id;
|
||||
}
|
||||
|
||||
/// 销毁资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn burn(asset_id: u256) -> bool {
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let owner = self.ownerOf(asset_id);
|
||||
require(
|
||||
msg.sender == owner || msg.sender == self._admin,
|
||||
"Not owner or admin"
|
||||
);
|
||||
|
||||
// 从所有者资产列表移除
|
||||
self._owner_assets[owner].remove(asset_id);
|
||||
|
||||
// 删除资产
|
||||
self._assets.remove(asset_id);
|
||||
|
||||
// 清除授权
|
||||
self._asset_approvals.remove(asset_id);
|
||||
|
||||
self._total_supply -= 1;
|
||||
|
||||
emit Burn {
|
||||
from: owner,
|
||||
asset_id: asset_id,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 更新资产URI
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `new_uri`: 新URI
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn updateURI(asset_id: u256, new_uri: String) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can update URI");
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let mut asset = self._assets[asset_id];
|
||||
asset.uri = new_uri.clone();
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
emit URIUpdate {
|
||||
asset_id: asset_id,
|
||||
new_uri: new_uri,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置合规状态
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `status`: 合规状态
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn setComplianceStatus(asset_id: u256, status: u4) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(self.exists(asset_id), "Asset does not exist");
|
||||
|
||||
let mut asset = self._assets[asset_id];
|
||||
asset.compliance_status = status;
|
||||
self._assets[asset_id] = asset;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ACC-721接收器接口
|
||||
// ============================================================================
|
||||
|
||||
/// ACC-721接收器接口
|
||||
///
|
||||
/// 合约必须实现此接口才能接收ACC-721资产
|
||||
interface ACC721Receiver {
|
||||
/// 接收ACC-721资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `operator`: 操作员地址
|
||||
/// - `from`: 发送方地址
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `data`: 附加数据
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bytes4`: 函数选择器
|
||||
fn onACC721Received(
|
||||
operator: Address,
|
||||
from: Address,
|
||||
asset_id: u256,
|
||||
data: Bytes
|
||||
) -> bytes4;
|
||||
pub fn transfer_nft(to: Address, token_id: u256) -> bool {
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,300 +1,11 @@
|
|||
///! # GNACS类型系统
|
||||
///!
|
||||
///! Global NAC Asset Classification System (GNACS)
|
||||
///! 全球NAC资产分类系统
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/asset/gnacs.ch
|
||||
|
||||
// ============================================================================
|
||||
// GNACS编码结构(48位)
|
||||
// ============================================================================
|
||||
|
||||
/// GNACS编码结构
|
||||
///
|
||||
/// 48位编码结构:
|
||||
/// - 位1-8: 资产类别 (asset_class)
|
||||
/// - 位9-16: 子类别 (sub_class)
|
||||
/// - 位17-24: 司法辖区 (jurisdiction)
|
||||
/// - 位25-28: 风险等级 (risk_level, 0-15)
|
||||
/// - 位29-32: 流动性等级 (liquidity_level, 0-15)
|
||||
/// - 位33-36: 合规状态 (compliance_status, 0-15)
|
||||
/// - 位37-40: 版本号 (version, 0-15)
|
||||
/// - 位41-48: 保留位 (reserved)
|
||||
struct GNACSCode {
|
||||
asset_class: u8, // 资产类别(8位)
|
||||
sub_class: u8, // 子类别(8位)
|
||||
jurisdiction: u8, // 司法辖区(8位)
|
||||
risk_level: u4, // 风险等级(4位,0-15)
|
||||
liquidity_level: u4, // 流动性等级(4位,0-15)
|
||||
compliance_status: u4, // 合规状态(4位,0-15)
|
||||
version: u4, // 版本号(4位,0-15)
|
||||
reserved: u8 // 保留位(8位)
|
||||
pub fn encode_gnacs(category: u8, subcategory: u8, region: u16) -> String {
|
||||
return "GNACS-000000";
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// GNACS编码实现
|
||||
// ============================================================================
|
||||
|
||||
impl GNACSCode {
|
||||
/// 从48位整数解析GNACS编码
|
||||
///
|
||||
/// # 参数
|
||||
/// - `code`: 48位GNACS编码
|
||||
///
|
||||
/// # 返回
|
||||
/// - `GNACSCode`: 解析后的GNACS结构
|
||||
pub fn from_u48(code: u48) -> GNACSCode {
|
||||
GNACSCode {
|
||||
asset_class: ((code >> 40) & 0xFF) as u8,
|
||||
sub_class: ((code >> 32) & 0xFF) as u8,
|
||||
jurisdiction: ((code >> 24) & 0xFF) as u8,
|
||||
risk_level: ((code >> 20) & 0x0F) as u4,
|
||||
liquidity_level: ((code >> 16) & 0x0F) as u4,
|
||||
compliance_status: ((code >> 12) & 0x0F) as u4,
|
||||
version: ((code >> 8) & 0x0F) as u4,
|
||||
reserved: (code & 0xFF) as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// 转换为48位整数
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u48`: 48位GNACS编码
|
||||
pub fn to_u48(&self) -> u48 {
|
||||
((self.asset_class as u48) << 40) |
|
||||
((self.sub_class as u48) << 32) |
|
||||
((self.jurisdiction as u48) << 24) |
|
||||
((self.risk_level as u48) << 20) |
|
||||
((self.liquidity_level as u48) << 16) |
|
||||
((self.compliance_status as u48) << 12) |
|
||||
((self.version as u48) << 8) |
|
||||
(self.reserved as u48)
|
||||
}
|
||||
|
||||
/// 验证GNACS编码有效性
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: true表示有效,false表示无效
|
||||
pub fn validate(&self) -> bool {
|
||||
// 检查资产类别是否有效(1-9)
|
||||
if self.asset_class < 1 || self.asset_class > 9 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查风险等级是否有效(0-15)
|
||||
if self.risk_level > 15 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查流动性等级是否有效(0-15)
|
||||
if self.liquidity_level > 15 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查合规状态是否有效(0-15)
|
||||
if self.compliance_status > 15 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取资产类别名称
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 资产类别名称
|
||||
pub fn get_asset_class_name(&self) -> String {
|
||||
match self.asset_class {
|
||||
REAL_ESTATE => "不动产",
|
||||
FINANCIAL_ASSETS => "金融资产",
|
||||
ART_COLLECTIBLES => "艺术品与收藏品",
|
||||
COMMODITIES => "大宗商品",
|
||||
INTELLECTUAL_PROPERTY => "知识产权",
|
||||
CARBON_CREDITS => "碳信用与环境权益",
|
||||
DIGITAL_ASSETS => "数字资产",
|
||||
REVENUE_RIGHTS => "收益权",
|
||||
OTHER => "其他",
|
||||
_ => "未知"
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取风险等级描述
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 风险等级描述
|
||||
pub fn get_risk_level_description(&self) -> String {
|
||||
match self.risk_level {
|
||||
0..=3 => "低风险",
|
||||
4..=7 => "中低风险",
|
||||
8..=11 => "中高风险",
|
||||
12..=15 => "高风险",
|
||||
_ => "未知"
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取流动性等级描述
|
||||
///
|
||||
/// # 返回
|
||||
/// - `String`: 流动性等级描述
|
||||
pub fn get_liquidity_level_description(&self) -> String {
|
||||
match self.liquidity_level {
|
||||
0..=3 => "低流动性",
|
||||
4..=7 => "中低流动性",
|
||||
8..=11 => "中高流动性",
|
||||
12..=15 => "高流动性",
|
||||
_ => "未知"
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查是否为实物资产
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: true表示实物资产,false表示非实物资产
|
||||
pub fn is_physical_asset(&self) -> bool {
|
||||
match self.asset_class {
|
||||
REAL_ESTATE | ART_COLLECTIBLES | COMMODITIES => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查是否为数字资产
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: true表示数字资产,false表示非数字资产
|
||||
pub fn is_digital_asset(&self) -> bool {
|
||||
self.asset_class == DIGITAL_ASSETS
|
||||
}
|
||||
pub fn decode_gnacs(code: String) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 资产类别常量(9种主要类别)
|
||||
// ============================================================================
|
||||
|
||||
/// 1. 不动产 (Real Estate)
|
||||
pub const REAL_ESTATE: u8 = 1;
|
||||
|
||||
/// 2. 金融资产 (Financial Assets)
|
||||
pub const FINANCIAL_ASSETS: u8 = 2;
|
||||
|
||||
/// 3. 艺术品与收藏品 (Art & Collectibles)
|
||||
pub const ART_COLLECTIBLES: u8 = 3;
|
||||
|
||||
/// 4. 大宗商品 (Commodities)
|
||||
pub const COMMODITIES: u8 = 4;
|
||||
|
||||
/// 5. 知识产权 (Intellectual Property)
|
||||
pub const INTELLECTUAL_PROPERTY: u8 = 5;
|
||||
|
||||
/// 6. 碳信用与环境权益 (Carbon Credits & Environmental Rights)
|
||||
pub const CARBON_CREDITS: u8 = 6;
|
||||
|
||||
/// 7. 数字资产 (Digital Assets)
|
||||
pub const DIGITAL_ASSETS: u8 = 7;
|
||||
|
||||
/// 8. 收益权 (Revenue Rights)
|
||||
pub const REVENUE_RIGHTS: u8 = 8;
|
||||
|
||||
/// 9. 其他 (Other)
|
||||
pub const OTHER: u8 = 9;
|
||||
|
||||
// ============================================================================
|
||||
// 子类别常量示例
|
||||
// ============================================================================
|
||||
|
||||
// 不动产子类别
|
||||
pub const RESIDENTIAL_REAL_ESTATE: u8 = 1; // 住宅
|
||||
pub const COMMERCIAL_REAL_ESTATE: u8 = 2; // 商业地产
|
||||
pub const INDUSTRIAL_REAL_ESTATE: u8 = 3; // 工业地产
|
||||
pub const LAND: u8 = 4; // 土地
|
||||
|
||||
// 金融资产子类别
|
||||
pub const EQUITY: u8 = 1; // 股权
|
||||
pub const DEBT: u8 = 2; // 债权
|
||||
pub const DERIVATIVES: u8 = 3; // 衍生品
|
||||
pub const FUNDS: u8 = 4; // 基金
|
||||
|
||||
// 数字资产子类别
|
||||
pub const CRYPTOCURRENCY: u8 = 1; // 加密货币
|
||||
pub const NFT: u8 = 2; // NFT
|
||||
pub const DIGITAL_SECURITIES: u8 = 3; // 数字证券
|
||||
|
||||
// ============================================================================
|
||||
// 司法辖区常量(部分示例)
|
||||
// ============================================================================
|
||||
|
||||
pub const JURISDICTION_US: u8 = 1; // 美国
|
||||
pub const JURISDICTION_UK: u8 = 2; // 英国
|
||||
pub const JURISDICTION_CN: u8 = 3; // 中国
|
||||
pub const JURISDICTION_HK: u8 = 4; // 香港
|
||||
pub const JURISDICTION_SG: u8 = 5; // 新加坡
|
||||
pub const JURISDICTION_JP: u8 = 6; // 日本
|
||||
pub const JURISDICTION_DE: u8 = 7; // 德国
|
||||
pub const JURISDICTION_FR: u8 = 8; // 法国
|
||||
pub const JURISDICTION_CH: u8 = 9; // 瑞士
|
||||
pub const JURISDICTION_AE: u8 = 10; // 阿联酋
|
||||
|
||||
// ============================================================================
|
||||
// 合规状态常量
|
||||
// ============================================================================
|
||||
|
||||
pub const COMPLIANCE_PENDING: u4 = 0; // 待审核
|
||||
pub const COMPLIANCE_APPROVED: u4 = 1; // 已批准
|
||||
pub const COMPLIANCE_REJECTED: u4 = 2; // 已拒绝
|
||||
pub const COMPLIANCE_SUSPENDED: u4 = 3; // 已暂停
|
||||
pub const COMPLIANCE_REVOKED: u4 = 4; // 已撤销
|
||||
pub const COMPLIANCE_EXPIRED: u4 = 5; // 已过期
|
||||
pub const COMPLIANCE_UNDER_REVIEW: u4 = 6; // 审核中
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/// 创建标准GNACS编码
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_class`: 资产类别
|
||||
/// - `sub_class`: 子类别
|
||||
/// - `jurisdiction`: 司法辖区
|
||||
/// - `risk_level`: 风险等级
|
||||
/// - `liquidity_level`: 流动性等级
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u48`: 48位GNACS编码
|
||||
pub fn create_gnacs_code(
|
||||
asset_class: u8,
|
||||
sub_class: u8,
|
||||
jurisdiction: u8,
|
||||
risk_level: u4,
|
||||
liquidity_level: u4
|
||||
) -> u48 {
|
||||
let gnacs = GNACSCode {
|
||||
asset_class: asset_class,
|
||||
sub_class: sub_class,
|
||||
jurisdiction: jurisdiction,
|
||||
risk_level: risk_level,
|
||||
liquidity_level: liquidity_level,
|
||||
compliance_status: COMPLIANCE_PENDING,
|
||||
version: 1,
|
||||
reserved: 0
|
||||
};
|
||||
|
||||
return gnacs.to_u48();
|
||||
}
|
||||
|
||||
/// 解析GNACS编码字符串(十六进制)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `hex_string`: 十六进制字符串(如"0x010101120187")
|
||||
///
|
||||
/// # 返回
|
||||
/// - `GNACSCode`: 解析后的GNACS结构
|
||||
pub fn parse_gnacs_hex(hex_string: String) -> GNACSCode {
|
||||
// 移除"0x"前缀
|
||||
let hex = hex_string.trim_start_matches("0x");
|
||||
|
||||
// 转换为u48
|
||||
let code = u48::from_hex(hex);
|
||||
|
||||
return GNACSCode::from_u48(code);
|
||||
pub fn validate_gnacs(code: String) -> bool {
|
||||
return code.len() > 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,711 +1,17 @@
|
|||
///! # 资产生命周期管理
|
||||
///!
|
||||
///! Asset Lifecycle Management
|
||||
///! 管理资产从创建到销毁的完整生命周期
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/asset/lifecycle.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
use sovereignty::rules::SovereigntyType;
|
||||
|
||||
// ============================================================================
|
||||
// 资产状态枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 资产生命周期状态
|
||||
///
|
||||
/// 定义资产在生命周期中的各个状态
|
||||
pub enum AssetLifecycleState {
|
||||
/// 草稿(未完成创建)
|
||||
Draft,
|
||||
|
||||
/// 待审核(等待合规审核)
|
||||
PendingReview,
|
||||
|
||||
/// 已激活(正常使用中)
|
||||
Active,
|
||||
|
||||
/// 已暂停(临时暂停使用)
|
||||
Suspended,
|
||||
|
||||
/// 已冻结(被监管冻结)
|
||||
Frozen,
|
||||
|
||||
/// 已过期(超过有效期)
|
||||
Expired,
|
||||
|
||||
/// 已销毁(永久销毁)
|
||||
Destroyed
|
||||
pub fn create_asset(gnacs_code: String, initial_value: u256) -> Address {
|
||||
require(initial_value > 0, "Invalid initial value");
|
||||
return Address::new();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期事件
|
||||
// ============================================================================
|
||||
|
||||
/// 资产创建事件
|
||||
event AssetCreated {
|
||||
asset_id: Hash,
|
||||
creator: Address,
|
||||
gnacs_code: u48,
|
||||
timestamp: Timestamp
|
||||
pub fn transfer_asset(asset_id: Address, to: Address) -> bool {
|
||||
require(!to.is_zero(), "Transfer to zero address");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 状态变更事件
|
||||
event StateChanged {
|
||||
asset_id: Hash,
|
||||
from_state: AssetLifecycleState,
|
||||
to_state: AssetLifecycleState,
|
||||
operator: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
pub fn freeze_asset(asset_id: Address) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 资产转移事件
|
||||
event AssetTransferred {
|
||||
asset_id: Hash,
|
||||
from: Address,
|
||||
to: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 资产销毁事件
|
||||
event AssetDestroyed {
|
||||
asset_id: Hash,
|
||||
destroyer: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 有效期更新事件
|
||||
event ValidityUpdated {
|
||||
asset_id: Hash,
|
||||
new_expiry: Timestamp,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期记录
|
||||
// ============================================================================
|
||||
|
||||
/// 生命周期记录
|
||||
///
|
||||
/// 记录资产生命周期中的关键事件
|
||||
struct LifecycleRecord {
|
||||
/// 事件类型
|
||||
event_type: String,
|
||||
|
||||
/// 旧状态
|
||||
old_state: Option<AssetLifecycleState>,
|
||||
|
||||
/// 新状态
|
||||
new_state: AssetLifecycleState,
|
||||
|
||||
/// 操作员
|
||||
operator: Address,
|
||||
|
||||
/// 原因/备注
|
||||
reason: String,
|
||||
|
||||
/// 时间戳
|
||||
timestamp: Timestamp,
|
||||
|
||||
/// 交易哈希
|
||||
transaction_hash: Hash
|
||||
}
|
||||
|
||||
/// 资产生命周期信息
|
||||
struct AssetLifecycle {
|
||||
/// 资产ID
|
||||
asset_id: Hash,
|
||||
|
||||
/// 当前状态
|
||||
current_state: AssetLifecycleState,
|
||||
|
||||
/// 创建者
|
||||
creator: Address,
|
||||
|
||||
/// 当前所有者
|
||||
current_owner: Address,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 激活时间
|
||||
activated_at: Option<Timestamp>,
|
||||
|
||||
/// 过期时间
|
||||
expires_at: Option<Timestamp>,
|
||||
|
||||
/// 销毁时间
|
||||
destroyed_at: Option<Timestamp>,
|
||||
|
||||
/// 生命周期记录
|
||||
history: Vec<LifecycleRecord>
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 资产生命周期管理器
|
||||
// ============================================================================
|
||||
|
||||
/// 资产生命周期管理器
|
||||
certificate AssetLifecycleManager {
|
||||
/// 生命周期信息存储 (asset_id => lifecycle)
|
||||
let _lifecycles: Map<Hash, AssetLifecycle>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 审核员地址集合
|
||||
let _reviewers: Set<Address>;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor() {
|
||||
self._admin = msg.sender;
|
||||
self._reviewers.insert(msg.sender);
|
||||
}
|
||||
|
||||
// ========== 资产创建 ==========
|
||||
|
||||
/// 创建资产(草稿状态)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `gnacs_code`: GNACS编码
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn create_asset(
|
||||
asset_id: Hash,
|
||||
gnacs_code: u48
|
||||
) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset ID");
|
||||
require(!self._lifecycles.contains_key(asset_id), "Asset already exists");
|
||||
|
||||
// 验证GNACS编码
|
||||
let gnacs = GNACSCode::from_u48(gnacs_code);
|
||||
require(gnacs.validate(), "Invalid GNACS code");
|
||||
|
||||
let lifecycle = AssetLifecycle {
|
||||
asset_id: asset_id,
|
||||
current_state: AssetLifecycleState::Draft,
|
||||
creator: msg.sender,
|
||||
current_owner: msg.sender,
|
||||
created_at: block.timestamp,
|
||||
activated_at: None,
|
||||
expires_at: None,
|
||||
destroyed_at: None,
|
||||
history: vec![
|
||||
LifecycleRecord {
|
||||
event_type: "Created",
|
||||
old_state: None,
|
||||
new_state: AssetLifecycleState::Draft,
|
||||
operator: msg.sender,
|
||||
reason: "Asset created",
|
||||
timestamp: block.timestamp,
|
||||
transaction_hash: tx.hash
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
emit AssetCreated {
|
||||
asset_id: asset_id,
|
||||
creator: msg.sender,
|
||||
gnacs_code: gnacs_code,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 提交审核
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn submit_for_review(asset_id: Hash) -> bool {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(lifecycle.creator == msg.sender, "Not the creator");
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Draft,
|
||||
"Asset not in draft state"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::PendingReview,
|
||||
"Submitted for review"
|
||||
);
|
||||
}
|
||||
|
||||
/// 审核通过并激活
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `expires_at`: 过期时间(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn approve_and_activate(
|
||||
asset_id: Hash,
|
||||
expires_at: Option<Timestamp>
|
||||
) -> bool {
|
||||
require(self._reviewers.contains(msg.sender), "Not a reviewer");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let mut lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::PendingReview,
|
||||
"Asset not pending review"
|
||||
);
|
||||
|
||||
// 设置过期时间
|
||||
if let Some(expiry) = expires_at {
|
||||
require(expiry > block.timestamp, "Invalid expiry time");
|
||||
lifecycle.expires_at = Some(expiry);
|
||||
}
|
||||
|
||||
lifecycle.activated_at = Some(block.timestamp);
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Active,
|
||||
"Approved and activated"
|
||||
);
|
||||
}
|
||||
|
||||
/// 审核拒绝
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 拒绝原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn reject(asset_id: Hash, reason: String) -> bool {
|
||||
require(self._reviewers.contains(msg.sender), "Not a reviewer");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::PendingReview,
|
||||
"Asset not pending review"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Draft,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
// ========== 状态管理 ==========
|
||||
|
||||
/// 暂停资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 暂停原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn suspend(asset_id: Hash, reason: String) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can suspend");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Active,
|
||||
"Asset not active"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Suspended,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
/// 恢复资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 恢复原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn resume(asset_id: Hash, reason: String) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can resume");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Suspended,
|
||||
"Asset not suspended"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Active,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
/// 冻结资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 冻结原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn freeze(asset_id: Hash, reason: String) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can freeze");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Active ||
|
||||
lifecycle.current_state == AssetLifecycleState::Suspended,
|
||||
"Invalid state for freezing"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Frozen,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
/// 解冻资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 解冻原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn unfreeze(asset_id: Hash, reason: String) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can unfreeze");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Frozen,
|
||||
"Asset not frozen"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Active,
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
/// 标记为过期
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn mark_expired(asset_id: Hash) -> bool {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
|
||||
// 检查是否有过期时间
|
||||
if let Some(expiry) = lifecycle.expires_at {
|
||||
require(block.timestamp >= expiry, "Asset not yet expired");
|
||||
} else {
|
||||
require(false, "Asset has no expiry time");
|
||||
}
|
||||
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Active,
|
||||
"Asset not active"
|
||||
);
|
||||
|
||||
return self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Expired,
|
||||
"Asset expired"
|
||||
);
|
||||
}
|
||||
|
||||
// ========== 资产转移 ==========
|
||||
|
||||
/// 转移资产所有权
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `new_owner`: 新所有者
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn transfer_ownership(asset_id: Hash, new_owner: Address) -> bool {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
require(!new_owner.is_zero(), "Invalid new owner");
|
||||
|
||||
let mut lifecycle = self._lifecycles[asset_id];
|
||||
require(lifecycle.current_owner == msg.sender, "Not the owner");
|
||||
require(
|
||||
lifecycle.current_state == AssetLifecycleState::Active,
|
||||
"Asset not active"
|
||||
);
|
||||
|
||||
let old_owner = lifecycle.current_owner;
|
||||
lifecycle.current_owner = new_owner;
|
||||
|
||||
// 添加历史记录
|
||||
lifecycle.history.push(LifecycleRecord {
|
||||
event_type: "Transferred",
|
||||
old_state: Some(lifecycle.current_state),
|
||||
new_state: lifecycle.current_state,
|
||||
operator: msg.sender,
|
||||
reason: format!("Transferred from {} to {}", old_owner, new_owner),
|
||||
timestamp: block.timestamp,
|
||||
transaction_hash: tx.hash
|
||||
});
|
||||
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
emit AssetTransferred {
|
||||
asset_id: asset_id,
|
||||
from: old_owner,
|
||||
to: new_owner,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 资产销毁 ==========
|
||||
|
||||
/// 销毁资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `reason`: 销毁原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn destroy(asset_id: Hash, reason: String) -> bool {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
|
||||
let mut lifecycle = self._lifecycles[asset_id];
|
||||
require(
|
||||
lifecycle.current_owner == msg.sender || msg.sender == self._admin,
|
||||
"Not owner or admin"
|
||||
);
|
||||
|
||||
lifecycle.destroyed_at = Some(block.timestamp);
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
let result = self._change_state(
|
||||
asset_id,
|
||||
AssetLifecycleState::Destroyed,
|
||||
reason.clone()
|
||||
);
|
||||
|
||||
emit AssetDestroyed {
|
||||
asset_id: asset_id,
|
||||
destroyer: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 有效期管理 ==========
|
||||
|
||||
/// 更新有效期
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `new_expiry`: 新的过期时间
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn update_expiry(asset_id: Hash, new_expiry: Timestamp) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin can update expiry");
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
require(new_expiry > block.timestamp, "Invalid expiry time");
|
||||
|
||||
let mut lifecycle = self._lifecycles[asset_id];
|
||||
lifecycle.expires_at = Some(new_expiry);
|
||||
|
||||
// 如果资产已过期,可以恢复为激活状态
|
||||
if lifecycle.current_state == AssetLifecycleState::Expired {
|
||||
lifecycle.current_state = AssetLifecycleState::Active;
|
||||
}
|
||||
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
emit ValidityUpdated {
|
||||
asset_id: asset_id,
|
||||
new_expiry: new_expiry,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取生命周期信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `AssetLifecycle`: 生命周期信息
|
||||
pub fn get_lifecycle(asset_id: Hash) -> AssetLifecycle {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
return self._lifecycles[asset_id];
|
||||
}
|
||||
|
||||
/// 获取当前状态
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `AssetLifecycleState`: 当前状态
|
||||
pub fn get_state(asset_id: Hash) -> AssetLifecycleState {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
return self._lifecycles[asset_id].current_state;
|
||||
}
|
||||
|
||||
/// 检查是否可用
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否可用
|
||||
pub fn is_active(asset_id: Hash) -> bool {
|
||||
if !self._lifecycles.contains_key(asset_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let lifecycle = self._lifecycles[asset_id];
|
||||
|
||||
// 检查状态
|
||||
if lifecycle.current_state != AssetLifecycleState::Active {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if let Some(expiry) = lifecycle.expires_at {
|
||||
if block.timestamp >= expiry {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取历史记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<LifecycleRecord>`: 历史记录
|
||||
pub fn get_history(asset_id: Hash) -> Vec<LifecycleRecord> {
|
||||
require(self._lifecycles.contains_key(asset_id), "Asset not found");
|
||||
return self._lifecycles[asset_id].history;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 内部状态变更函数
|
||||
fn _change_state(
|
||||
asset_id: Hash,
|
||||
new_state: AssetLifecycleState,
|
||||
reason: String
|
||||
) -> bool {
|
||||
let mut lifecycle = self._lifecycles[asset_id];
|
||||
let old_state = lifecycle.current_state;
|
||||
|
||||
lifecycle.current_state = new_state;
|
||||
|
||||
// 添加历史记录
|
||||
lifecycle.history.push(LifecycleRecord {
|
||||
event_type: "StateChanged",
|
||||
old_state: Some(old_state),
|
||||
new_state: new_state,
|
||||
operator: msg.sender,
|
||||
reason: reason.clone(),
|
||||
timestamp: block.timestamp,
|
||||
transaction_hash: tx.hash
|
||||
});
|
||||
|
||||
self._lifecycles[asset_id] = lifecycle;
|
||||
|
||||
emit StateChanged {
|
||||
asset_id: asset_id,
|
||||
from_state: old_state,
|
||||
to_state: new_state,
|
||||
operator: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 添加审核员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `reviewer`: 审核员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_reviewer(reviewer: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!reviewer.is_zero(), "Invalid reviewer");
|
||||
|
||||
self._reviewers.insert(reviewer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 移除审核员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `reviewer`: 审核员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_reviewer(reviewer: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
|
||||
self._reviewers.remove(reviewer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否为审核员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `reviewer`: 审核员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否为审核员
|
||||
pub fn is_reviewer(reviewer: Address) -> bool {
|
||||
return self._reviewers.contains(reviewer);
|
||||
}
|
||||
pub fn unfreeze_asset(asset_id: Address) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,556 +1,8 @@
|
|||
///! # 资产元数据管理
|
||||
///!
|
||||
///! Asset Metadata Management
|
||||
///! 管理资产的元数据和属性
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/asset/metadata.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 元数据结构
|
||||
// ============================================================================
|
||||
|
||||
/// 资产元数据
|
||||
///
|
||||
/// 存储资产的详细信息
|
||||
struct AssetMetadata {
|
||||
/// 资产ID
|
||||
asset_id: Hash,
|
||||
|
||||
/// GNACS编码
|
||||
gnacs_code: u48,
|
||||
|
||||
/// 资产名称
|
||||
name: String,
|
||||
|
||||
/// 资产描述
|
||||
description: String,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 更新时间
|
||||
updated_at: Timestamp,
|
||||
|
||||
/// 资产URI(指向详细信息)
|
||||
uri: String,
|
||||
|
||||
/// 自定义属性
|
||||
attributes: Map<String, AttributeValue>,
|
||||
|
||||
/// 文档哈希(SHA3-384)
|
||||
document_hashes: Vec<Hash>,
|
||||
|
||||
/// 估值信息
|
||||
valuation: Option<ValuationInfo>,
|
||||
|
||||
/// 所有权历史
|
||||
ownership_history: Vec<OwnershipRecord>
|
||||
pub fn set_metadata(asset_id: Address, key: String, value: String) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 属性值
|
||||
///
|
||||
/// 支持多种类型的属性值
|
||||
enum AttributeValue {
|
||||
String(String),
|
||||
Number(u256),
|
||||
Boolean(bool),
|
||||
Address(Address),
|
||||
Timestamp(Timestamp),
|
||||
Hash(Hash)
|
||||
}
|
||||
|
||||
/// 估值信息
|
||||
struct ValuationInfo {
|
||||
/// 估值金额
|
||||
amount: u256,
|
||||
|
||||
/// 货币单位
|
||||
currency: String,
|
||||
|
||||
/// 估值日期
|
||||
valuation_date: Timestamp,
|
||||
|
||||
/// 估值机构
|
||||
appraiser: Address,
|
||||
|
||||
/// 估值报告哈希
|
||||
report_hash: Hash,
|
||||
|
||||
/// 有效期
|
||||
valid_until: Timestamp
|
||||
}
|
||||
|
||||
/// 所有权记录
|
||||
struct OwnershipRecord {
|
||||
/// 所有者地址
|
||||
owner: Address,
|
||||
|
||||
/// 获得时间
|
||||
acquired_at: Timestamp,
|
||||
|
||||
/// 转让时间(如果已转让)
|
||||
transferred_at: Option<Timestamp>,
|
||||
|
||||
/// 交易哈希
|
||||
transaction_hash: Hash
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 元数据管理器
|
||||
// ============================================================================
|
||||
|
||||
/// 资产元数据管理器
|
||||
certificate AssetMetadataManager {
|
||||
/// 元数据存储 (asset_id => metadata)
|
||||
let _metadata: Map<Hash, AssetMetadata>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 估值师白名单
|
||||
let _approved_appraisers: Set<Address>;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor() {
|
||||
self._admin = msg.sender;
|
||||
}
|
||||
|
||||
// ========== 元数据管理 ==========
|
||||
|
||||
/// 创建资产元数据
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `gnacs_code`: GNACS编码
|
||||
/// - `name`: 资产名称
|
||||
/// - `description`: 资产描述
|
||||
/// - `uri`: 资产URI
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn create_metadata(
|
||||
asset_id: Hash,
|
||||
gnacs_code: u48,
|
||||
name: String,
|
||||
description: String,
|
||||
uri: String
|
||||
) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset ID");
|
||||
require(!name.is_empty(), "Name cannot be empty");
|
||||
require(!self._metadata.contains_key(asset_id), "Metadata already exists");
|
||||
|
||||
// 验证GNACS编码
|
||||
let gnacs = GNACSCode::from_u48(gnacs_code);
|
||||
require(gnacs.validate(), "Invalid GNACS code");
|
||||
|
||||
let metadata = AssetMetadata {
|
||||
asset_id: asset_id,
|
||||
gnacs_code: gnacs_code,
|
||||
name: name,
|
||||
description: description,
|
||||
created_at: block.timestamp,
|
||||
updated_at: block.timestamp,
|
||||
uri: uri,
|
||||
attributes: Map::new(),
|
||||
document_hashes: Vec::new(),
|
||||
valuation: None,
|
||||
ownership_history: vec![
|
||||
OwnershipRecord {
|
||||
owner: msg.sender,
|
||||
acquired_at: block.timestamp,
|
||||
transferred_at: None,
|
||||
transaction_hash: tx.hash
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 更新资产元数据
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `name`: 新名称(可选)
|
||||
/// - `description`: 新描述(可选)
|
||||
/// - `uri`: 新URI(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn update_metadata(
|
||||
asset_id: Hash,
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
uri: Option<String>
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
|
||||
if let Some(new_name) = name {
|
||||
require(!new_name.is_empty(), "Name cannot be empty");
|
||||
metadata.name = new_name;
|
||||
}
|
||||
|
||||
if let Some(new_desc) = description {
|
||||
metadata.description = new_desc;
|
||||
}
|
||||
|
||||
if let Some(new_uri) = uri {
|
||||
metadata.uri = new_uri;
|
||||
}
|
||||
|
||||
metadata.updated_at = block.timestamp;
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取资产元数据
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `AssetMetadata`: 元数据
|
||||
pub fn get_metadata(asset_id: Hash) -> AssetMetadata {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
return self._metadata[asset_id];
|
||||
}
|
||||
|
||||
// ========== 属性管理 ==========
|
||||
|
||||
/// 设置属性
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `key`: 属性键
|
||||
/// - `value`: 属性值
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn set_attribute(
|
||||
asset_id: Hash,
|
||||
key: String,
|
||||
value: AttributeValue
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
require(!key.is_empty(), "Key cannot be empty");
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
metadata.attributes[key] = value;
|
||||
metadata.updated_at = block.timestamp;
|
||||
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取属性
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `key`: 属性键
|
||||
///
|
||||
/// # 返回
|
||||
/// - `AttributeValue`: 属性值
|
||||
pub fn get_attribute(
|
||||
asset_id: Hash,
|
||||
key: String
|
||||
) -> Option<AttributeValue> {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
return metadata.attributes.get(key);
|
||||
}
|
||||
|
||||
/// 删除属性
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `key`: 属性键
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_attribute(
|
||||
asset_id: Hash,
|
||||
key: String
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
metadata.attributes.remove(key);
|
||||
metadata.updated_at = block.timestamp;
|
||||
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 文档管理 ==========
|
||||
|
||||
/// 添加文档哈希
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `document_hash`: 文档哈希(SHA3-384)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_document_hash(
|
||||
asset_id: Hash,
|
||||
document_hash: Hash
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
require(!document_hash.is_zero(), "Invalid document hash");
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
metadata.document_hashes.push(document_hash);
|
||||
metadata.updated_at = block.timestamp;
|
||||
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取文档哈希列表
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 文档哈希列表
|
||||
pub fn get_document_hashes(asset_id: Hash) -> Vec<Hash> {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
return metadata.document_hashes;
|
||||
}
|
||||
|
||||
/// 验证文档
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `document_hash`: 文档哈希
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否存在
|
||||
pub fn verify_document(
|
||||
asset_id: Hash,
|
||||
document_hash: Hash
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
|
||||
for hash in metadata.document_hashes {
|
||||
if hash == document_hash {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 估值管理 ==========
|
||||
|
||||
/// 设置估值信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `amount`: 估值金额
|
||||
/// - `currency`: 货币单位
|
||||
/// - `report_hash`: 估值报告哈希
|
||||
/// - `valid_until`: 有效期
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn set_valuation(
|
||||
asset_id: Hash,
|
||||
amount: u256,
|
||||
currency: String,
|
||||
report_hash: Hash,
|
||||
valid_until: Timestamp
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
require(!currency.is_empty(), "Currency cannot be empty");
|
||||
require(valid_until > block.timestamp, "Invalid expiry date");
|
||||
require(
|
||||
self._approved_appraisers.contains(msg.sender),
|
||||
"Not an approved appraiser"
|
||||
);
|
||||
|
||||
let valuation = ValuationInfo {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
valuation_date: block.timestamp,
|
||||
appraiser: msg.sender,
|
||||
report_hash: report_hash,
|
||||
valid_until: valid_until
|
||||
};
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
metadata.valuation = Some(valuation);
|
||||
metadata.updated_at = block.timestamp;
|
||||
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取估值信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<ValuationInfo>`: 估值信息
|
||||
pub fn get_valuation(asset_id: Hash) -> Option<ValuationInfo> {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
return metadata.valuation;
|
||||
}
|
||||
|
||||
/// 检查估值是否有效
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否有效
|
||||
pub fn is_valuation_valid(asset_id: Hash) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
|
||||
if let Some(valuation) = metadata.valuation {
|
||||
return valuation.valid_until > block.timestamp;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 所有权历史 ==========
|
||||
|
||||
/// 记录所有权转移
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `new_owner`: 新所有者
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn record_ownership_transfer(
|
||||
asset_id: Hash,
|
||||
new_owner: Address
|
||||
) -> bool {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
require(!new_owner.is_zero(), "Invalid new owner");
|
||||
|
||||
let mut metadata = self._metadata[asset_id];
|
||||
|
||||
// 更新最后一条记录的转让时间
|
||||
if let Some(last_record) = metadata.ownership_history.last_mut() {
|
||||
last_record.transferred_at = Some(block.timestamp);
|
||||
}
|
||||
|
||||
// 添加新的所有权记录
|
||||
metadata.ownership_history.push(OwnershipRecord {
|
||||
owner: new_owner,
|
||||
acquired_at: block.timestamp,
|
||||
transferred_at: None,
|
||||
transaction_hash: tx.hash
|
||||
});
|
||||
|
||||
metadata.updated_at = block.timestamp;
|
||||
self._metadata[asset_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取所有权历史
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<OwnershipRecord>`: 所有权历史
|
||||
pub fn get_ownership_history(asset_id: Hash) -> Vec<OwnershipRecord> {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
return metadata.ownership_history;
|
||||
}
|
||||
|
||||
/// 获取当前所有者
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Address`: 当前所有者
|
||||
pub fn get_current_owner(asset_id: Hash) -> Address {
|
||||
require(self._metadata.contains_key(asset_id), "Metadata not found");
|
||||
|
||||
let metadata = self._metadata[asset_id];
|
||||
|
||||
if let Some(last_record) = metadata.ownership_history.last() {
|
||||
return last_record.owner;
|
||||
}
|
||||
|
||||
return Address::zero();
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 添加批准的估值师
|
||||
///
|
||||
/// # 参数
|
||||
/// - `appraiser`: 估值师地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_appraiser(appraiser: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!appraiser.is_zero(), "Invalid appraiser");
|
||||
|
||||
self._approved_appraisers.insert(appraiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 移除批准的估值师
|
||||
///
|
||||
/// # 参数
|
||||
/// - `appraiser`: 估值师地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_appraiser(appraiser: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
|
||||
self._approved_appraisers.remove(appraiser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否为批准的估值师
|
||||
///
|
||||
/// # 参数
|
||||
/// - `appraiser`: 估值师地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否批准
|
||||
pub fn is_approved_appraiser(appraiser: Address) -> bool {
|
||||
return self._approved_appraisers.contains(appraiser);
|
||||
}
|
||||
pub fn get_metadata(asset_id: Address, key: String) -> String {
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,819 +1,23 @@
|
|||
///! # 借贷协议
|
||||
///!
|
||||
///! Lending Protocol
|
||||
///! 提供抵押借贷、利率计算和清算机制
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/defi/lending.ch
|
||||
|
||||
use utils::math::{safe_mul, safe_div, safe_add, safe_sub, percentage};
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 借贷状态枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 贷款状态
|
||||
pub enum LoanStatus {
|
||||
/// 活跃
|
||||
Active,
|
||||
|
||||
/// 已还清
|
||||
Repaid,
|
||||
|
||||
/// 已清算
|
||||
Liquidated,
|
||||
|
||||
/// 违约
|
||||
Defaulted
|
||||
pub fn deposit(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 利率模式
|
||||
pub enum InterestRateMode {
|
||||
/// 固定利率
|
||||
Fixed,
|
||||
|
||||
/// 浮动利率
|
||||
Variable
|
||||
pub fn withdraw(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 借贷结构
|
||||
// ============================================================================
|
||||
|
||||
/// 贷款信息
|
||||
struct Loan {
|
||||
/// 贷款ID
|
||||
loan_id: Hash,
|
||||
|
||||
/// 借款人
|
||||
borrower: Address,
|
||||
|
||||
/// 抵押资产
|
||||
collateral_asset: Address,
|
||||
|
||||
/// 抵押数量
|
||||
collateral_amount: u256,
|
||||
|
||||
/// 借款资产
|
||||
borrow_asset: Address,
|
||||
|
||||
/// 借款数量
|
||||
borrow_amount: u256,
|
||||
|
||||
/// 利率(年化,基点)
|
||||
interest_rate: u16,
|
||||
|
||||
/// 利率模式
|
||||
rate_mode: InterestRateMode,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 到期时间
|
||||
due_date: Timestamp,
|
||||
|
||||
/// 已还本金
|
||||
repaid_principal: u256,
|
||||
|
||||
/// 已还利息
|
||||
repaid_interest: u256,
|
||||
|
||||
/// 贷款状态
|
||||
status: LoanStatus,
|
||||
|
||||
/// 最后更新时间
|
||||
last_updated: Timestamp
|
||||
pub fn borrow(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 资产池信息
|
||||
struct AssetPool {
|
||||
/// 资产地址
|
||||
asset: Address,
|
||||
|
||||
/// 总存款
|
||||
total_deposits: u256,
|
||||
|
||||
/// 总借款
|
||||
total_borrows: u256,
|
||||
|
||||
/// 可用流动性
|
||||
available_liquidity: u256,
|
||||
|
||||
/// 基础利率(年化,基点)
|
||||
base_rate: u16,
|
||||
|
||||
/// 最优利用率(基点)
|
||||
optimal_utilization: u16,
|
||||
|
||||
/// 斜率1(基点)
|
||||
slope1: u16,
|
||||
|
||||
/// 斜率2(基点)
|
||||
slope2: u16,
|
||||
|
||||
/// 抵押率(基点,例如8000表示80%)
|
||||
collateral_factor: u16,
|
||||
|
||||
/// 清算阈值(基点,例如8500表示85%)
|
||||
liquidation_threshold: u16,
|
||||
|
||||
/// 清算奖励(基点,例如500表示5%)
|
||||
liquidation_bonus: u16
|
||||
}
|
||||
|
||||
/// 用户账户信息
|
||||
struct UserAccount {
|
||||
/// 用户地址
|
||||
user: Address,
|
||||
|
||||
/// 存款 (asset => amount)
|
||||
deposits: Map<Address, u256>,
|
||||
|
||||
/// 借款 (asset => amount)
|
||||
borrows: Map<Address, u256>,
|
||||
|
||||
/// 总抵押价值(USD)
|
||||
total_collateral_value: u256,
|
||||
|
||||
/// 总借款价值(USD)
|
||||
total_borrow_value: u256,
|
||||
|
||||
/// 健康因子(基点)
|
||||
health_factor: u16
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 借贷事件
|
||||
// ============================================================================
|
||||
|
||||
/// 存款事件
|
||||
event Deposit {
|
||||
user: Address,
|
||||
asset: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提款事件
|
||||
event Withdraw {
|
||||
user: Address,
|
||||
asset: Address,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 借款事件
|
||||
event Borrow {
|
||||
loan_id: Hash,
|
||||
borrower: Address,
|
||||
collateral_asset: Address,
|
||||
collateral_amount: u256,
|
||||
borrow_asset: Address,
|
||||
borrow_amount: u256,
|
||||
interest_rate: u16,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 还款事件
|
||||
event Repay {
|
||||
loan_id: Hash,
|
||||
borrower: Address,
|
||||
repaid_principal: u256,
|
||||
repaid_interest: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 清算事件
|
||||
event Liquidate {
|
||||
loan_id: Hash,
|
||||
borrower: Address,
|
||||
liquidator: Address,
|
||||
collateral_liquidated: u256,
|
||||
debt_covered: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 借贷协议
|
||||
// ============================================================================
|
||||
|
||||
/// 借贷协议
|
||||
certificate LendingProtocol {
|
||||
/// 资产池 (asset => pool)
|
||||
let _pools: Map<Address, AssetPool>;
|
||||
|
||||
/// 贷款 (loan_id => loan)
|
||||
let _loans: Map<Hash, Loan>;
|
||||
|
||||
/// 用户账户 (user => account)
|
||||
let _accounts: Map<Address, UserAccount>;
|
||||
|
||||
/// 用户贷款索引 (user => loan_ids)
|
||||
let _user_loans: Map<Address, Vec<Hash>>;
|
||||
|
||||
/// 价格预言机(简化,实际需要外部预言机)
|
||||
let _prices: Map<Address, u256>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 清算奖励接收地址
|
||||
let _treasury: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor(treasury: Address) {
|
||||
require(!treasury.is_zero(), "Invalid treasury");
|
||||
|
||||
self._admin = msg.sender;
|
||||
self._treasury = treasury;
|
||||
}
|
||||
|
||||
// ========== 资产池管理 ==========
|
||||
|
||||
/// 创建资产池
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
/// - `base_rate`: 基础利率(基点)
|
||||
/// - `optimal_utilization`: 最优利用率(基点)
|
||||
/// - `slope1`: 斜率1(基点)
|
||||
/// - `slope2`: 斜率2(基点)
|
||||
/// - `collateral_factor`: 抵押率(基点)
|
||||
/// - `liquidation_threshold`: 清算阈值(基点)
|
||||
/// - `liquidation_bonus`: 清算奖励(基点)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn create_pool(
|
||||
asset: Address,
|
||||
base_rate: u16,
|
||||
optimal_utilization: u16,
|
||||
slope1: u16,
|
||||
slope2: u16,
|
||||
collateral_factor: u16,
|
||||
liquidation_threshold: u16,
|
||||
liquidation_bonus: u16
|
||||
) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(!self._pools.contains_key(asset), "Pool already exists");
|
||||
require(collateral_factor <= 10000, "Invalid collateral factor");
|
||||
require(liquidation_threshold <= 10000, "Invalid liquidation threshold");
|
||||
require(collateral_factor < liquidation_threshold, "CF must be < LT");
|
||||
|
||||
let pool = AssetPool {
|
||||
asset: asset,
|
||||
total_deposits: 0,
|
||||
total_borrows: 0,
|
||||
available_liquidity: 0,
|
||||
base_rate: base_rate,
|
||||
optimal_utilization: optimal_utilization,
|
||||
slope1: slope1,
|
||||
slope2: slope2,
|
||||
collateral_factor: collateral_factor,
|
||||
liquidation_threshold: liquidation_threshold,
|
||||
liquidation_bonus: liquidation_bonus
|
||||
};
|
||||
|
||||
self._pools[asset] = pool;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取资产池信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `AssetPool`: 资产池信息
|
||||
pub fn get_pool(asset: Address) -> AssetPool {
|
||||
require(self._pools.contains_key(asset), "Pool not found");
|
||||
return self._pools[asset];
|
||||
}
|
||||
|
||||
/// 计算当前借款利率
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u16`: 借款利率(基点)
|
||||
pub fn get_borrow_rate(asset: Address) -> u16 {
|
||||
require(self._pools.contains_key(asset), "Pool not found");
|
||||
|
||||
let pool = self._pools[asset];
|
||||
|
||||
if pool.total_deposits == 0 {
|
||||
return pool.base_rate;
|
||||
}
|
||||
|
||||
// 计算利用率
|
||||
let utilization = safe_mul(pool.total_borrows, 10000) / pool.total_deposits;
|
||||
|
||||
if utilization <= pool.optimal_utilization as u256 {
|
||||
// 利用率 <= 最优利用率
|
||||
// rate = base_rate + (utilization / optimal) * slope1
|
||||
let rate_increase = safe_mul(utilization, pool.slope1 as u256) / pool.optimal_utilization as u256;
|
||||
return pool.base_rate + rate_increase as u16;
|
||||
} else {
|
||||
// 利用率 > 最优利用率
|
||||
// rate = base_rate + slope1 + ((utilization - optimal) / (10000 - optimal)) * slope2
|
||||
let excess_utilization = safe_sub(utilization, pool.optimal_utilization as u256);
|
||||
let excess_range = safe_sub(10000, pool.optimal_utilization as u256);
|
||||
let rate_increase = safe_mul(excess_utilization, pool.slope2 as u256) / excess_range;
|
||||
return pool.base_rate + pool.slope1 + rate_increase as u16;
|
||||
}
|
||||
}
|
||||
|
||||
/// 计算存款利率
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u16`: 存款利率(基点)
|
||||
pub fn get_deposit_rate(asset: Address) -> u16 {
|
||||
require(self._pools.contains_key(asset), "Pool not found");
|
||||
|
||||
let pool = self._pools[asset];
|
||||
|
||||
if pool.total_deposits == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 存款利率 = 借款利率 * 利用率
|
||||
let borrow_rate = self.get_borrow_rate(asset);
|
||||
let utilization = safe_mul(pool.total_borrows, 10000) / pool.total_deposits;
|
||||
|
||||
return safe_mul(borrow_rate as u256, utilization) / 10000 as u16;
|
||||
}
|
||||
|
||||
// ========== 存款和提款 ==========
|
||||
|
||||
/// 存款
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
/// - `amount`: 数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn deposit(asset: Address, amount: u256) -> bool {
|
||||
require(self._pools.contains_key(asset), "Pool not found");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
// 实际实现需要调用资产合约的transferFrom
|
||||
|
||||
// 更新资产池
|
||||
let mut pool = self._pools[asset];
|
||||
pool.total_deposits = safe_add(pool.total_deposits, amount);
|
||||
pool.available_liquidity = safe_add(pool.available_liquidity, amount);
|
||||
self._pools[asset] = pool;
|
||||
|
||||
// 更新用户账户
|
||||
if !self._accounts.contains_key(msg.sender) {
|
||||
self._accounts[msg.sender] = UserAccount {
|
||||
user: msg.sender,
|
||||
deposits: Map::new(),
|
||||
borrows: Map::new(),
|
||||
total_collateral_value: 0,
|
||||
total_borrow_value: 0,
|
||||
health_factor: 10000
|
||||
};
|
||||
}
|
||||
|
||||
let mut account = self._accounts[msg.sender];
|
||||
let current_deposit = account.deposits.get(asset).unwrap_or(0);
|
||||
account.deposits[asset] = safe_add(current_deposit, amount);
|
||||
self._accounts[msg.sender] = account;
|
||||
|
||||
emit Deposit {
|
||||
user: msg.sender,
|
||||
asset: asset,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 提款
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
/// - `amount`: 数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn withdraw(asset: Address, amount: u256) -> bool {
|
||||
require(self._pools.contains_key(asset), "Pool not found");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
require(self._accounts.contains_key(msg.sender), "No account");
|
||||
|
||||
let mut account = self._accounts[msg.sender];
|
||||
let deposit = account.deposits.get(asset).unwrap_or(0);
|
||||
require(deposit >= amount, "Insufficient deposit");
|
||||
|
||||
// 检查是否有足够的流动性
|
||||
let pool = self._pools[asset];
|
||||
require(pool.available_liquidity >= amount, "Insufficient liquidity");
|
||||
|
||||
// 检查健康因子
|
||||
// 提款后健康因子不能低于1.0
|
||||
let new_health_factor = self._calculate_health_factor_after_withdraw(
|
||||
msg.sender,
|
||||
asset,
|
||||
amount
|
||||
);
|
||||
require(new_health_factor >= 10000, "Would break health factor");
|
||||
|
||||
// 更新资产池
|
||||
let mut pool = self._pools[asset];
|
||||
pool.total_deposits = safe_sub(pool.total_deposits, amount);
|
||||
pool.available_liquidity = safe_sub(pool.available_liquidity, amount);
|
||||
self._pools[asset] = pool;
|
||||
|
||||
// 更新用户账户
|
||||
account.deposits[asset] = safe_sub(deposit, amount);
|
||||
self._accounts[msg.sender] = account;
|
||||
|
||||
// 实际实现需要调用资产合约的transfer
|
||||
|
||||
emit Withdraw {
|
||||
user: msg.sender,
|
||||
asset: asset,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 借款和还款 ==========
|
||||
|
||||
/// 借款
|
||||
///
|
||||
/// # 参数
|
||||
/// - `collateral_asset`: 抵押资产
|
||||
/// - `collateral_amount`: 抵押数量
|
||||
/// - `borrow_asset`: 借款资产
|
||||
/// - `borrow_amount`: 借款数量
|
||||
/// - `duration`: 借款期限(秒)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 贷款ID
|
||||
pub fn borrow(
|
||||
collateral_asset: Address,
|
||||
collateral_amount: u256,
|
||||
borrow_asset: Address,
|
||||
borrow_amount: u256,
|
||||
duration: Duration
|
||||
) -> Hash {
|
||||
require(self._pools.contains_key(collateral_asset), "Collateral pool not found");
|
||||
require(self._pools.contains_key(borrow_asset), "Borrow pool not found");
|
||||
require(collateral_amount > 0, "Collateral must be positive");
|
||||
require(borrow_amount > 0, "Borrow amount must be positive");
|
||||
require(duration > 0, "Duration must be positive");
|
||||
|
||||
let collateral_pool = self._pools[collateral_asset];
|
||||
let borrow_pool = self._pools[borrow_asset];
|
||||
|
||||
// 检查流动性
|
||||
require(
|
||||
borrow_pool.available_liquidity >= borrow_amount,
|
||||
"Insufficient liquidity"
|
||||
);
|
||||
|
||||
// 计算抵押价值和借款价值
|
||||
let collateral_price = self._get_price(collateral_asset);
|
||||
let borrow_price = self._get_price(borrow_asset);
|
||||
|
||||
let collateral_value = safe_mul(collateral_amount, collateral_price) / 1e18;
|
||||
let borrow_value = safe_mul(borrow_amount, borrow_price) / 1e18;
|
||||
|
||||
// 检查抵押率
|
||||
let max_borrow_value = safe_mul(
|
||||
collateral_value,
|
||||
collateral_pool.collateral_factor as u256
|
||||
) / 10000;
|
||||
|
||||
require(borrow_value <= max_borrow_value, "Insufficient collateral");
|
||||
|
||||
// 计算利率
|
||||
let interest_rate = self.get_borrow_rate(borrow_asset);
|
||||
|
||||
// 生成贷款ID
|
||||
let loan_id = self._generate_loan_id(msg.sender, collateral_asset, borrow_asset);
|
||||
|
||||
let loan = Loan {
|
||||
loan_id: loan_id,
|
||||
borrower: msg.sender,
|
||||
collateral_asset: collateral_asset,
|
||||
collateral_amount: collateral_amount,
|
||||
borrow_asset: borrow_asset,
|
||||
borrow_amount: borrow_amount,
|
||||
interest_rate: interest_rate,
|
||||
rate_mode: InterestRateMode::Variable,
|
||||
created_at: block.timestamp,
|
||||
due_date: block.timestamp + duration,
|
||||
repaid_principal: 0,
|
||||
repaid_interest: 0,
|
||||
status: LoanStatus::Active,
|
||||
last_updated: block.timestamp
|
||||
};
|
||||
|
||||
self._loans[loan_id] = loan;
|
||||
|
||||
// 更新用户贷款索引
|
||||
if !self._user_loans.contains_key(msg.sender) {
|
||||
self._user_loans[msg.sender] = Vec::new();
|
||||
}
|
||||
self._user_loans[msg.sender].push(loan_id);
|
||||
|
||||
// 更新资产池
|
||||
let mut borrow_pool = self._pools[borrow_asset];
|
||||
borrow_pool.total_borrows = safe_add(borrow_pool.total_borrows, borrow_amount);
|
||||
borrow_pool.available_liquidity = safe_sub(borrow_pool.available_liquidity, borrow_amount);
|
||||
self._pools[borrow_asset] = borrow_pool;
|
||||
|
||||
// 转移抵押资产(实际需要调用资产合约)
|
||||
// 转移借款资产给借款人(实际需要调用资产合约)
|
||||
|
||||
emit Borrow {
|
||||
loan_id: loan_id,
|
||||
borrower: msg.sender,
|
||||
collateral_asset: collateral_asset,
|
||||
collateral_amount: collateral_amount,
|
||||
borrow_asset: borrow_asset,
|
||||
borrow_amount: borrow_amount,
|
||||
interest_rate: interest_rate,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return loan_id;
|
||||
}
|
||||
|
||||
/// 还款
|
||||
///
|
||||
/// # 参数
|
||||
/// - `loan_id`: 贷款ID
|
||||
/// - `amount`: 还款数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn repay(loan_id: Hash, amount: u256) -> bool {
|
||||
require(self._loans.contains_key(loan_id), "Loan not found");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
let mut loan = self._loans[loan_id];
|
||||
require(loan.borrower == msg.sender, "Not the borrower");
|
||||
require(loan.status == LoanStatus::Active, "Loan not active");
|
||||
|
||||
// 计算应还利息
|
||||
let interest = self._calculate_interest(loan_id);
|
||||
let total_debt = safe_add(
|
||||
safe_sub(loan.borrow_amount, loan.repaid_principal),
|
||||
safe_sub(interest, loan.repaid_interest)
|
||||
);
|
||||
|
||||
require(amount <= total_debt, "Amount exceeds debt");
|
||||
|
||||
// 先还利息,再还本金
|
||||
let remaining_interest = safe_sub(interest, loan.repaid_interest);
|
||||
|
||||
let interest_payment = if amount <= remaining_interest {
|
||||
amount
|
||||
} else {
|
||||
remaining_interest
|
||||
};
|
||||
|
||||
let principal_payment = safe_sub(amount, interest_payment);
|
||||
|
||||
loan.repaid_interest = safe_add(loan.repaid_interest, interest_payment);
|
||||
loan.repaid_principal = safe_add(loan.repaid_principal, principal_payment);
|
||||
loan.last_updated = block.timestamp;
|
||||
|
||||
// 检查是否还清
|
||||
if loan.repaid_principal == loan.borrow_amount &&
|
||||
loan.repaid_interest == interest {
|
||||
loan.status = LoanStatus::Repaid;
|
||||
|
||||
// 返还抵押品(实际需要调用资产合约)
|
||||
}
|
||||
|
||||
self._loans[loan_id] = loan;
|
||||
|
||||
// 更新资产池
|
||||
let mut pool = self._pools[loan.borrow_asset];
|
||||
pool.total_borrows = safe_sub(pool.total_borrows, principal_payment);
|
||||
pool.available_liquidity = safe_add(pool.available_liquidity, amount);
|
||||
self._pools[loan.borrow_asset] = pool;
|
||||
|
||||
emit Repay {
|
||||
loan_id: loan_id,
|
||||
borrower: msg.sender,
|
||||
repaid_principal: principal_payment,
|
||||
repaid_interest: interest_payment,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 清算 ==========
|
||||
|
||||
/// 清算
|
||||
///
|
||||
/// # 参数
|
||||
/// - `loan_id`: 贷款ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn liquidate(loan_id: Hash) -> bool {
|
||||
require(self._loans.contains_key(loan_id), "Loan not found");
|
||||
|
||||
let mut loan = self._loans[loan_id];
|
||||
require(loan.status == LoanStatus::Active, "Loan not active");
|
||||
|
||||
// 检查是否可以清算
|
||||
require(self._is_liquidatable(loan_id), "Cannot liquidate");
|
||||
|
||||
// 计算债务
|
||||
let interest = self._calculate_interest(loan_id);
|
||||
let total_debt = safe_add(
|
||||
safe_sub(loan.borrow_amount, loan.repaid_principal),
|
||||
safe_sub(interest, loan.repaid_interest)
|
||||
);
|
||||
|
||||
// 计算清算奖励
|
||||
let collateral_pool = self._pools[loan.collateral_asset];
|
||||
let liquidation_amount = safe_mul(
|
||||
loan.collateral_amount,
|
||||
(10000 + collateral_pool.liquidation_bonus) as u256
|
||||
) / 10000;
|
||||
|
||||
loan.status = LoanStatus::Liquidated;
|
||||
self._loans[loan_id] = loan;
|
||||
|
||||
// 转移抵押品给清算人(实际需要调用资产合约)
|
||||
// 清算人需要支付债务(实际需要调用资产合约)
|
||||
|
||||
emit Liquidate {
|
||||
loan_id: loan_id,
|
||||
borrower: loan.borrower,
|
||||
liquidator: msg.sender,
|
||||
collateral_liquidated: liquidation_amount,
|
||||
debt_covered: total_debt,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查贷款是否可以清算
|
||||
///
|
||||
/// # 参数
|
||||
/// - `loan_id`: 贷款ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否可以清算
|
||||
pub fn is_liquidatable(loan_id: Hash) -> bool {
|
||||
return self._is_liquidatable(loan_id);
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取贷款信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `loan_id`: 贷款ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Loan`: 贷款信息
|
||||
pub fn get_loan(loan_id: Hash) -> Loan {
|
||||
require(self._loans.contains_key(loan_id), "Loan not found");
|
||||
return self._loans[loan_id];
|
||||
}
|
||||
|
||||
/// 获取用户贷款列表
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 贷款ID列表
|
||||
pub fn get_user_loans(user: Address) -> Vec<Hash> {
|
||||
return self._user_loans.get(user).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 计算应还利息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `loan_id`: 贷款ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 应还利息
|
||||
pub fn calculate_interest(loan_id: Hash) -> u256 {
|
||||
return self._calculate_interest(loan_id);
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成贷款ID
|
||||
fn _generate_loan_id(
|
||||
borrower: Address,
|
||||
collateral_asset: Address,
|
||||
borrow_asset: Address
|
||||
) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(borrower.as_bytes());
|
||||
data.extend(collateral_asset.as_bytes());
|
||||
data.extend(borrow_asset.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 计算利息
|
||||
fn _calculate_interest(loan_id: Hash) -> u256 {
|
||||
let loan = self._loans[loan_id];
|
||||
|
||||
let time_elapsed = safe_sub(block.timestamp, loan.last_updated);
|
||||
let principal = safe_sub(loan.borrow_amount, loan.repaid_principal);
|
||||
|
||||
// 年化利率转换为秒利率
|
||||
// interest = principal * rate * time / (365 * 24 * 3600 * 10000)
|
||||
let interest = safe_mul(
|
||||
safe_mul(principal, loan.interest_rate as u256),
|
||||
time_elapsed
|
||||
) / (365 * 24 * 3600 * 10000);
|
||||
|
||||
return safe_add(loan.repaid_interest, interest);
|
||||
}
|
||||
|
||||
/// 检查是否可以清算
|
||||
fn _is_liquidatable(loan_id: Hash) -> bool {
|
||||
let loan = self._loans[loan_id];
|
||||
|
||||
if loan.status != LoanStatus::Active {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if block.timestamp > loan.due_date {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查健康因子
|
||||
let collateral_pool = self._pools[loan.collateral_asset];
|
||||
let borrow_pool = self._pools[loan.borrow_asset];
|
||||
|
||||
let collateral_price = self._get_price(loan.collateral_asset);
|
||||
let borrow_price = self._get_price(loan.borrow_asset);
|
||||
|
||||
let collateral_value = safe_mul(loan.collateral_amount, collateral_price) / 1e18;
|
||||
|
||||
let interest = self._calculate_interest(loan_id);
|
||||
let total_debt = safe_add(
|
||||
safe_sub(loan.borrow_amount, loan.repaid_principal),
|
||||
safe_sub(interest, loan.repaid_interest)
|
||||
);
|
||||
let debt_value = safe_mul(total_debt, borrow_price) / 1e18;
|
||||
|
||||
// 健康因子 = (抵押价值 * 清算阈值) / 债务价值
|
||||
let health_factor = safe_mul(
|
||||
collateral_value,
|
||||
collateral_pool.liquidation_threshold as u256
|
||||
) / debt_value;
|
||||
|
||||
// 健康因子 < 1.0 可以清算
|
||||
return health_factor < 10000;
|
||||
}
|
||||
|
||||
/// 计算提款后的健康因子
|
||||
fn _calculate_health_factor_after_withdraw(
|
||||
user: Address,
|
||||
asset: Address,
|
||||
amount: u256
|
||||
) -> u16 {
|
||||
// 简化实现,实际需要重新计算所有抵押和借款
|
||||
return 10000;
|
||||
}
|
||||
|
||||
/// 获取价格(简化,实际需要预言机)
|
||||
fn _get_price(asset: Address) -> u256 {
|
||||
return self._prices.get(asset).unwrap_or(1e18);
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 设置价格(简化,实际应该使用预言机)
|
||||
pub fn set_price(asset: Address, price: u256) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._prices[asset] = price;
|
||||
return true;
|
||||
}
|
||||
pub fn repay(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,807 +1,21 @@
|
|||
///! # 流动性池
|
||||
///!
|
||||
///! Liquidity Pool (AMM)
|
||||
///! 提供自动做市商(AMM)机制和流动性管理
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/defi/liquidity.ch
|
||||
|
||||
use utils::math::{safe_mul, safe_div, safe_add, safe_sub, sqrt};
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 流动性池结构
|
||||
// ============================================================================
|
||||
|
||||
/// 流动性池
|
||||
struct LiquidityPool {
|
||||
/// 池ID
|
||||
pool_id: Hash,
|
||||
|
||||
/// 资产A
|
||||
asset_a: Address,
|
||||
|
||||
/// 资产B
|
||||
asset_b: Address,
|
||||
|
||||
/// 资产A储备量
|
||||
reserve_a: u256,
|
||||
|
||||
/// 资产B储备量
|
||||
reserve_b: u256,
|
||||
|
||||
/// LP代币总供应量
|
||||
total_lp_supply: u256,
|
||||
|
||||
/// 手续费率(基点,例如30表示0.3%)
|
||||
fee_rate: u16,
|
||||
|
||||
/// 累计手续费A
|
||||
accumulated_fee_a: u256,
|
||||
|
||||
/// 累计手续费B
|
||||
accumulated_fee_b: u256,
|
||||
|
||||
/// 最后更新时间
|
||||
last_updated: Timestamp,
|
||||
|
||||
/// K值(恒定乘积)
|
||||
k_last: u256
|
||||
pub fn add_liquidity(token_a: Address, token_b: Address, amount_a: u256, amount_b: u256) -> bool {
|
||||
require(!token_a.is_zero(), "Invalid token A");
|
||||
require(!token_b.is_zero(), "Invalid token B");
|
||||
require(amount_a > 0, "Amount A must be positive");
|
||||
require(amount_b > 0, "Amount B must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 流动性提供者信息
|
||||
struct LiquidityProvider {
|
||||
/// 提供者地址
|
||||
provider: Address,
|
||||
|
||||
/// 池ID
|
||||
pool_id: Hash,
|
||||
|
||||
/// LP代币数量
|
||||
lp_tokens: u256,
|
||||
|
||||
/// 提供时间
|
||||
provided_at: Timestamp,
|
||||
|
||||
/// 已领取奖励A
|
||||
claimed_reward_a: u256,
|
||||
|
||||
/// 已领取奖励B
|
||||
claimed_reward_b: u256
|
||||
pub fn remove_liquidity(token_a: Address, token_b: Address, liquidity: u256) -> bool {
|
||||
require(!token_a.is_zero(), "Invalid token A");
|
||||
require(!token_b.is_zero(), "Invalid token B");
|
||||
require(liquidity > 0, "Liquidity must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 交换记录
|
||||
struct SwapRecord {
|
||||
/// 交换ID
|
||||
swap_id: Hash,
|
||||
|
||||
/// 池ID
|
||||
pool_id: Hash,
|
||||
|
||||
/// 交换者
|
||||
swapper: Address,
|
||||
|
||||
/// 输入资产
|
||||
asset_in: Address,
|
||||
|
||||
/// 输入数量
|
||||
amount_in: u256,
|
||||
|
||||
/// 输出资产
|
||||
asset_out: Address,
|
||||
|
||||
/// 输出数量
|
||||
amount_out: u256,
|
||||
|
||||
/// 手续费
|
||||
fee: u256,
|
||||
|
||||
/// 时间戳
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 流动性事件
|
||||
// ============================================================================
|
||||
|
||||
/// 添加流动性事件
|
||||
event AddLiquidity {
|
||||
pool_id: Hash,
|
||||
provider: Address,
|
||||
amount_a: u256,
|
||||
amount_b: u256,
|
||||
lp_tokens: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 移除流动性事件
|
||||
event RemoveLiquidity {
|
||||
pool_id: Hash,
|
||||
provider: Address,
|
||||
amount_a: u256,
|
||||
amount_b: u256,
|
||||
lp_tokens: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 交换事件
|
||||
event Swap {
|
||||
swap_id: Hash,
|
||||
pool_id: Hash,
|
||||
swapper: Address,
|
||||
asset_in: Address,
|
||||
amount_in: u256,
|
||||
asset_out: Address,
|
||||
amount_out: u256,
|
||||
fee: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 领取奖励事件
|
||||
event ClaimRewards {
|
||||
pool_id: Hash,
|
||||
provider: Address,
|
||||
reward_a: u256,
|
||||
reward_b: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 流动性池协议
|
||||
// ============================================================================
|
||||
|
||||
/// 流动性池协议
|
||||
certificate LiquidityPoolProtocol {
|
||||
/// 流动性池 (pool_id => pool)
|
||||
let _pools: Map<Hash, LiquidityPool>;
|
||||
|
||||
/// 流动性提供者 (provider => pool_id => lp_info)
|
||||
let _providers: Map<Address, Map<Hash, LiquidityProvider>>;
|
||||
|
||||
/// 交换记录 (swap_id => record)
|
||||
let _swaps: Map<Hash, SwapRecord>;
|
||||
|
||||
/// 池索引 (asset_a => asset_b => pool_id)
|
||||
let _pool_index: Map<Address, Map<Address, Hash>>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 默认手续费率(基点)
|
||||
let _default_fee_rate: u16;
|
||||
|
||||
/// 最小流动性(防止除零)
|
||||
let _minimum_liquidity: u256;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor(fee_rate: u16) {
|
||||
require(fee_rate <= 1000, "Fee rate too high"); // 最高10%
|
||||
|
||||
self._admin = msg.sender;
|
||||
self._default_fee_rate = fee_rate;
|
||||
self._minimum_liquidity = 1000; // 最小流动性锁定
|
||||
}
|
||||
|
||||
// ========== 池管理 ==========
|
||||
|
||||
/// 创建流动性池
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_a`: 资产A地址
|
||||
/// - `asset_b`: 资产B地址
|
||||
/// - `initial_a`: 初始资产A数量
|
||||
/// - `initial_b`: 初始资产B数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 池ID
|
||||
pub fn create_pool(
|
||||
asset_a: Address,
|
||||
asset_b: Address,
|
||||
initial_a: u256,
|
||||
initial_b: u256
|
||||
) -> Hash {
|
||||
require(!asset_a.is_zero(), "Invalid asset A");
|
||||
require(!asset_b.is_zero(), "Invalid asset B");
|
||||
require(asset_a != asset_b, "Assets must be different");
|
||||
require(initial_a > 0, "Initial A must be positive");
|
||||
require(initial_b > 0, "Initial B must be positive");
|
||||
|
||||
// 确保资产顺序一致(A < B)
|
||||
let (token0, token1, amount0, amount1) = if asset_a < asset_b {
|
||||
(asset_a, asset_b, initial_a, initial_b)
|
||||
} else {
|
||||
(asset_b, asset_a, initial_b, initial_a)
|
||||
};
|
||||
|
||||
// 检查池是否已存在
|
||||
if let Some(existing_pools) = self._pool_index.get(token0) {
|
||||
require(!existing_pools.contains_key(token1), "Pool already exists");
|
||||
}
|
||||
|
||||
// 生成池ID
|
||||
let pool_id = self._generate_pool_id(token0, token1);
|
||||
|
||||
// 计算初始LP代币数量(几何平均数)
|
||||
let initial_lp = sqrt(safe_mul(amount0, amount1));
|
||||
require(initial_lp > self._minimum_liquidity, "Insufficient initial liquidity");
|
||||
|
||||
// 锁定最小流动性
|
||||
let lp_to_provider = safe_sub(initial_lp, self._minimum_liquidity);
|
||||
|
||||
let pool = LiquidityPool {
|
||||
pool_id: pool_id,
|
||||
asset_a: token0,
|
||||
asset_b: token1,
|
||||
reserve_a: amount0,
|
||||
reserve_b: amount1,
|
||||
total_lp_supply: initial_lp,
|
||||
fee_rate: self._default_fee_rate,
|
||||
accumulated_fee_a: 0,
|
||||
accumulated_fee_b: 0,
|
||||
last_updated: block.timestamp,
|
||||
k_last: safe_mul(amount0, amount1)
|
||||
};
|
||||
|
||||
self._pools[pool_id] = pool;
|
||||
|
||||
// 更新索引
|
||||
if !self._pool_index.contains_key(token0) {
|
||||
self._pool_index[token0] = Map::new();
|
||||
}
|
||||
self._pool_index[token0][token1] = pool_id;
|
||||
|
||||
// 记录流动性提供者
|
||||
if !self._providers.contains_key(msg.sender) {
|
||||
self._providers[msg.sender] = Map::new();
|
||||
}
|
||||
|
||||
let lp_info = LiquidityProvider {
|
||||
provider: msg.sender,
|
||||
pool_id: pool_id,
|
||||
lp_tokens: lp_to_provider,
|
||||
provided_at: block.timestamp,
|
||||
claimed_reward_a: 0,
|
||||
claimed_reward_b: 0
|
||||
};
|
||||
|
||||
self._providers[msg.sender][pool_id] = lp_info;
|
||||
|
||||
// 实际需要转移资产到池中
|
||||
|
||||
emit AddLiquidity {
|
||||
pool_id: pool_id,
|
||||
provider: msg.sender,
|
||||
amount_a: amount0,
|
||||
amount_b: amount1,
|
||||
lp_tokens: lp_to_provider,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return pool_id;
|
||||
}
|
||||
|
||||
/// 获取池信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `LiquidityPool`: 池信息
|
||||
pub fn get_pool(pool_id: Hash) -> LiquidityPool {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
return self._pools[pool_id];
|
||||
}
|
||||
|
||||
/// 通过资产对查找池
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_a`: 资产A地址
|
||||
/// - `asset_b`: 资产B地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<Hash>`: 池ID
|
||||
pub fn find_pool(asset_a: Address, asset_b: Address) -> Option<Hash> {
|
||||
let (token0, token1) = if asset_a < asset_b {
|
||||
(asset_a, asset_b)
|
||||
} else {
|
||||
(asset_b, asset_a)
|
||||
};
|
||||
|
||||
return self._pool_index.get(token0)
|
||||
.and_then(|m| m.get(token1));
|
||||
}
|
||||
|
||||
// ========== 添加和移除流动性 ==========
|
||||
|
||||
/// 添加流动性
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `amount_a`: 资产A数量
|
||||
/// - `amount_b`: 资产B数量
|
||||
/// - `min_lp_tokens`: 最小LP代币数量(滑点保护)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 获得的LP代币数量
|
||||
pub fn add_liquidity(
|
||||
pool_id: Hash,
|
||||
amount_a: u256,
|
||||
amount_b: u256,
|
||||
min_lp_tokens: u256
|
||||
) -> u256 {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
require(amount_a > 0, "Amount A must be positive");
|
||||
require(amount_b > 0, "Amount B must be positive");
|
||||
|
||||
let mut pool = self._pools[pool_id];
|
||||
|
||||
// 计算最优添加比例
|
||||
let optimal_b = safe_mul(amount_a, pool.reserve_b) / pool.reserve_a;
|
||||
|
||||
let (final_a, final_b) = if optimal_b <= amount_b {
|
||||
(amount_a, optimal_b)
|
||||
} else {
|
||||
let optimal_a = safe_mul(amount_b, pool.reserve_a) / pool.reserve_b;
|
||||
(optimal_a, amount_b)
|
||||
};
|
||||
|
||||
// 计算LP代币数量
|
||||
let lp_tokens = if pool.total_lp_supply == 0 {
|
||||
sqrt(safe_mul(final_a, final_b))
|
||||
} else {
|
||||
let lp_a = safe_mul(final_a, pool.total_lp_supply) / pool.reserve_a;
|
||||
let lp_b = safe_mul(final_b, pool.total_lp_supply) / pool.reserve_b;
|
||||
if lp_a < lp_b { lp_a } else { lp_b }
|
||||
};
|
||||
|
||||
require(lp_tokens >= min_lp_tokens, "Slippage too high");
|
||||
|
||||
// 更新池状态
|
||||
pool.reserve_a = safe_add(pool.reserve_a, final_a);
|
||||
pool.reserve_b = safe_add(pool.reserve_b, final_b);
|
||||
pool.total_lp_supply = safe_add(pool.total_lp_supply, lp_tokens);
|
||||
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
|
||||
pool.last_updated = block.timestamp;
|
||||
|
||||
self._pools[pool_id] = pool;
|
||||
|
||||
// 更新流动性提供者信息
|
||||
if !self._providers.contains_key(msg.sender) {
|
||||
self._providers[msg.sender] = Map::new();
|
||||
}
|
||||
|
||||
if let Some(mut lp_info) = self._providers[msg.sender].get(pool_id) {
|
||||
lp_info.lp_tokens = safe_add(lp_info.lp_tokens, lp_tokens);
|
||||
self._providers[msg.sender][pool_id] = lp_info;
|
||||
} else {
|
||||
let lp_info = LiquidityProvider {
|
||||
provider: msg.sender,
|
||||
pool_id: pool_id,
|
||||
lp_tokens: lp_tokens,
|
||||
provided_at: block.timestamp,
|
||||
claimed_reward_a: 0,
|
||||
claimed_reward_b: 0
|
||||
};
|
||||
self._providers[msg.sender][pool_id] = lp_info;
|
||||
}
|
||||
|
||||
// 实际需要转移资产到池中
|
||||
|
||||
emit AddLiquidity {
|
||||
pool_id: pool_id,
|
||||
provider: msg.sender,
|
||||
amount_a: final_a,
|
||||
amount_b: final_b,
|
||||
lp_tokens: lp_tokens,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return lp_tokens;
|
||||
}
|
||||
|
||||
/// 移除流动性
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `lp_tokens`: LP代币数量
|
||||
/// - `min_amount_a`: 最小资产A数量(滑点保护)
|
||||
/// - `min_amount_b`: 最小资产B数量(滑点保护)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `(u256, u256)`: (资产A数量, 资产B数量)
|
||||
pub fn remove_liquidity(
|
||||
pool_id: Hash,
|
||||
lp_tokens: u256,
|
||||
min_amount_a: u256,
|
||||
min_amount_b: u256
|
||||
) -> (u256, u256) {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
require(lp_tokens > 0, "LP tokens must be positive");
|
||||
require(self._providers.contains_key(msg.sender), "No liquidity provided");
|
||||
require(
|
||||
self._providers[msg.sender].contains_key(pool_id),
|
||||
"No liquidity in this pool"
|
||||
);
|
||||
|
||||
let mut lp_info = self._providers[msg.sender][pool_id];
|
||||
require(lp_info.lp_tokens >= lp_tokens, "Insufficient LP tokens");
|
||||
|
||||
let mut pool = self._pools[pool_id];
|
||||
|
||||
// 计算可取回的资产数量
|
||||
let amount_a = safe_mul(lp_tokens, pool.reserve_a) / pool.total_lp_supply;
|
||||
let amount_b = safe_mul(lp_tokens, pool.reserve_b) / pool.total_lp_supply;
|
||||
|
||||
require(amount_a >= min_amount_a, "Slippage too high for A");
|
||||
require(amount_b >= min_amount_b, "Slippage too high for B");
|
||||
|
||||
// 更新池状态
|
||||
pool.reserve_a = safe_sub(pool.reserve_a, amount_a);
|
||||
pool.reserve_b = safe_sub(pool.reserve_b, amount_b);
|
||||
pool.total_lp_supply = safe_sub(pool.total_lp_supply, lp_tokens);
|
||||
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
|
||||
pool.last_updated = block.timestamp;
|
||||
|
||||
self._pools[pool_id] = pool;
|
||||
|
||||
// 更新流动性提供者信息
|
||||
lp_info.lp_tokens = safe_sub(lp_info.lp_tokens, lp_tokens);
|
||||
self._providers[msg.sender][pool_id] = lp_info;
|
||||
|
||||
// 实际需要转移资产给提供者
|
||||
|
||||
emit RemoveLiquidity {
|
||||
pool_id: pool_id,
|
||||
provider: msg.sender,
|
||||
amount_a: amount_a,
|
||||
amount_b: amount_b,
|
||||
lp_tokens: lp_tokens,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return (amount_a, amount_b);
|
||||
}
|
||||
|
||||
// ========== 交换 ==========
|
||||
|
||||
/// 交换(精确输入)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `asset_in`: 输入资产
|
||||
/// - `amount_in`: 输入数量
|
||||
/// - `min_amount_out`: 最小输出数量(滑点保护)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 输出数量
|
||||
pub fn swap_exact_input(
|
||||
pool_id: Hash,
|
||||
asset_in: Address,
|
||||
amount_in: u256,
|
||||
min_amount_out: u256
|
||||
) -> u256 {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
require(amount_in > 0, "Amount in must be positive");
|
||||
|
||||
let mut pool = self._pools[pool_id];
|
||||
|
||||
// 确定输入输出资产
|
||||
let (reserve_in, reserve_out, asset_out) = if asset_in == pool.asset_a {
|
||||
(pool.reserve_a, pool.reserve_b, pool.asset_b)
|
||||
} else if asset_in == pool.asset_b {
|
||||
(pool.reserve_b, pool.reserve_a, pool.asset_a)
|
||||
} else {
|
||||
revert("Invalid asset");
|
||||
};
|
||||
|
||||
// 计算输出数量(扣除手续费)
|
||||
let amount_in_with_fee = safe_mul(amount_in, (10000 - pool.fee_rate) as u256);
|
||||
let numerator = safe_mul(amount_in_with_fee, reserve_out);
|
||||
let denominator = safe_add(safe_mul(reserve_in, 10000), amount_in_with_fee);
|
||||
let amount_out = numerator / denominator;
|
||||
|
||||
require(amount_out >= min_amount_out, "Slippage too high");
|
||||
require(amount_out < reserve_out, "Insufficient liquidity");
|
||||
|
||||
// 计算手续费
|
||||
let fee = safe_mul(amount_in, pool.fee_rate as u256) / 10000;
|
||||
|
||||
// 更新储备量
|
||||
if asset_in == pool.asset_a {
|
||||
pool.reserve_a = safe_add(pool.reserve_a, amount_in);
|
||||
pool.reserve_b = safe_sub(pool.reserve_b, amount_out);
|
||||
pool.accumulated_fee_a = safe_add(pool.accumulated_fee_a, fee);
|
||||
} else {
|
||||
pool.reserve_b = safe_add(pool.reserve_b, amount_in);
|
||||
pool.reserve_a = safe_sub(pool.reserve_a, amount_out);
|
||||
pool.accumulated_fee_b = safe_add(pool.accumulated_fee_b, fee);
|
||||
}
|
||||
|
||||
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
|
||||
pool.last_updated = block.timestamp;
|
||||
|
||||
self._pools[pool_id] = pool;
|
||||
|
||||
// 生成交换ID
|
||||
let swap_id = self._generate_swap_id(pool_id, msg.sender);
|
||||
|
||||
// 记录交换
|
||||
let swap_record = SwapRecord {
|
||||
swap_id: swap_id,
|
||||
pool_id: pool_id,
|
||||
swapper: msg.sender,
|
||||
asset_in: asset_in,
|
||||
amount_in: amount_in,
|
||||
asset_out: asset_out,
|
||||
amount_out: amount_out,
|
||||
fee: fee,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
self._swaps[swap_id] = swap_record;
|
||||
|
||||
// 实际需要转移资产
|
||||
|
||||
emit Swap {
|
||||
swap_id: swap_id,
|
||||
pool_id: pool_id,
|
||||
swapper: msg.sender,
|
||||
asset_in: asset_in,
|
||||
amount_in: amount_in,
|
||||
asset_out: asset_out,
|
||||
amount_out: amount_out,
|
||||
fee: fee,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return amount_out;
|
||||
}
|
||||
|
||||
/// 交换(精确输出)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `asset_out`: 输出资产
|
||||
/// - `amount_out`: 输出数量
|
||||
/// - `max_amount_in`: 最大输入数量(滑点保护)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 输入数量
|
||||
pub fn swap_exact_output(
|
||||
pool_id: Hash,
|
||||
asset_out: Address,
|
||||
amount_out: u256,
|
||||
max_amount_in: u256
|
||||
) -> u256 {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
require(amount_out > 0, "Amount out must be positive");
|
||||
|
||||
let mut pool = self._pools[pool_id];
|
||||
|
||||
// 确定输入输出资产
|
||||
let (reserve_in, reserve_out, asset_in) = if asset_out == pool.asset_a {
|
||||
(pool.reserve_b, pool.reserve_a, pool.asset_b)
|
||||
} else if asset_out == pool.asset_b {
|
||||
(pool.reserve_a, pool.reserve_b, pool.asset_a)
|
||||
} else {
|
||||
revert("Invalid asset");
|
||||
};
|
||||
|
||||
require(amount_out < reserve_out, "Insufficient liquidity");
|
||||
|
||||
// 计算输入数量(包含手续费)
|
||||
let numerator = safe_mul(safe_mul(reserve_in, amount_out), 10000);
|
||||
let denominator = safe_mul(
|
||||
safe_sub(reserve_out, amount_out),
|
||||
(10000 - pool.fee_rate) as u256
|
||||
);
|
||||
let amount_in = safe_add(numerator / denominator, 1); // 向上取整
|
||||
|
||||
require(amount_in <= max_amount_in, "Slippage too high");
|
||||
|
||||
// 计算手续费
|
||||
let fee = safe_mul(amount_in, pool.fee_rate as u256) / 10000;
|
||||
|
||||
// 更新储备量
|
||||
if asset_out == pool.asset_a {
|
||||
pool.reserve_b = safe_add(pool.reserve_b, amount_in);
|
||||
pool.reserve_a = safe_sub(pool.reserve_a, amount_out);
|
||||
pool.accumulated_fee_b = safe_add(pool.accumulated_fee_b, fee);
|
||||
} else {
|
||||
pool.reserve_a = safe_add(pool.reserve_a, amount_in);
|
||||
pool.reserve_b = safe_sub(pool.reserve_b, amount_out);
|
||||
pool.accumulated_fee_a = safe_add(pool.accumulated_fee_a, fee);
|
||||
}
|
||||
|
||||
pool.k_last = safe_mul(pool.reserve_a, pool.reserve_b);
|
||||
pool.last_updated = block.timestamp;
|
||||
|
||||
self._pools[pool_id] = pool;
|
||||
|
||||
// 生成交换ID
|
||||
let swap_id = self._generate_swap_id(pool_id, msg.sender);
|
||||
|
||||
// 记录交换
|
||||
let swap_record = SwapRecord {
|
||||
swap_id: swap_id,
|
||||
pool_id: pool_id,
|
||||
swapper: msg.sender,
|
||||
asset_in: asset_in,
|
||||
amount_in: amount_in,
|
||||
asset_out: asset_out,
|
||||
amount_out: amount_out,
|
||||
fee: fee,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
self._swaps[swap_id] = swap_record;
|
||||
|
||||
emit Swap {
|
||||
swap_id: swap_id,
|
||||
pool_id: pool_id,
|
||||
swapper: msg.sender,
|
||||
asset_in: asset_in,
|
||||
amount_in: amount_in,
|
||||
asset_out: asset_out,
|
||||
amount_out: amount_out,
|
||||
fee: fee,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return amount_in;
|
||||
}
|
||||
|
||||
/// 获取输出数量(不执行交换)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `asset_in`: 输入资产
|
||||
/// - `amount_in`: 输入数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 输出数量
|
||||
pub fn get_amount_out(
|
||||
pool_id: Hash,
|
||||
asset_in: Address,
|
||||
amount_in: u256
|
||||
) -> u256 {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
|
||||
let pool = self._pools[pool_id];
|
||||
|
||||
let (reserve_in, reserve_out) = if asset_in == pool.asset_a {
|
||||
(pool.reserve_a, pool.reserve_b)
|
||||
} else {
|
||||
(pool.reserve_b, pool.reserve_a)
|
||||
};
|
||||
|
||||
let amount_in_with_fee = safe_mul(amount_in, (10000 - pool.fee_rate) as u256);
|
||||
let numerator = safe_mul(amount_in_with_fee, reserve_out);
|
||||
let denominator = safe_add(safe_mul(reserve_in, 10000), amount_in_with_fee);
|
||||
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
// ========== 奖励管理 ==========
|
||||
|
||||
/// 计算待领取奖励
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
/// - `provider`: 提供者地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `(u256, u256)`: (奖励A, 奖励B)
|
||||
pub fn calculate_rewards(
|
||||
pool_id: Hash,
|
||||
provider: Address
|
||||
) -> (u256, u256) {
|
||||
require(self._pools.contains_key(pool_id), "Pool not found");
|
||||
require(self._providers.contains_key(provider), "No liquidity provided");
|
||||
require(
|
||||
self._providers[provider].contains_key(pool_id),
|
||||
"No liquidity in this pool"
|
||||
);
|
||||
|
||||
let pool = self._pools[pool_id];
|
||||
let lp_info = self._providers[provider][pool_id];
|
||||
|
||||
// 计算份额
|
||||
let share = safe_mul(lp_info.lp_tokens, 1e18) / pool.total_lp_supply;
|
||||
|
||||
// 计算奖励
|
||||
let reward_a = safe_sub(
|
||||
safe_mul(pool.accumulated_fee_a, share) / 1e18,
|
||||
lp_info.claimed_reward_a
|
||||
);
|
||||
|
||||
let reward_b = safe_sub(
|
||||
safe_mul(pool.accumulated_fee_b, share) / 1e18,
|
||||
lp_info.claimed_reward_b
|
||||
);
|
||||
|
||||
return (reward_a, reward_b);
|
||||
}
|
||||
|
||||
/// 领取奖励
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pool_id`: 池ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `(u256, u256)`: (奖励A, 奖励B)
|
||||
pub fn claim_rewards(pool_id: Hash) -> (u256, u256) {
|
||||
let (reward_a, reward_b) = self.calculate_rewards(pool_id, msg.sender);
|
||||
|
||||
require(reward_a > 0 || reward_b > 0, "No rewards to claim");
|
||||
|
||||
// 更新已领取奖励
|
||||
let mut lp_info = self._providers[msg.sender][pool_id];
|
||||
lp_info.claimed_reward_a = safe_add(lp_info.claimed_reward_a, reward_a);
|
||||
lp_info.claimed_reward_b = safe_add(lp_info.claimed_reward_b, reward_b);
|
||||
self._providers[msg.sender][pool_id] = lp_info;
|
||||
|
||||
// 实际需要转移奖励
|
||||
|
||||
emit ClaimRewards {
|
||||
pool_id: pool_id,
|
||||
provider: msg.sender,
|
||||
reward_a: reward_a,
|
||||
reward_b: reward_b,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return (reward_a, reward_b);
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取流动性提供者信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `provider`: 提供者地址
|
||||
/// - `pool_id`: 池ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<LiquidityProvider>`: 提供者信息
|
||||
pub fn get_provider_info(
|
||||
provider: Address,
|
||||
pool_id: Hash
|
||||
) -> Option<LiquidityProvider> {
|
||||
return self._providers.get(provider)
|
||||
.and_then(|m| m.get(pool_id));
|
||||
}
|
||||
|
||||
/// 获取交换记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `swap_id`: 交换ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `SwapRecord`: 交换记录
|
||||
pub fn get_swap(swap_id: Hash) -> SwapRecord {
|
||||
require(self._swaps.contains_key(swap_id), "Swap not found");
|
||||
return self._swaps[swap_id];
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成池ID
|
||||
fn _generate_pool_id(asset_a: Address, asset_b: Address) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(asset_a.as_bytes());
|
||||
data.extend(asset_b.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 生成交换ID
|
||||
fn _generate_swap_id(pool_id: Hash, swapper: Address) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(pool_id.as_bytes());
|
||||
data.extend(swapper.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
pub fn swap(token_in: Address, token_out: Address, amount_in: u256) -> u256 {
|
||||
require(!token_in.is_zero(), "Invalid input token");
|
||||
require(!token_out.is_zero(), "Invalid output token");
|
||||
require(amount_in > 0, "Amount must be positive");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,875 +1,15 @@
|
|||
///! # 去中心化交易市场
|
||||
///!
|
||||
///! Decentralized Marketplace
|
||||
///! 提供订单簿、撮合引擎和交易功能
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/defi/marketplace.ch
|
||||
|
||||
use utils::math::{safe_mul, safe_div, safe_add, safe_sub};
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 订单类型枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 订单类型
|
||||
pub enum OrderType {
|
||||
/// 限价单
|
||||
Limit,
|
||||
|
||||
/// 市价单
|
||||
Market
|
||||
pub fn list_asset(asset_id: Address, price: u256) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset");
|
||||
require(price > 0, "Price must be positive");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 订单方向
|
||||
pub enum OrderSide {
|
||||
/// 买入
|
||||
Buy,
|
||||
|
||||
/// 卖出
|
||||
Sell
|
||||
pub fn buy_asset(asset_id: Address) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 订单状态
|
||||
pub enum OrderStatus {
|
||||
/// 待成交
|
||||
Open,
|
||||
|
||||
/// 部分成交
|
||||
PartiallyFilled,
|
||||
|
||||
/// 完全成交
|
||||
Filled,
|
||||
|
||||
/// 已取消
|
||||
Cancelled,
|
||||
|
||||
/// 已过期
|
||||
Expired
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 订单结构
|
||||
// ============================================================================
|
||||
|
||||
/// 订单
|
||||
struct Order {
|
||||
/// 订单ID
|
||||
order_id: Hash,
|
||||
|
||||
/// 交易对ID
|
||||
pair_id: Hash,
|
||||
|
||||
/// 订单类型
|
||||
order_type: OrderType,
|
||||
|
||||
/// 订单方向
|
||||
side: OrderSide,
|
||||
|
||||
/// 下单者
|
||||
maker: Address,
|
||||
|
||||
/// 基础资产(要卖出的)
|
||||
base_asset: Address,
|
||||
|
||||
/// 报价资产(要买入的)
|
||||
quote_asset: Address,
|
||||
|
||||
/// 价格(报价资产/基础资产)
|
||||
price: u256,
|
||||
|
||||
/// 数量(基础资产数量)
|
||||
amount: u256,
|
||||
|
||||
/// 已成交数量
|
||||
filled_amount: u256,
|
||||
|
||||
/// 订单状态
|
||||
status: OrderStatus,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 过期时间(可选)
|
||||
expires_at: Option<Timestamp>,
|
||||
|
||||
/// 手续费率(基点)
|
||||
fee_rate: u16
|
||||
}
|
||||
|
||||
/// 交易记录
|
||||
struct Trade {
|
||||
/// 交易ID
|
||||
trade_id: Hash,
|
||||
|
||||
/// 交易对ID
|
||||
pair_id: Hash,
|
||||
|
||||
/// 买单ID
|
||||
buy_order_id: Hash,
|
||||
|
||||
/// 卖单ID
|
||||
sell_order_id: Hash,
|
||||
|
||||
/// 买方
|
||||
buyer: Address,
|
||||
|
||||
/// 卖方
|
||||
seller: Address,
|
||||
|
||||
/// 成交价格
|
||||
price: u256,
|
||||
|
||||
/// 成交数量
|
||||
amount: u256,
|
||||
|
||||
/// 成交时间
|
||||
timestamp: Timestamp,
|
||||
|
||||
/// 买方手续费
|
||||
buyer_fee: u256,
|
||||
|
||||
/// 卖方手续费
|
||||
seller_fee: u256
|
||||
}
|
||||
|
||||
/// 交易对
|
||||
struct TradingPair {
|
||||
/// 交易对ID
|
||||
pair_id: Hash,
|
||||
|
||||
/// 基础资产
|
||||
base_asset: Address,
|
||||
|
||||
/// 报价资产
|
||||
quote_asset: Address,
|
||||
|
||||
/// 最新价格
|
||||
last_price: u256,
|
||||
|
||||
/// 24小时最高价
|
||||
high_24h: u256,
|
||||
|
||||
/// 24小时最低价
|
||||
low_24h: u256,
|
||||
|
||||
/// 24小时成交量
|
||||
volume_24h: u256,
|
||||
|
||||
/// 是否激活
|
||||
is_active: bool
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 市场事件
|
||||
// ============================================================================
|
||||
|
||||
/// 订单创建事件
|
||||
event OrderCreated {
|
||||
order_id: Hash,
|
||||
pair_id: Hash,
|
||||
maker: Address,
|
||||
side: OrderSide,
|
||||
price: u256,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 订单取消事件
|
||||
event OrderCancelled {
|
||||
order_id: Hash,
|
||||
maker: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 交易成交事件
|
||||
event TradeExecuted {
|
||||
trade_id: Hash,
|
||||
pair_id: Hash,
|
||||
buyer: Address,
|
||||
seller: Address,
|
||||
price: u256,
|
||||
amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 订单成交事件
|
||||
event OrderFilled {
|
||||
order_id: Hash,
|
||||
filled_amount: u256,
|
||||
remaining_amount: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 去中心化交易市场
|
||||
// ============================================================================
|
||||
|
||||
/// 去中心化交易市场
|
||||
certificate DecentralizedMarketplace {
|
||||
/// 订单存储 (order_id => order)
|
||||
let _orders: Map<Hash, Order>;
|
||||
|
||||
/// 交易记录 (trade_id => trade)
|
||||
let _trades: Map<Hash, Trade>;
|
||||
|
||||
/// 交易对 (pair_id => trading_pair)
|
||||
let _pairs: Map<Hash, TradingPair>;
|
||||
|
||||
/// 用户订单索引 (user => order_ids)
|
||||
let _user_orders: Map<Address, Vec<Hash>>;
|
||||
|
||||
/// 交易对订单簿 - 买单 (pair_id => orders sorted by price desc)
|
||||
let _buy_orders: Map<Hash, Vec<Hash>>;
|
||||
|
||||
/// 交易对订单簿 - 卖单 (pair_id => orders sorted by price asc)
|
||||
let _sell_orders: Map<Hash, Vec<Hash>>;
|
||||
|
||||
/// 用户资产余额 (user => asset => amount)
|
||||
let _balances: Map<Address, Map<Address, u256>>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 默认手续费率(基点,例如30表示0.3%)
|
||||
let _default_fee_rate: u16;
|
||||
|
||||
/// 手续费收取地址
|
||||
let _fee_recipient: Address;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor(fee_rate: u16, fee_recipient: Address) {
|
||||
require(fee_rate <= 1000, "Fee rate too high"); // 最高10%
|
||||
require(!fee_recipient.is_zero(), "Invalid fee recipient");
|
||||
|
||||
self._admin = msg.sender;
|
||||
self._default_fee_rate = fee_rate;
|
||||
self._fee_recipient = fee_recipient;
|
||||
}
|
||||
|
||||
// ========== 交易对管理 ==========
|
||||
|
||||
/// 创建交易对
|
||||
///
|
||||
/// # 参数
|
||||
/// - `base_asset`: 基础资产地址
|
||||
/// - `quote_asset`: 报价资产地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 交易对ID
|
||||
pub fn create_pair(
|
||||
base_asset: Address,
|
||||
quote_asset: Address
|
||||
) -> Hash {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!base_asset.is_zero(), "Invalid base asset");
|
||||
require(!quote_asset.is_zero(), "Invalid quote asset");
|
||||
require(base_asset != quote_asset, "Assets must be different");
|
||||
|
||||
// 生成交易对ID
|
||||
let pair_id = self._generate_pair_id(base_asset, quote_asset);
|
||||
require(!self._pairs.contains_key(pair_id), "Pair already exists");
|
||||
|
||||
let pair = TradingPair {
|
||||
pair_id: pair_id,
|
||||
base_asset: base_asset,
|
||||
quote_asset: quote_asset,
|
||||
last_price: 0,
|
||||
high_24h: 0,
|
||||
low_24h: 0,
|
||||
volume_24h: 0,
|
||||
is_active: true
|
||||
};
|
||||
|
||||
self._pairs[pair_id] = pair;
|
||||
self._buy_orders[pair_id] = Vec::new();
|
||||
self._sell_orders[pair_id] = Vec::new();
|
||||
|
||||
return pair_id;
|
||||
}
|
||||
|
||||
/// 获取交易对信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pair_id`: 交易对ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `TradingPair`: 交易对信息
|
||||
pub fn get_pair(pair_id: Hash) -> TradingPair {
|
||||
require(self._pairs.contains_key(pair_id), "Pair not found");
|
||||
return self._pairs[pair_id];
|
||||
}
|
||||
|
||||
// ========== 资产存取 ==========
|
||||
|
||||
/// 存入资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
/// - `amount`: 数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn deposit(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
// 实际实现需要调用资产合约的transferFrom
|
||||
// 这里简化处理
|
||||
|
||||
if !self._balances.contains_key(msg.sender) {
|
||||
self._balances[msg.sender] = Map::new();
|
||||
}
|
||||
|
||||
let current_balance = self._balances[msg.sender].get(asset).unwrap_or(0);
|
||||
self._balances[msg.sender][asset] = safe_add(current_balance, amount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 提取资产
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset`: 资产地址
|
||||
/// - `amount`: 数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn withdraw(asset: Address, amount: u256) -> bool {
|
||||
require(!asset.is_zero(), "Invalid asset");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
let balance = self.get_balance(msg.sender, asset);
|
||||
require(balance >= amount, "Insufficient balance");
|
||||
|
||||
self._balances[msg.sender][asset] = safe_sub(balance, amount);
|
||||
|
||||
// 实际实现需要调用资产合约的transfer
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取余额
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
/// - `asset`: 资产地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 余额
|
||||
pub fn get_balance(user: Address, asset: Address) -> u256 {
|
||||
return self._balances.get(user)
|
||||
.and_then(|m| m.get(asset))
|
||||
.unwrap_or(0);
|
||||
}
|
||||
|
||||
// ========== 订单管理 ==========
|
||||
|
||||
/// 创建限价单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pair_id`: 交易对ID
|
||||
/// - `side`: 订单方向
|
||||
/// - `price`: 价格
|
||||
/// - `amount`: 数量
|
||||
/// - `expires_at`: 过期时间(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 订单ID
|
||||
pub fn create_limit_order(
|
||||
pair_id: Hash,
|
||||
side: OrderSide,
|
||||
price: u256,
|
||||
amount: u256,
|
||||
expires_at: Option<Timestamp>
|
||||
) -> Hash {
|
||||
require(self._pairs.contains_key(pair_id), "Pair not found");
|
||||
require(price > 0, "Price must be positive");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
let pair = self._pairs[pair_id];
|
||||
require(pair.is_active, "Pair not active");
|
||||
|
||||
if let Some(expiry) = expires_at {
|
||||
require(expiry > block.timestamp, "Invalid expiry time");
|
||||
}
|
||||
|
||||
// 检查余额
|
||||
let required_asset = match side {
|
||||
OrderSide::Buy => pair.quote_asset,
|
||||
OrderSide::Sell => pair.base_asset
|
||||
};
|
||||
|
||||
let required_amount = match side {
|
||||
OrderSide::Buy => safe_mul(price, amount) / 1e18, // 价格 * 数量
|
||||
OrderSide::Sell => amount
|
||||
};
|
||||
|
||||
let balance = self.get_balance(msg.sender, required_asset);
|
||||
require(balance >= required_amount, "Insufficient balance");
|
||||
|
||||
// 生成订单ID
|
||||
let order_id = self._generate_order_id(msg.sender, pair_id);
|
||||
|
||||
let order = Order {
|
||||
order_id: order_id,
|
||||
pair_id: pair_id,
|
||||
order_type: OrderType::Limit,
|
||||
side: side,
|
||||
maker: msg.sender,
|
||||
base_asset: pair.base_asset,
|
||||
quote_asset: pair.quote_asset,
|
||||
price: price,
|
||||
amount: amount,
|
||||
filled_amount: 0,
|
||||
status: OrderStatus::Open,
|
||||
created_at: block.timestamp,
|
||||
expires_at: expires_at,
|
||||
fee_rate: self._default_fee_rate
|
||||
};
|
||||
|
||||
self._orders[order_id] = order;
|
||||
|
||||
// 添加到用户订单索引
|
||||
if !self._user_orders.contains_key(msg.sender) {
|
||||
self._user_orders[msg.sender] = Vec::new();
|
||||
}
|
||||
self._user_orders[msg.sender].push(order_id);
|
||||
|
||||
// 添加到订单簿
|
||||
match side {
|
||||
OrderSide::Buy => self._add_buy_order(pair_id, order_id, price),
|
||||
OrderSide::Sell => self._add_sell_order(pair_id, order_id, price)
|
||||
}
|
||||
|
||||
emit OrderCreated {
|
||||
order_id: order_id,
|
||||
pair_id: pair_id,
|
||||
maker: msg.sender,
|
||||
side: side,
|
||||
price: price,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
// 尝试撮合
|
||||
self._match_orders(pair_id);
|
||||
|
||||
return order_id;
|
||||
}
|
||||
|
||||
/// 创建市价单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pair_id`: 交易对ID
|
||||
/// - `side`: 订单方向
|
||||
/// - `amount`: 数量
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 订单ID
|
||||
pub fn create_market_order(
|
||||
pair_id: Hash,
|
||||
side: OrderSide,
|
||||
amount: u256
|
||||
) -> Hash {
|
||||
require(self._pairs.contains_key(pair_id), "Pair not found");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
let pair = self._pairs[pair_id];
|
||||
require(pair.is_active, "Pair not active");
|
||||
|
||||
// 市价单使用最新价格
|
||||
let price = pair.last_price;
|
||||
require(price > 0, "No market price available");
|
||||
|
||||
// 生成订单ID
|
||||
let order_id = self._generate_order_id(msg.sender, pair_id);
|
||||
|
||||
let order = Order {
|
||||
order_id: order_id,
|
||||
pair_id: pair_id,
|
||||
order_type: OrderType::Market,
|
||||
side: side,
|
||||
maker: msg.sender,
|
||||
base_asset: pair.base_asset,
|
||||
quote_asset: pair.quote_asset,
|
||||
price: price,
|
||||
amount: amount,
|
||||
filled_amount: 0,
|
||||
status: OrderStatus::Open,
|
||||
created_at: block.timestamp,
|
||||
expires_at: None,
|
||||
fee_rate: self._default_fee_rate
|
||||
};
|
||||
|
||||
self._orders[order_id] = order;
|
||||
|
||||
emit OrderCreated {
|
||||
order_id: order_id,
|
||||
pair_id: pair_id,
|
||||
maker: msg.sender,
|
||||
side: side,
|
||||
price: price,
|
||||
amount: amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
// 立即撮合
|
||||
self._match_market_order(order_id);
|
||||
|
||||
return order_id;
|
||||
}
|
||||
|
||||
/// 取消订单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `order_id`: 订单ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn cancel_order(order_id: Hash) -> bool {
|
||||
require(self._orders.contains_key(order_id), "Order not found");
|
||||
|
||||
let mut order = self._orders[order_id];
|
||||
require(order.maker == msg.sender, "Not the maker");
|
||||
require(
|
||||
order.status == OrderStatus::Open ||
|
||||
order.status == OrderStatus::PartiallyFilled,
|
||||
"Cannot cancel"
|
||||
);
|
||||
|
||||
order.status = OrderStatus::Cancelled;
|
||||
self._orders[order_id] = order;
|
||||
|
||||
// 从订单簿移除
|
||||
self._remove_from_orderbook(order_id);
|
||||
|
||||
emit OrderCancelled {
|
||||
order_id: order_id,
|
||||
maker: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取订单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `order_id`: 订单ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Order`: 订单信息
|
||||
pub fn get_order(order_id: Hash) -> Order {
|
||||
require(self._orders.contains_key(order_id), "Order not found");
|
||||
return self._orders[order_id];
|
||||
}
|
||||
|
||||
/// 获取用户订单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 订单ID列表
|
||||
pub fn get_user_orders(user: Address) -> Vec<Hash> {
|
||||
return self._user_orders.get(user).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
// ========== 订单簿查询 ==========
|
||||
|
||||
/// 获取买单列表
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pair_id`: 交易对ID
|
||||
/// - `limit`: 数量限制
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Order>`: 买单列表
|
||||
pub fn get_buy_orders(pair_id: Hash, limit: u256) -> Vec<Order> {
|
||||
let order_ids = self._buy_orders.get(pair_id).unwrap_or(Vec::new());
|
||||
let mut orders = Vec::new();
|
||||
|
||||
let count = if limit > 0 && limit < order_ids.len() as u256 {
|
||||
limit as usize
|
||||
} else {
|
||||
order_ids.len()
|
||||
};
|
||||
|
||||
for i in 0..count {
|
||||
if let Some(order) = self._orders.get(order_ids[i]) {
|
||||
orders.push(order);
|
||||
}
|
||||
}
|
||||
|
||||
return orders;
|
||||
}
|
||||
|
||||
/// 获取卖单列表
|
||||
///
|
||||
/// # 参数
|
||||
/// - `pair_id`: 交易对ID
|
||||
/// - `limit`: 数量限制
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Order>`: 卖单列表
|
||||
pub fn get_sell_orders(pair_id: Hash, limit: u256) -> Vec<Order> {
|
||||
let order_ids = self._sell_orders.get(pair_id).unwrap_or(Vec::new());
|
||||
let mut orders = Vec::new();
|
||||
|
||||
let count = if limit > 0 && limit < order_ids.len() as u256 {
|
||||
limit as usize
|
||||
} else {
|
||||
order_ids.len()
|
||||
};
|
||||
|
||||
for i in 0..count {
|
||||
if let Some(order) = self._orders.get(order_ids[i]) {
|
||||
orders.push(order);
|
||||
}
|
||||
}
|
||||
|
||||
return orders;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成交易对ID
|
||||
fn _generate_pair_id(base_asset: Address, quote_asset: Address) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(base_asset.as_bytes());
|
||||
data.extend(quote_asset.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 生成订单ID
|
||||
fn _generate_order_id(maker: Address, pair_id: Hash) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(maker.as_bytes());
|
||||
data.extend(pair_id.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 添加买单到订单簿(按价格降序)
|
||||
fn _add_buy_order(pair_id: Hash, order_id: Hash, price: u256) {
|
||||
let mut orders = self._buy_orders[pair_id];
|
||||
|
||||
// 找到插入位置(价格降序)
|
||||
let mut insert_pos = orders.len();
|
||||
for i in 0..orders.len() {
|
||||
if let Some(existing_order) = self._orders.get(orders[i]) {
|
||||
if price > existing_order.price {
|
||||
insert_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orders.insert(insert_pos, order_id);
|
||||
self._buy_orders[pair_id] = orders;
|
||||
}
|
||||
|
||||
/// 添加卖单到订单簿(按价格升序)
|
||||
fn _add_sell_order(pair_id: Hash, order_id: Hash, price: u256) {
|
||||
let mut orders = self._sell_orders[pair_id];
|
||||
|
||||
// 找到插入位置(价格升序)
|
||||
let mut insert_pos = orders.len();
|
||||
for i in 0..orders.len() {
|
||||
if let Some(existing_order) = self._orders.get(orders[i]) {
|
||||
if price < existing_order.price {
|
||||
insert_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orders.insert(insert_pos, order_id);
|
||||
self._sell_orders[pair_id] = orders;
|
||||
}
|
||||
|
||||
/// 从订单簿移除订单
|
||||
fn _remove_from_orderbook(order_id: Hash) {
|
||||
let order = self._orders[order_id];
|
||||
|
||||
match order.side {
|
||||
OrderSide::Buy => {
|
||||
let mut orders = self._buy_orders[order.pair_id];
|
||||
orders.retain(|&id| id != order_id);
|
||||
self._buy_orders[order.pair_id] = orders;
|
||||
},
|
||||
OrderSide::Sell => {
|
||||
let mut orders = self._sell_orders[order.pair_id];
|
||||
orders.retain(|&id| id != order_id);
|
||||
self._sell_orders[order.pair_id] = orders;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 撮合订单
|
||||
fn _match_orders(pair_id: Hash) {
|
||||
let buy_orders = self._buy_orders.get(pair_id).unwrap_or(Vec::new());
|
||||
let sell_orders = self._sell_orders.get(pair_id).unwrap_or(Vec::new());
|
||||
|
||||
if buy_orders.len() == 0 || sell_orders.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取最高买价和最低卖价
|
||||
let best_buy_id = buy_orders[0];
|
||||
let best_sell_id = sell_orders[0];
|
||||
|
||||
let buy_order = self._orders[best_buy_id];
|
||||
let sell_order = self._orders[best_sell_id];
|
||||
|
||||
// 检查是否可以成交(买价 >= 卖价)
|
||||
if buy_order.price >= sell_order.price {
|
||||
self._execute_trade(best_buy_id, best_sell_id);
|
||||
|
||||
// 递归撮合
|
||||
self._match_orders(pair_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// 撮合市价单
|
||||
fn _match_market_order(order_id: Hash) {
|
||||
let order = self._orders[order_id];
|
||||
|
||||
let opposite_orders = match order.side {
|
||||
OrderSide::Buy => self._sell_orders.get(order.pair_id).unwrap_or(Vec::new()),
|
||||
OrderSide::Sell => self._buy_orders.get(order.pair_id).unwrap_or(Vec::new())
|
||||
};
|
||||
|
||||
if opposite_orders.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// 与最优价格成交
|
||||
let opposite_id = opposite_orders[0];
|
||||
|
||||
match order.side {
|
||||
OrderSide::Buy => self._execute_trade(order_id, opposite_id),
|
||||
OrderSide::Sell => self._execute_trade(opposite_id, order_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行交易
|
||||
fn _execute_trade(buy_order_id: Hash, sell_order_id: Hash) {
|
||||
let mut buy_order = self._orders[buy_order_id];
|
||||
let mut sell_order = self._orders[sell_order_id];
|
||||
|
||||
// 计算成交数量(取较小值)
|
||||
let buy_remaining = safe_sub(buy_order.amount, buy_order.filled_amount);
|
||||
let sell_remaining = safe_sub(sell_order.amount, sell_order.filled_amount);
|
||||
let trade_amount = if buy_remaining < sell_remaining {
|
||||
buy_remaining
|
||||
} else {
|
||||
sell_remaining
|
||||
};
|
||||
|
||||
// 成交价格(使用卖单价格)
|
||||
let trade_price = sell_order.price;
|
||||
|
||||
// 计算手续费
|
||||
let buyer_fee = safe_mul(trade_amount, buy_order.fee_rate as u256) / 10000;
|
||||
let seller_fee = safe_mul(trade_amount, sell_order.fee_rate as u256) / 10000;
|
||||
|
||||
// 生成交易ID
|
||||
let trade_id = self._generate_trade_id(buy_order_id, sell_order_id);
|
||||
|
||||
// 创建交易记录
|
||||
let trade = Trade {
|
||||
trade_id: trade_id,
|
||||
pair_id: buy_order.pair_id,
|
||||
buy_order_id: buy_order_id,
|
||||
sell_order_id: sell_order_id,
|
||||
buyer: buy_order.maker,
|
||||
seller: sell_order.maker,
|
||||
price: trade_price,
|
||||
amount: trade_amount,
|
||||
timestamp: block.timestamp,
|
||||
buyer_fee: buyer_fee,
|
||||
seller_fee: seller_fee
|
||||
};
|
||||
|
||||
self._trades[trade_id] = trade;
|
||||
|
||||
// 更新订单状态
|
||||
buy_order.filled_amount = safe_add(buy_order.filled_amount, trade_amount);
|
||||
sell_order.filled_amount = safe_add(sell_order.filled_amount, trade_amount);
|
||||
|
||||
if buy_order.filled_amount == buy_order.amount {
|
||||
buy_order.status = OrderStatus::Filled;
|
||||
self._remove_from_orderbook(buy_order_id);
|
||||
} else {
|
||||
buy_order.status = OrderStatus::PartiallyFilled;
|
||||
}
|
||||
|
||||
if sell_order.filled_amount == sell_order.amount {
|
||||
sell_order.status = OrderStatus::Filled;
|
||||
self._remove_from_orderbook(sell_order_id);
|
||||
} else {
|
||||
sell_order.status = OrderStatus::PartiallyFilled;
|
||||
}
|
||||
|
||||
self._orders[buy_order_id] = buy_order;
|
||||
self._orders[sell_order_id] = sell_order;
|
||||
|
||||
// 更新余额
|
||||
self._settle_trade(trade);
|
||||
|
||||
// 更新交易对统计
|
||||
self._update_pair_stats(buy_order.pair_id, trade_price, trade_amount);
|
||||
|
||||
emit TradeExecuted {
|
||||
trade_id: trade_id,
|
||||
pair_id: buy_order.pair_id,
|
||||
buyer: buy_order.maker,
|
||||
seller: sell_order.maker,
|
||||
price: trade_price,
|
||||
amount: trade_amount,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
}
|
||||
|
||||
/// 生成交易ID
|
||||
fn _generate_trade_id(buy_order_id: Hash, sell_order_id: Hash) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(buy_order_id.as_bytes());
|
||||
data.extend(sell_order_id.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 结算交易
|
||||
fn _settle_trade(trade: Trade) {
|
||||
// 买方支付报价资产,获得基础资产
|
||||
// 卖方支付基础资产,获得报价资产
|
||||
|
||||
// 实际实现需要更新余额映射
|
||||
// 这里简化处理
|
||||
}
|
||||
|
||||
/// 更新交易对统计
|
||||
fn _update_pair_stats(pair_id: Hash, price: u256, volume: u256) {
|
||||
let mut pair = self._pairs[pair_id];
|
||||
|
||||
pair.last_price = price;
|
||||
|
||||
if price > pair.high_24h {
|
||||
pair.high_24h = price;
|
||||
}
|
||||
|
||||
if pair.low_24h == 0 || price < pair.low_24h {
|
||||
pair.low_24h = price;
|
||||
}
|
||||
|
||||
pair.volume_24h = safe_add(pair.volume_24h, volume);
|
||||
|
||||
self._pairs[pair_id] = pair;
|
||||
}
|
||||
pub fn cancel_listing(asset_id: Address) -> bool {
|
||||
require(!asset_id.is_zero(), "Invalid asset");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,703 +1,14 @@
|
|||
///! # 提案管理系统
|
||||
///!
|
||||
///! Proposal Management System
|
||||
///! 提供提案创建、执行和历史管理功能
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/governance/proposal.ch
|
||||
|
||||
use utils::math::{safe_add, safe_sub};
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 提案枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 提案类型
|
||||
pub enum ProposalType {
|
||||
/// 参数修改
|
||||
ParameterChange,
|
||||
|
||||
/// 资金支出
|
||||
Treasury,
|
||||
|
||||
/// 合约升级
|
||||
Upgrade,
|
||||
|
||||
/// 文本提案
|
||||
Text,
|
||||
|
||||
/// 自定义
|
||||
Custom
|
||||
pub fn create_proposal(title: String, description: String) -> u256 {
|
||||
require(title.len() > 0, "Title cannot be empty");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// 提案状态
|
||||
pub enum ProposalStatus {
|
||||
/// 草稿
|
||||
Draft,
|
||||
|
||||
/// 待投票
|
||||
Pending,
|
||||
|
||||
/// 投票中
|
||||
Active,
|
||||
|
||||
/// 已通过
|
||||
Passed,
|
||||
|
||||
/// 未通过
|
||||
Rejected,
|
||||
|
||||
/// 已执行
|
||||
Executed,
|
||||
|
||||
/// 已取消
|
||||
Cancelled,
|
||||
|
||||
/// 已过期
|
||||
Expired
|
||||
pub fn execute_proposal(proposal_id: u256) -> bool {
|
||||
require(proposal_id > 0, "Invalid proposal ID");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 提案结构
|
||||
// ============================================================================
|
||||
|
||||
/// 提案
|
||||
struct Proposal {
|
||||
/// 提案ID
|
||||
proposal_id: Hash,
|
||||
|
||||
/// 提案类型
|
||||
proposal_type: ProposalType,
|
||||
|
||||
/// 标题
|
||||
title: String,
|
||||
|
||||
/// 描述
|
||||
description: String,
|
||||
|
||||
/// 提案者
|
||||
proposer: Address,
|
||||
|
||||
/// 创建时间
|
||||
created_at: Timestamp,
|
||||
|
||||
/// 投票开始时间
|
||||
voting_start: Timestamp,
|
||||
|
||||
/// 投票结束时间
|
||||
voting_end: Timestamp,
|
||||
|
||||
/// 执行延迟(秒)
|
||||
execution_delay: Duration,
|
||||
|
||||
/// 最早执行时间
|
||||
earliest_execution: Timestamp,
|
||||
|
||||
/// 执行截止时间
|
||||
execution_deadline: Timestamp,
|
||||
|
||||
/// 提案状态
|
||||
status: ProposalStatus,
|
||||
|
||||
/// 投票ID
|
||||
vote_id: Option<Hash>,
|
||||
|
||||
/// 执行交易哈希
|
||||
execution_tx: Option<Hash>,
|
||||
|
||||
/// 执行时间
|
||||
executed_at: Option<Timestamp>,
|
||||
|
||||
/// 取消原因
|
||||
cancellation_reason: Option<String>
|
||||
}
|
||||
|
||||
/// 提案操作
|
||||
struct ProposalAction {
|
||||
/// 目标合约
|
||||
target: Address,
|
||||
|
||||
/// 函数签名
|
||||
function_sig: String,
|
||||
|
||||
/// 调用数据
|
||||
call_data: Bytes,
|
||||
|
||||
/// 转账金额
|
||||
value: u256,
|
||||
|
||||
/// 描述
|
||||
description: String
|
||||
}
|
||||
|
||||
/// 提案元数据
|
||||
struct ProposalMetadata {
|
||||
/// 提案ID
|
||||
proposal_id: Hash,
|
||||
|
||||
/// 标签
|
||||
tags: Vec<String>,
|
||||
|
||||
/// 相关链接
|
||||
links: Vec<String>,
|
||||
|
||||
/// 讨论链接
|
||||
discussion_url: Option<String>,
|
||||
|
||||
/// 文档哈希
|
||||
document_hash: Option<Hash>
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 提案事件
|
||||
// ============================================================================
|
||||
|
||||
/// 提案创建事件
|
||||
event ProposalCreated {
|
||||
proposal_id: Hash,
|
||||
proposer: Address,
|
||||
title: String,
|
||||
proposal_type: ProposalType,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提案提交事件
|
||||
event ProposalSubmitted {
|
||||
proposal_id: Hash,
|
||||
vote_id: Hash,
|
||||
voting_start: Timestamp,
|
||||
voting_end: Timestamp,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提案通过事件
|
||||
event ProposalPassed {
|
||||
proposal_id: Hash,
|
||||
vote_id: Hash,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提案拒绝事件
|
||||
event ProposalRejected {
|
||||
proposal_id: Hash,
|
||||
vote_id: Hash,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提案执行事件
|
||||
event ProposalExecuted {
|
||||
proposal_id: Hash,
|
||||
executor: Address,
|
||||
execution_tx: Hash,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 提案取消事件
|
||||
event ProposalCancelled {
|
||||
proposal_id: Hash,
|
||||
canceller: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 提案管理系统
|
||||
// ============================================================================
|
||||
|
||||
/// 提案管理系统
|
||||
certificate ProposalManagement {
|
||||
/// 提案 (proposal_id => proposal)
|
||||
let _proposals: Map<Hash, Proposal>;
|
||||
|
||||
/// 提案操作 (proposal_id => actions)
|
||||
let _proposal_actions: Map<Hash, Vec<ProposalAction>>;
|
||||
|
||||
/// 提案元数据 (proposal_id => metadata)
|
||||
let _proposal_metadata: Map<Hash, ProposalMetadata>;
|
||||
|
||||
/// 提案者提案列表 (proposer => proposal_ids)
|
||||
let _proposer_proposals: Map<Address, Vec<Hash>>;
|
||||
|
||||
/// 投票系统地址
|
||||
let _voting_system: Address;
|
||||
|
||||
/// 治理代币地址
|
||||
let _governance_token: Address;
|
||||
|
||||
/// 时间锁地址
|
||||
let _timelock: Address;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 提案门槛(需要的代币数量)
|
||||
let _proposal_threshold: u256;
|
||||
|
||||
/// 默认投票期限(秒)
|
||||
let _default_voting_period: Duration;
|
||||
|
||||
/// 默认执行延迟(秒)
|
||||
let _default_execution_delay: Duration;
|
||||
|
||||
/// 执行窗口期(秒)
|
||||
let _execution_window: Duration;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor(
|
||||
voting_system: Address,
|
||||
governance_token: Address,
|
||||
timelock: Address,
|
||||
proposal_threshold: u256,
|
||||
voting_period: Duration,
|
||||
execution_delay: Duration,
|
||||
execution_window: Duration
|
||||
) {
|
||||
require(!voting_system.is_zero(), "Invalid voting system");
|
||||
require(!governance_token.is_zero(), "Invalid governance token");
|
||||
require(!timelock.is_zero(), "Invalid timelock");
|
||||
require(proposal_threshold > 0, "Threshold must be positive");
|
||||
require(voting_period > 0, "Voting period must be positive");
|
||||
require(execution_delay > 0, "Execution delay must be positive");
|
||||
require(execution_window > 0, "Execution window must be positive");
|
||||
|
||||
self._voting_system = voting_system;
|
||||
self._governance_token = governance_token;
|
||||
self._timelock = timelock;
|
||||
self._admin = msg.sender;
|
||||
self._proposal_threshold = proposal_threshold;
|
||||
self._default_voting_period = voting_period;
|
||||
self._default_execution_delay = execution_delay;
|
||||
self._execution_window = execution_window;
|
||||
}
|
||||
|
||||
// ========== 提案创建 ==========
|
||||
|
||||
/// 创建提案
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_type`: 提案类型
|
||||
/// - `title`: 标题
|
||||
/// - `description`: 描述
|
||||
/// - `actions`: 操作列表
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 提案ID
|
||||
pub fn create_proposal(
|
||||
proposal_type: ProposalType,
|
||||
title: String,
|
||||
description: String,
|
||||
actions: Vec<ProposalAction>
|
||||
) -> Hash {
|
||||
require(!title.is_empty(), "Title required");
|
||||
require(!description.is_empty(), "Description required");
|
||||
|
||||
// 检查提案门槛(实际需要查询治理代币余额)
|
||||
let proposer_balance = self._get_token_balance(msg.sender);
|
||||
require(
|
||||
proposer_balance >= self._proposal_threshold,
|
||||
"Insufficient tokens to propose"
|
||||
);
|
||||
|
||||
// 生成提案ID
|
||||
let proposal_id = self._generate_proposal_id(msg.sender, title.clone());
|
||||
|
||||
let proposal = Proposal {
|
||||
proposal_id: proposal_id,
|
||||
proposal_type: proposal_type,
|
||||
title: title.clone(),
|
||||
description: description,
|
||||
proposer: msg.sender,
|
||||
created_at: block.timestamp,
|
||||
voting_start: 0,
|
||||
voting_end: 0,
|
||||
execution_delay: self._default_execution_delay,
|
||||
earliest_execution: 0,
|
||||
execution_deadline: 0,
|
||||
status: ProposalStatus::Draft,
|
||||
vote_id: None,
|
||||
execution_tx: None,
|
||||
executed_at: None,
|
||||
cancellation_reason: None
|
||||
};
|
||||
|
||||
self._proposals[proposal_id] = proposal;
|
||||
self._proposal_actions[proposal_id] = actions;
|
||||
|
||||
// 添加到提案者列表
|
||||
if !self._proposer_proposals.contains_key(msg.sender) {
|
||||
self._proposer_proposals[msg.sender] = Vec::new();
|
||||
}
|
||||
self._proposer_proposals[msg.sender].push(proposal_id);
|
||||
|
||||
emit ProposalCreated {
|
||||
proposal_id: proposal_id,
|
||||
proposer: msg.sender,
|
||||
title: title,
|
||||
proposal_type: proposal_type,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return proposal_id;
|
||||
}
|
||||
|
||||
/// 提交提案进行投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
/// - `voting_period`: 投票期限(秒,0表示使用默认值)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 投票ID
|
||||
pub fn submit_proposal(
|
||||
proposal_id: Hash,
|
||||
voting_period: Duration
|
||||
) -> Hash {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
|
||||
let mut proposal = self._proposals[proposal_id];
|
||||
require(proposal.proposer == msg.sender, "Not the proposer");
|
||||
require(proposal.status == ProposalStatus::Draft, "Not in draft status");
|
||||
|
||||
let period = if voting_period == 0 {
|
||||
self._default_voting_period
|
||||
} else {
|
||||
voting_period
|
||||
};
|
||||
|
||||
let voting_start = block.timestamp;
|
||||
let voting_end = block.timestamp + period;
|
||||
|
||||
// 创建投票(实际需要调用投票系统合约)
|
||||
let vote_id = self._create_vote(proposal_id, proposal.title.clone(), period);
|
||||
|
||||
proposal.voting_start = voting_start;
|
||||
proposal.voting_end = voting_end;
|
||||
proposal.status = ProposalStatus::Active;
|
||||
proposal.vote_id = Some(vote_id);
|
||||
|
||||
// 计算执行时间窗口
|
||||
proposal.earliest_execution = voting_end + proposal.execution_delay;
|
||||
proposal.execution_deadline = proposal.earliest_execution + self._execution_window;
|
||||
|
||||
self._proposals[proposal_id] = proposal;
|
||||
|
||||
emit ProposalSubmitted {
|
||||
proposal_id: proposal_id,
|
||||
vote_id: vote_id,
|
||||
voting_start: voting_start,
|
||||
voting_end: voting_end,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return vote_id;
|
||||
}
|
||||
|
||||
// ========== 提案执行 ==========
|
||||
|
||||
/// 执行提案
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn execute_proposal(proposal_id: Hash) -> bool {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
|
||||
let mut proposal = self._proposals[proposal_id];
|
||||
require(proposal.status == ProposalStatus::Passed, "Proposal not passed");
|
||||
require(
|
||||
block.timestamp >= proposal.earliest_execution,
|
||||
"Execution delay not met"
|
||||
);
|
||||
require(
|
||||
block.timestamp <= proposal.execution_deadline,
|
||||
"Execution deadline passed"
|
||||
);
|
||||
|
||||
// 获取提案操作
|
||||
let actions = self._proposal_actions.get(proposal_id).unwrap_or(Vec::new());
|
||||
|
||||
// 执行所有操作(实际需要通过时间锁执行)
|
||||
for action in actions {
|
||||
self._execute_action(action);
|
||||
}
|
||||
|
||||
// 生成执行交易哈希
|
||||
let execution_tx = tx.hash;
|
||||
|
||||
proposal.status = ProposalStatus::Executed;
|
||||
proposal.execution_tx = Some(execution_tx);
|
||||
proposal.executed_at = Some(block.timestamp);
|
||||
|
||||
self._proposals[proposal_id] = proposal;
|
||||
|
||||
emit ProposalExecuted {
|
||||
proposal_id: proposal_id,
|
||||
executor: msg.sender,
|
||||
execution_tx: execution_tx,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 更新提案状态(根据投票结果)
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn update_proposal_status(proposal_id: Hash) -> bool {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
|
||||
let mut proposal = self._proposals[proposal_id];
|
||||
require(proposal.status == ProposalStatus::Active, "Proposal not active");
|
||||
require(block.timestamp >= proposal.voting_end, "Voting not ended");
|
||||
|
||||
// 获取投票结果(实际需要调用投票系统合约)
|
||||
let vote_result = self._get_vote_result(proposal.vote_id.unwrap());
|
||||
|
||||
match vote_result {
|
||||
VoteResult::Passed => {
|
||||
proposal.status = ProposalStatus::Passed;
|
||||
|
||||
emit ProposalPassed {
|
||||
proposal_id: proposal_id,
|
||||
vote_id: proposal.vote_id.unwrap(),
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
},
|
||||
_ => {
|
||||
proposal.status = ProposalStatus::Rejected;
|
||||
|
||||
emit ProposalRejected {
|
||||
proposal_id: proposal_id,
|
||||
vote_id: proposal.vote_id.unwrap(),
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
self._proposals[proposal_id] = proposal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 取消提案
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
/// - `reason`: 取消原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn cancel_proposal(proposal_id: Hash, reason: String) -> bool {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
|
||||
let mut proposal = self._proposals[proposal_id];
|
||||
require(
|
||||
msg.sender == proposal.proposer || msg.sender == self._admin,
|
||||
"Not authorized"
|
||||
);
|
||||
require(
|
||||
proposal.status == ProposalStatus::Draft ||
|
||||
proposal.status == ProposalStatus::Pending ||
|
||||
proposal.status == ProposalStatus::Active,
|
||||
"Cannot cancel"
|
||||
);
|
||||
|
||||
proposal.status = ProposalStatus::Cancelled;
|
||||
proposal.cancellation_reason = Some(reason.clone());
|
||||
|
||||
self._proposals[proposal_id] = proposal;
|
||||
|
||||
emit ProposalCancelled {
|
||||
proposal_id: proposal_id,
|
||||
canceller: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 元数据管理 ==========
|
||||
|
||||
/// 设置提案元数据
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
/// - `tags`: 标签
|
||||
/// - `links`: 相关链接
|
||||
/// - `discussion_url`: 讨论链接
|
||||
/// - `document_hash`: 文档哈希
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn set_proposal_metadata(
|
||||
proposal_id: Hash,
|
||||
tags: Vec<String>,
|
||||
links: Vec<String>,
|
||||
discussion_url: Option<String>,
|
||||
document_hash: Option<Hash>
|
||||
) -> bool {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
|
||||
let proposal = self._proposals[proposal_id];
|
||||
require(proposal.proposer == msg.sender, "Not the proposer");
|
||||
|
||||
let metadata = ProposalMetadata {
|
||||
proposal_id: proposal_id,
|
||||
tags: tags,
|
||||
links: links,
|
||||
discussion_url: discussion_url,
|
||||
document_hash: document_hash
|
||||
};
|
||||
|
||||
self._proposal_metadata[proposal_id] = metadata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取提案元数据
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<ProposalMetadata>`: 元数据
|
||||
pub fn get_proposal_metadata(proposal_id: Hash) -> Option<ProposalMetadata> {
|
||||
return self._proposal_metadata.get(proposal_id);
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取提案
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Proposal`: 提案信息
|
||||
pub fn get_proposal(proposal_id: Hash) -> Proposal {
|
||||
require(self._proposals.contains_key(proposal_id), "Proposal not found");
|
||||
return self._proposals[proposal_id];
|
||||
}
|
||||
|
||||
/// 获取提案操作
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<ProposalAction>`: 操作列表
|
||||
pub fn get_proposal_actions(proposal_id: Hash) -> Vec<ProposalAction> {
|
||||
return self._proposal_actions.get(proposal_id).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 获取提案者的提案列表
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposer`: 提案者地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 提案ID列表
|
||||
pub fn get_proposer_proposals(proposer: Address) -> Vec<Hash> {
|
||||
return self._proposer_proposals.get(proposer).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 检查提案是否可执行
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否可执行
|
||||
pub fn is_executable(proposal_id: Hash) -> bool {
|
||||
if !self._proposals.contains_key(proposal_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let proposal = self._proposals[proposal_id];
|
||||
|
||||
return proposal.status == ProposalStatus::Passed &&
|
||||
block.timestamp >= proposal.earliest_execution &&
|
||||
block.timestamp <= proposal.execution_deadline;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成提案ID
|
||||
fn _generate_proposal_id(proposer: Address, title: String) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(proposer.as_bytes());
|
||||
data.extend(title.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 获取代币余额(简化,实际需要调用代币合约)
|
||||
fn _get_token_balance(account: Address) -> u256 {
|
||||
return 1000; // 简化
|
||||
}
|
||||
|
||||
/// 创建投票(简化,实际需要调用投票系统合约)
|
||||
fn _create_vote(proposal_id: Hash, title: String, period: Duration) -> Hash {
|
||||
// 实际需要调用投票系统的create_vote函数
|
||||
return sha3_384_hash(proposal_id.as_bytes());
|
||||
}
|
||||
|
||||
/// 获取投票结果(简化,实际需要调用投票系统合约)
|
||||
fn _get_vote_result(vote_id: Hash) -> VoteResult {
|
||||
// 实际需要调用投票系统的get_vote_result函数
|
||||
return VoteResult::Passed;
|
||||
}
|
||||
|
||||
/// 执行操作(简化,实际需要通过时间锁执行)
|
||||
fn _execute_action(action: ProposalAction) {
|
||||
// 实际需要通过时间锁合约执行
|
||||
// timelock.execute(action.target, action.function_sig, action.call_data, action.value)
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 设置提案门槛
|
||||
pub fn set_proposal_threshold(threshold: u256) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(threshold > 0, "Threshold must be positive");
|
||||
self._proposal_threshold = threshold;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置默认投票期限
|
||||
pub fn set_default_voting_period(period: Duration) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(period > 0, "Period must be positive");
|
||||
self._default_voting_period = period;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置默认执行延迟
|
||||
pub fn set_default_execution_delay(delay: Duration) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(delay > 0, "Delay must be positive");
|
||||
self._default_execution_delay = delay;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 投票结果枚举(从voting.ch引用)
|
||||
// ============================================================================
|
||||
|
||||
enum VoteResult {
|
||||
Undecided,
|
||||
Passed,
|
||||
Failed,
|
||||
QuorumNotReached
|
||||
pub fn cancel_proposal(proposal_id: u256) -> bool {
|
||||
require(proposal_id > 0, "Invalid proposal ID");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,800 +1,12 @@
|
|||
///! # 投票系统
|
||||
///!
|
||||
///! Voting System
|
||||
///! 提供提案投票、权重计算和委托投票功能
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/governance/voting.ch
|
||||
|
||||
use utils::math::{safe_add, safe_sub, safe_mul, safe_div};
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 投票枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 投票选项
|
||||
pub enum VoteOption {
|
||||
/// 赞成
|
||||
For,
|
||||
|
||||
/// 反对
|
||||
Against,
|
||||
|
||||
/// 弃权
|
||||
Abstain
|
||||
pub fn vote(proposal_id: u256, support: bool) -> bool {
|
||||
require(proposal_id > 0, "Invalid proposal ID");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 投票状态
|
||||
pub enum VoteStatus {
|
||||
/// 待开始
|
||||
Pending,
|
||||
|
||||
/// 进行中
|
||||
Active,
|
||||
|
||||
/// 已结束
|
||||
Ended,
|
||||
|
||||
/// 已取消
|
||||
Cancelled
|
||||
pub fn get_votes(proposal_id: u256) -> u256 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 投票结果
|
||||
pub enum VoteResult {
|
||||
/// 未决定
|
||||
Undecided,
|
||||
|
||||
/// 通过
|
||||
Passed,
|
||||
|
||||
/// 未通过
|
||||
Failed,
|
||||
|
||||
/// 法定人数不足
|
||||
QuorumNotReached
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 投票结构
|
||||
// ============================================================================
|
||||
|
||||
/// 投票信息
|
||||
struct Vote {
|
||||
/// 投票ID
|
||||
vote_id: Hash,
|
||||
|
||||
/// 提案ID
|
||||
proposal_id: Hash,
|
||||
|
||||
/// 标题
|
||||
title: String,
|
||||
|
||||
/// 描述
|
||||
description: String,
|
||||
|
||||
/// 创建者
|
||||
creator: Address,
|
||||
|
||||
/// 开始时间
|
||||
start_time: Timestamp,
|
||||
|
||||
/// 结束时间
|
||||
end_time: Timestamp,
|
||||
|
||||
/// 赞成票数
|
||||
votes_for: u256,
|
||||
|
||||
/// 反对票数
|
||||
votes_against: u256,
|
||||
|
||||
/// 弃权票数
|
||||
votes_abstain: u256,
|
||||
|
||||
/// 总投票权重
|
||||
total_weight: u256,
|
||||
|
||||
/// 法定人数(基点)
|
||||
quorum: u16,
|
||||
|
||||
/// 通过阈值(基点)
|
||||
threshold: u16,
|
||||
|
||||
/// 投票状态
|
||||
status: VoteStatus,
|
||||
|
||||
/// 投票结果
|
||||
result: VoteResult,
|
||||
|
||||
/// 是否允许委托
|
||||
allow_delegation: bool
|
||||
}
|
||||
|
||||
/// 投票记录
|
||||
struct VoteRecord {
|
||||
/// 投票者
|
||||
voter: Address,
|
||||
|
||||
/// 投票ID
|
||||
vote_id: Hash,
|
||||
|
||||
/// 投票选项
|
||||
option: VoteOption,
|
||||
|
||||
/// 投票权重
|
||||
weight: u256,
|
||||
|
||||
/// 投票时间
|
||||
timestamp: Timestamp,
|
||||
|
||||
/// 是否通过委托
|
||||
is_delegated: bool,
|
||||
|
||||
/// 委托人(如果是委托投票)
|
||||
delegator: Option<Address>
|
||||
}
|
||||
|
||||
/// 委托记录
|
||||
struct Delegation {
|
||||
/// 委托人
|
||||
delegator: Address,
|
||||
|
||||
/// 被委托人
|
||||
delegate: Address,
|
||||
|
||||
/// 委托权重
|
||||
weight: u256,
|
||||
|
||||
/// 委托时间
|
||||
delegated_at: Timestamp,
|
||||
|
||||
/// 过期时间(可选)
|
||||
expires_at: Option<Timestamp>
|
||||
}
|
||||
|
||||
/// 投票权重快照
|
||||
struct WeightSnapshot {
|
||||
/// 地址
|
||||
address: Address,
|
||||
|
||||
/// 权重
|
||||
weight: u256,
|
||||
|
||||
/// 快照时间
|
||||
snapshot_at: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 投票事件
|
||||
// ============================================================================
|
||||
|
||||
/// 投票创建事件
|
||||
event VoteCreated {
|
||||
vote_id: Hash,
|
||||
proposal_id: Hash,
|
||||
title: String,
|
||||
creator: Address,
|
||||
start_time: Timestamp,
|
||||
end_time: Timestamp,
|
||||
quorum: u16,
|
||||
threshold: u16
|
||||
}
|
||||
|
||||
/// 投票提交事件
|
||||
event VoteCast {
|
||||
vote_id: Hash,
|
||||
voter: Address,
|
||||
option: VoteOption,
|
||||
weight: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 投票结束事件
|
||||
event VoteEnded {
|
||||
vote_id: Hash,
|
||||
result: VoteResult,
|
||||
votes_for: u256,
|
||||
votes_against: u256,
|
||||
votes_abstain: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 委托事件
|
||||
event DelegationCreated {
|
||||
delegator: Address,
|
||||
delegate: Address,
|
||||
weight: u256,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 取消委托事件
|
||||
event DelegationRevoked {
|
||||
delegator: Address,
|
||||
delegate: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 投票系统
|
||||
// ============================================================================
|
||||
|
||||
/// 投票系统
|
||||
certificate VotingSystem {
|
||||
/// 投票 (vote_id => vote)
|
||||
let _votes: Map<Hash, Vote>;
|
||||
|
||||
/// 投票记录 (vote_id => voter => record)
|
||||
let _vote_records: Map<Hash, Map<Address, VoteRecord>>;
|
||||
|
||||
/// 委托 (delegator => delegate => delegation)
|
||||
let _delegations: Map<Address, Map<Address, Delegation>>;
|
||||
|
||||
/// 权重快照 (vote_id => address => snapshot)
|
||||
let _weight_snapshots: Map<Hash, Map<Address, WeightSnapshot>>;
|
||||
|
||||
/// 治理代币地址
|
||||
let _governance_token: Address;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 默认法定人数(基点)
|
||||
let _default_quorum: u16;
|
||||
|
||||
/// 默认通过阈值(基点)
|
||||
let _default_threshold: u16;
|
||||
|
||||
/// 最小投票期限(秒)
|
||||
let _min_voting_period: Duration;
|
||||
|
||||
/// 最大投票期限(秒)
|
||||
let _max_voting_period: Duration;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor(
|
||||
governance_token: Address,
|
||||
default_quorum: u16,
|
||||
default_threshold: u16,
|
||||
min_period: Duration,
|
||||
max_period: Duration
|
||||
) {
|
||||
require(!governance_token.is_zero(), "Invalid governance token");
|
||||
require(default_quorum <= 10000, "Invalid quorum");
|
||||
require(default_threshold <= 10000, "Invalid threshold");
|
||||
require(min_period > 0, "Min period must be positive");
|
||||
require(max_period > min_period, "Max period must be > min period");
|
||||
|
||||
self._governance_token = governance_token;
|
||||
self._admin = msg.sender;
|
||||
self._default_quorum = default_quorum;
|
||||
self._default_threshold = default_threshold;
|
||||
self._min_voting_period = min_period;
|
||||
self._max_voting_period = max_period;
|
||||
}
|
||||
|
||||
// ========== 投票管理 ==========
|
||||
|
||||
/// 创建投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `proposal_id`: 提案ID
|
||||
/// - `title`: 标题
|
||||
/// - `description`: 描述
|
||||
/// - `duration`: 投票期限(秒)
|
||||
/// - `quorum`: 法定人数(基点,0表示使用默认值)
|
||||
/// - `threshold`: 通过阈值(基点,0表示使用默认值)
|
||||
/// - `allow_delegation`: 是否允许委托
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 投票ID
|
||||
pub fn create_vote(
|
||||
proposal_id: Hash,
|
||||
title: String,
|
||||
description: String,
|
||||
duration: Duration,
|
||||
quorum: u16,
|
||||
threshold: u16,
|
||||
allow_delegation: bool
|
||||
) -> Hash {
|
||||
require(!title.is_empty(), "Title required");
|
||||
require(duration >= self._min_voting_period, "Duration too short");
|
||||
require(duration <= self._max_voting_period, "Duration too long");
|
||||
|
||||
let final_quorum = if quorum == 0 {
|
||||
self._default_quorum
|
||||
} else {
|
||||
require(quorum <= 10000, "Invalid quorum");
|
||||
quorum
|
||||
};
|
||||
|
||||
let final_threshold = if threshold == 0 {
|
||||
self._default_threshold
|
||||
} else {
|
||||
require(threshold <= 10000, "Invalid threshold");
|
||||
threshold
|
||||
};
|
||||
|
||||
// 生成投票ID
|
||||
let vote_id = self._generate_vote_id(proposal_id, msg.sender);
|
||||
|
||||
let start_time = block.timestamp;
|
||||
let end_time = block.timestamp + duration;
|
||||
|
||||
let vote = Vote {
|
||||
vote_id: vote_id,
|
||||
proposal_id: proposal_id,
|
||||
title: title.clone(),
|
||||
description: description,
|
||||
creator: msg.sender,
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
votes_for: 0,
|
||||
votes_against: 0,
|
||||
votes_abstain: 0,
|
||||
total_weight: 0,
|
||||
quorum: final_quorum,
|
||||
threshold: final_threshold,
|
||||
status: VoteStatus::Active,
|
||||
result: VoteResult::Undecided,
|
||||
allow_delegation: allow_delegation
|
||||
};
|
||||
|
||||
self._votes[vote_id] = vote;
|
||||
|
||||
emit VoteCreated {
|
||||
vote_id: vote_id,
|
||||
proposal_id: proposal_id,
|
||||
title: title,
|
||||
creator: msg.sender,
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
quorum: final_quorum,
|
||||
threshold: final_threshold
|
||||
};
|
||||
|
||||
return vote_id;
|
||||
}
|
||||
|
||||
/// 投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
/// - `option`: 投票选项
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn cast_vote(vote_id: Hash, option: VoteOption) -> bool {
|
||||
require(self._votes.contains_key(vote_id), "Vote not found");
|
||||
|
||||
let mut vote = self._votes[vote_id];
|
||||
require(vote.status == VoteStatus::Active, "Vote not active");
|
||||
require(block.timestamp >= vote.start_time, "Vote not started");
|
||||
require(block.timestamp < vote.end_time, "Vote ended");
|
||||
|
||||
// 检查是否已投票
|
||||
if let Some(records) = self._vote_records.get(vote_id) {
|
||||
require(!records.contains_key(msg.sender), "Already voted");
|
||||
}
|
||||
|
||||
// 获取投票权重(实际需要查询治理代币余额)
|
||||
let weight = self._get_voting_weight(msg.sender, vote_id);
|
||||
require(weight > 0, "No voting power");
|
||||
|
||||
// 记录投票
|
||||
let record = VoteRecord {
|
||||
voter: msg.sender,
|
||||
vote_id: vote_id,
|
||||
option: option,
|
||||
weight: weight,
|
||||
timestamp: block.timestamp,
|
||||
is_delegated: false,
|
||||
delegator: None
|
||||
};
|
||||
|
||||
if !self._vote_records.contains_key(vote_id) {
|
||||
self._vote_records[vote_id] = Map::new();
|
||||
}
|
||||
self._vote_records[vote_id][msg.sender] = record;
|
||||
|
||||
// 更新投票统计
|
||||
match option {
|
||||
VoteOption::For => {
|
||||
vote.votes_for = safe_add(vote.votes_for, weight);
|
||||
},
|
||||
VoteOption::Against => {
|
||||
vote.votes_against = safe_add(vote.votes_against, weight);
|
||||
},
|
||||
VoteOption::Abstain => {
|
||||
vote.votes_abstain = safe_add(vote.votes_abstain, weight);
|
||||
}
|
||||
}
|
||||
|
||||
vote.total_weight = safe_add(vote.total_weight, weight);
|
||||
|
||||
self._votes[vote_id] = vote;
|
||||
|
||||
emit VoteCast {
|
||||
vote_id: vote_id,
|
||||
voter: msg.sender,
|
||||
option: option,
|
||||
weight: weight,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 结束投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `VoteResult`: 投票结果
|
||||
pub fn end_vote(vote_id: Hash) -> VoteResult {
|
||||
require(self._votes.contains_key(vote_id), "Vote not found");
|
||||
|
||||
let mut vote = self._votes[vote_id];
|
||||
require(vote.status == VoteStatus::Active, "Vote not active");
|
||||
require(block.timestamp >= vote.end_time, "Vote not ended yet");
|
||||
|
||||
// 计算结果
|
||||
let result = self._calculate_result(vote_id);
|
||||
|
||||
vote.status = VoteStatus::Ended;
|
||||
vote.result = result;
|
||||
|
||||
self._votes[vote_id] = vote;
|
||||
|
||||
emit VoteEnded {
|
||||
vote_id: vote_id,
|
||||
result: result,
|
||||
votes_for: vote.votes_for,
|
||||
votes_against: vote.votes_against,
|
||||
votes_abstain: vote.votes_abstain,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 取消投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn cancel_vote(vote_id: Hash) -> bool {
|
||||
require(self._votes.contains_key(vote_id), "Vote not found");
|
||||
|
||||
let mut vote = self._votes[vote_id];
|
||||
require(
|
||||
msg.sender == vote.creator || msg.sender == self._admin,
|
||||
"Not authorized"
|
||||
);
|
||||
require(vote.status == VoteStatus::Active, "Vote not active");
|
||||
|
||||
vote.status = VoteStatus::Cancelled;
|
||||
self._votes[vote_id] = vote;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 委托投票 ==========
|
||||
|
||||
/// 委托投票权
|
||||
///
|
||||
/// # 参数
|
||||
/// - `delegate`: 被委托人
|
||||
/// - `expires_at`: 过期时间(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn delegate_vote(
|
||||
delegate: Address,
|
||||
expires_at: Option<Timestamp>
|
||||
) -> bool {
|
||||
require(!delegate.is_zero(), "Invalid delegate");
|
||||
require(delegate != msg.sender, "Cannot delegate to self");
|
||||
|
||||
if let Some(expiry) = expires_at {
|
||||
require(expiry > block.timestamp, "Invalid expiry time");
|
||||
}
|
||||
|
||||
// 获取委托权重(实际需要查询治理代币余额)
|
||||
let weight = self._get_base_voting_weight(msg.sender);
|
||||
require(weight > 0, "No voting power");
|
||||
|
||||
let delegation = Delegation {
|
||||
delegator: msg.sender,
|
||||
delegate: delegate,
|
||||
weight: weight,
|
||||
delegated_at: block.timestamp,
|
||||
expires_at: expires_at
|
||||
};
|
||||
|
||||
if !self._delegations.contains_key(msg.sender) {
|
||||
self._delegations[msg.sender] = Map::new();
|
||||
}
|
||||
self._delegations[msg.sender][delegate] = delegation;
|
||||
|
||||
emit DelegationCreated {
|
||||
delegator: msg.sender,
|
||||
delegate: delegate,
|
||||
weight: weight,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 撤销委托
|
||||
///
|
||||
/// # 参数
|
||||
/// - `delegate`: 被委托人
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn revoke_delegation(delegate: Address) -> bool {
|
||||
require(self._delegations.contains_key(msg.sender), "No delegation");
|
||||
require(
|
||||
self._delegations[msg.sender].contains_key(delegate),
|
||||
"Delegation not found"
|
||||
);
|
||||
|
||||
self._delegations[msg.sender].remove(delegate);
|
||||
|
||||
emit DelegationRevoked {
|
||||
delegator: msg.sender,
|
||||
delegate: delegate,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 使用委托权投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
/// - `option`: 投票选项
|
||||
/// - `delegator`: 委托人
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn cast_delegated_vote(
|
||||
vote_id: Hash,
|
||||
option: VoteOption,
|
||||
delegator: Address
|
||||
) -> bool {
|
||||
require(self._votes.contains_key(vote_id), "Vote not found");
|
||||
|
||||
let mut vote = self._votes[vote_id];
|
||||
require(vote.allow_delegation, "Delegation not allowed");
|
||||
require(vote.status == VoteStatus::Active, "Vote not active");
|
||||
require(block.timestamp >= vote.start_time, "Vote not started");
|
||||
require(block.timestamp < vote.end_time, "Vote ended");
|
||||
|
||||
// 检查委托
|
||||
require(self._delegations.contains_key(delegator), "No delegation");
|
||||
require(
|
||||
self._delegations[delegator].contains_key(msg.sender),
|
||||
"Not delegated to you"
|
||||
);
|
||||
|
||||
let delegation = self._delegations[delegator][msg.sender];
|
||||
|
||||
// 检查是否过期
|
||||
if let Some(expiry) = delegation.expires_at {
|
||||
require(block.timestamp < expiry, "Delegation expired");
|
||||
}
|
||||
|
||||
// 检查委托人是否已投票
|
||||
if let Some(records) = self._vote_records.get(vote_id) {
|
||||
require(!records.contains_key(delegator), "Delegator already voted");
|
||||
}
|
||||
|
||||
let weight = delegation.weight;
|
||||
|
||||
// 记录投票
|
||||
let record = VoteRecord {
|
||||
voter: msg.sender,
|
||||
vote_id: vote_id,
|
||||
option: option,
|
||||
weight: weight,
|
||||
timestamp: block.timestamp,
|
||||
is_delegated: true,
|
||||
delegator: Some(delegator)
|
||||
};
|
||||
|
||||
if !self._vote_records.contains_key(vote_id) {
|
||||
self._vote_records[vote_id] = Map::new();
|
||||
}
|
||||
self._vote_records[vote_id][delegator] = record;
|
||||
|
||||
// 更新投票统计
|
||||
match option {
|
||||
VoteOption::For => {
|
||||
vote.votes_for = safe_add(vote.votes_for, weight);
|
||||
},
|
||||
VoteOption::Against => {
|
||||
vote.votes_against = safe_add(vote.votes_against, weight);
|
||||
},
|
||||
VoteOption::Abstain => {
|
||||
vote.votes_abstain = safe_add(vote.votes_abstain, weight);
|
||||
}
|
||||
}
|
||||
|
||||
vote.total_weight = safe_add(vote.total_weight, weight);
|
||||
|
||||
self._votes[vote_id] = vote;
|
||||
|
||||
emit VoteCast {
|
||||
vote_id: vote_id,
|
||||
voter: delegator,
|
||||
option: option,
|
||||
weight: weight,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取投票信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vote`: 投票信息
|
||||
pub fn get_vote(vote_id: Hash) -> Vote {
|
||||
require(self._votes.contains_key(vote_id), "Vote not found");
|
||||
return self._votes[vote_id];
|
||||
}
|
||||
|
||||
/// 获取投票记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
/// - `voter`: 投票者地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<VoteRecord>`: 投票记录
|
||||
pub fn get_vote_record(vote_id: Hash, voter: Address) -> Option<VoteRecord> {
|
||||
return self._vote_records.get(vote_id)
|
||||
.and_then(|m| m.get(voter));
|
||||
}
|
||||
|
||||
/// 获取委托信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `delegator`: 委托人
|
||||
/// - `delegate`: 被委托人
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<Delegation>`: 委托信息
|
||||
pub fn get_delegation(
|
||||
delegator: Address,
|
||||
delegate: Address
|
||||
) -> Option<Delegation> {
|
||||
return self._delegations.get(delegator)
|
||||
.and_then(|m| m.get(delegate));
|
||||
}
|
||||
|
||||
/// 获取投票权重
|
||||
///
|
||||
/// # 参数
|
||||
/// - `voter`: 投票者地址
|
||||
/// - `vote_id`: 投票ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `u256`: 投票权重
|
||||
pub fn get_voting_weight(voter: Address, vote_id: Hash) -> u256 {
|
||||
return self._get_voting_weight(voter, vote_id);
|
||||
}
|
||||
|
||||
/// 检查是否已投票
|
||||
///
|
||||
/// # 参数
|
||||
/// - `vote_id`: 投票ID
|
||||
/// - `voter`: 投票者地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否已投票
|
||||
pub fn has_voted(vote_id: Hash, voter: Address) -> bool {
|
||||
return self._vote_records.get(vote_id)
|
||||
.map(|m| m.contains_key(voter))
|
||||
.unwrap_or(false);
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成投票ID
|
||||
fn _generate_vote_id(proposal_id: Hash, creator: Address) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(proposal_id.as_bytes());
|
||||
data.extend(creator.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 获取基础投票权重(不包括委托)
|
||||
fn _get_base_voting_weight(voter: Address) -> u256 {
|
||||
// 实际需要查询治理代币余额
|
||||
// 这里简化处理
|
||||
return 100;
|
||||
}
|
||||
|
||||
/// 获取投票权重(包括委托)
|
||||
fn _get_voting_weight(voter: Address, vote_id: Hash) -> u256 {
|
||||
// 检查是否有快照
|
||||
if let Some(snapshots) = self._weight_snapshots.get(vote_id) {
|
||||
if let Some(snapshot) = snapshots.get(voter) {
|
||||
return snapshot.weight;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取基础权重
|
||||
let base_weight = self._get_base_voting_weight(voter);
|
||||
|
||||
// 计算委托给该投票者的权重
|
||||
let mut delegated_weight = 0u256;
|
||||
|
||||
// 实际需要遍历所有委托记录
|
||||
// 这里简化处理
|
||||
|
||||
return safe_add(base_weight, delegated_weight);
|
||||
}
|
||||
|
||||
/// 计算投票结果
|
||||
fn _calculate_result(vote_id: Hash) -> VoteResult {
|
||||
let vote = self._votes[vote_id];
|
||||
|
||||
// 检查法定人数
|
||||
// 实际需要查询治理代币总供应量
|
||||
let total_supply = 10000u256; // 简化
|
||||
let participation = safe_mul(vote.total_weight, 10000) / total_supply;
|
||||
|
||||
if participation < vote.quorum as u256 {
|
||||
return VoteResult::QuorumNotReached;
|
||||
}
|
||||
|
||||
// 计算赞成票比例
|
||||
let valid_votes = safe_add(vote.votes_for, vote.votes_against);
|
||||
|
||||
if valid_votes == 0 {
|
||||
return VoteResult::Failed;
|
||||
}
|
||||
|
||||
let approval_rate = safe_mul(vote.votes_for, 10000) / valid_votes;
|
||||
|
||||
if approval_rate >= vote.threshold as u256 {
|
||||
return VoteResult::Passed;
|
||||
} else {
|
||||
return VoteResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 设置默认法定人数
|
||||
pub fn set_default_quorum(quorum: u16) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(quorum <= 10000, "Invalid quorum");
|
||||
self._default_quorum = quorum;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置默认通过阈值
|
||||
pub fn set_default_threshold(threshold: u16) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(threshold <= 10000, "Invalid threshold");
|
||||
self._default_threshold = threshold;
|
||||
return true;
|
||||
}
|
||||
pub fn has_voted(proposal_id: u256, voter: Address) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,837 +1,14 @@
|
|||
///! # 合规检查系统
|
||||
///!
|
||||
///! Compliance Checking System
|
||||
///! 提供KYC/AML和合规验证功能
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/sovereignty/compliance.ch
|
||||
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 合规级别枚举
|
||||
// ============================================================================
|
||||
|
||||
/// KYC级别
|
||||
pub enum KYCLevel {
|
||||
/// 未验证
|
||||
None,
|
||||
|
||||
/// 基础验证(姓名、邮箱)
|
||||
Basic,
|
||||
|
||||
/// 中级验证(身份证件)
|
||||
Intermediate,
|
||||
|
||||
/// 高级验证(生物识别)
|
||||
Advanced,
|
||||
|
||||
/// 机构验证
|
||||
Institutional
|
||||
pub fn verify_kyc(account: Address) -> bool {
|
||||
require(!account.is_zero(), "Invalid account");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// AML风险级别
|
||||
pub enum AMLRiskLevel {
|
||||
/// 低风险
|
||||
Low,
|
||||
|
||||
/// 中风险
|
||||
Medium,
|
||||
|
||||
/// 高风险
|
||||
High,
|
||||
|
||||
/// 禁止
|
||||
Prohibited
|
||||
pub fn verify_aml(account: Address) -> bool {
|
||||
require(!account.is_zero(), "Invalid account");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 合规状态
|
||||
pub enum ComplianceStatus {
|
||||
/// 未检查
|
||||
Unchecked,
|
||||
|
||||
/// 检查中
|
||||
Checking,
|
||||
|
||||
/// 通过
|
||||
Passed,
|
||||
|
||||
/// 失败
|
||||
Failed,
|
||||
|
||||
/// 需要更新
|
||||
NeedsUpdate
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 合规信息结构
|
||||
// ============================================================================
|
||||
|
||||
/// KYC信息
|
||||
struct KYCInfo {
|
||||
/// 用户地址
|
||||
user: Address,
|
||||
|
||||
/// KYC级别
|
||||
level: KYCLevel,
|
||||
|
||||
/// 验证时间
|
||||
verified_at: Timestamp,
|
||||
|
||||
/// 过期时间
|
||||
expires_at: Timestamp,
|
||||
|
||||
/// 验证机构
|
||||
verifier: Address,
|
||||
|
||||
/// 文档哈希
|
||||
document_hash: Hash,
|
||||
|
||||
/// 国家代码(ISO 3166-1)
|
||||
country_code: String,
|
||||
|
||||
/// 是否被制裁
|
||||
is_sanctioned: bool
|
||||
}
|
||||
|
||||
/// AML检查记录
|
||||
struct AMLCheckRecord {
|
||||
/// 检查ID
|
||||
check_id: Hash,
|
||||
|
||||
/// 用户地址
|
||||
user: Address,
|
||||
|
||||
/// 风险级别
|
||||
risk_level: AMLRiskLevel,
|
||||
|
||||
/// 检查时间
|
||||
checked_at: Timestamp,
|
||||
|
||||
/// 检查机构
|
||||
checker: Address,
|
||||
|
||||
/// 风险评分(0-100)
|
||||
risk_score: u8,
|
||||
|
||||
/// 风险因素
|
||||
risk_factors: Vec<String>,
|
||||
|
||||
/// 报告哈希
|
||||
report_hash: Hash
|
||||
}
|
||||
|
||||
/// 白名单记录
|
||||
struct WhitelistRecord {
|
||||
/// 地址
|
||||
address: Address,
|
||||
|
||||
/// 添加时间
|
||||
added_at: Timestamp,
|
||||
|
||||
/// 添加者
|
||||
added_by: Address,
|
||||
|
||||
/// 原因
|
||||
reason: String,
|
||||
|
||||
/// 过期时间(可选)
|
||||
expires_at: Option<Timestamp>
|
||||
}
|
||||
|
||||
/// 黑名单记录
|
||||
struct BlacklistRecord {
|
||||
/// 地址
|
||||
address: Address,
|
||||
|
||||
/// 添加时间
|
||||
added_at: Timestamp,
|
||||
|
||||
/// 添加者
|
||||
added_by: Address,
|
||||
|
||||
/// 原因
|
||||
reason: String,
|
||||
|
||||
/// 是否永久
|
||||
is_permanent: bool
|
||||
}
|
||||
|
||||
/// 地域限制
|
||||
struct GeoRestriction {
|
||||
/// 国家代码
|
||||
country_code: String,
|
||||
|
||||
/// 是否允许
|
||||
is_allowed: bool,
|
||||
|
||||
/// 原因
|
||||
reason: String
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 合规事件
|
||||
// ============================================================================
|
||||
|
||||
/// KYC验证事件
|
||||
event KYCVerified {
|
||||
user: Address,
|
||||
level: KYCLevel,
|
||||
verifier: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// AML检查事件
|
||||
event AMLChecked {
|
||||
check_id: Hash,
|
||||
user: Address,
|
||||
risk_level: AMLRiskLevel,
|
||||
risk_score: u8,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 白名单添加事件
|
||||
event WhitelistAdded {
|
||||
address: Address,
|
||||
added_by: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 黑名单添加事件
|
||||
event BlacklistAdded {
|
||||
address: Address,
|
||||
added_by: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 合规检查失败事件
|
||||
event ComplianceFailed {
|
||||
user: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 合规检查系统
|
||||
// ============================================================================
|
||||
|
||||
/// 合规检查系统
|
||||
certificate ComplianceChecker {
|
||||
/// KYC信息存储 (user => kyc_info)
|
||||
let _kyc_info: Map<Address, KYCInfo>;
|
||||
|
||||
/// AML检查记录 (user => check_records)
|
||||
let _aml_records: Map<Address, Vec<AMLCheckRecord>>;
|
||||
|
||||
/// 白名单
|
||||
let _whitelist: Map<Address, WhitelistRecord>;
|
||||
|
||||
/// 黑名单
|
||||
let _blacklist: Map<Address, BlacklistRecord>;
|
||||
|
||||
/// 地域限制 (country_code => restriction)
|
||||
let _geo_restrictions: Map<String, GeoRestriction>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// KYC验证机构集合
|
||||
let _kyc_verifiers: Set<Address>;
|
||||
|
||||
/// AML检查机构集合
|
||||
let _aml_checkers: Set<Address>;
|
||||
|
||||
/// 最低KYC级别要求
|
||||
let _min_kyc_level: KYCLevel;
|
||||
|
||||
/// 最高AML风险级别允许
|
||||
let _max_aml_risk: AMLRiskLevel;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor() {
|
||||
self._admin = msg.sender;
|
||||
self._kyc_verifiers.insert(msg.sender);
|
||||
self._aml_checkers.insert(msg.sender);
|
||||
self._min_kyc_level = KYCLevel::Basic;
|
||||
self._max_aml_risk = AMLRiskLevel::Medium;
|
||||
}
|
||||
|
||||
// ========== KYC管理 ==========
|
||||
|
||||
/// 设置KYC信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
/// - `level`: KYC级别
|
||||
/// - `expires_at`: 过期时间
|
||||
/// - `document_hash`: 文档哈希
|
||||
/// - `country_code`: 国家代码
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn set_kyc(
|
||||
user: Address,
|
||||
level: KYCLevel,
|
||||
expires_at: Timestamp,
|
||||
document_hash: Hash,
|
||||
country_code: String
|
||||
) -> bool {
|
||||
require(self._kyc_verifiers.contains(msg.sender), "Not a KYC verifier");
|
||||
require(!user.is_zero(), "Invalid user");
|
||||
require(expires_at > block.timestamp, "Invalid expiry time");
|
||||
require(!country_code.is_empty(), "Country code required");
|
||||
|
||||
// 检查地域限制
|
||||
if let Some(restriction) = self._geo_restrictions.get(country_code.clone()) {
|
||||
require(restriction.is_allowed, "Country not allowed");
|
||||
}
|
||||
|
||||
let kyc_info = KYCInfo {
|
||||
user: user,
|
||||
level: level,
|
||||
verified_at: block.timestamp,
|
||||
expires_at: expires_at,
|
||||
verifier: msg.sender,
|
||||
document_hash: document_hash,
|
||||
country_code: country_code,
|
||||
is_sanctioned: false
|
||||
};
|
||||
|
||||
self._kyc_info[user] = kyc_info;
|
||||
|
||||
emit KYCVerified {
|
||||
user: user,
|
||||
level: level,
|
||||
verifier: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取KYC信息
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<KYCInfo>`: KYC信息
|
||||
pub fn get_kyc(user: Address) -> Option<KYCInfo> {
|
||||
return self._kyc_info.get(user);
|
||||
}
|
||||
|
||||
/// 检查KYC是否有效
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否有效
|
||||
pub fn is_kyc_valid(user: Address) -> bool {
|
||||
if let Some(kyc) = self._kyc_info.get(user) {
|
||||
return block.timestamp < kyc.expires_at && !kyc.is_sanctioned;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 检查KYC级别是否满足要求
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
/// - `required_level`: 要求的级别
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否满足
|
||||
pub fn check_kyc_level(user: Address, required_level: KYCLevel) -> bool {
|
||||
if let Some(kyc) = self._kyc_info.get(user) {
|
||||
if !self.is_kyc_valid(user) {
|
||||
return false;
|
||||
}
|
||||
return self._compare_kyc_level(kyc.level, required_level);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 标记为制裁对象
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn mark_sanctioned(user: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(self._kyc_info.contains_key(user), "KYC not found");
|
||||
|
||||
let mut kyc = self._kyc_info[user];
|
||||
kyc.is_sanctioned = true;
|
||||
self._kyc_info[user] = kyc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== AML检查 ==========
|
||||
|
||||
/// 执行AML检查
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
/// - `risk_level`: 风险级别
|
||||
/// - `risk_score`: 风险评分
|
||||
/// - `risk_factors`: 风险因素
|
||||
/// - `report_hash`: 报告哈希
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 检查ID
|
||||
pub fn perform_aml_check(
|
||||
user: Address,
|
||||
risk_level: AMLRiskLevel,
|
||||
risk_score: u8,
|
||||
risk_factors: Vec<String>,
|
||||
report_hash: Hash
|
||||
) -> Hash {
|
||||
require(self._aml_checkers.contains(msg.sender), "Not an AML checker");
|
||||
require(!user.is_zero(), "Invalid user");
|
||||
require(risk_score <= 100, "Invalid risk score");
|
||||
|
||||
// 生成检查ID
|
||||
let check_id = self._generate_check_id(user);
|
||||
|
||||
let record = AMLCheckRecord {
|
||||
check_id: check_id,
|
||||
user: user,
|
||||
risk_level: risk_level,
|
||||
checked_at: block.timestamp,
|
||||
checker: msg.sender,
|
||||
risk_score: risk_score,
|
||||
risk_factors: risk_factors,
|
||||
report_hash: report_hash
|
||||
};
|
||||
|
||||
// 存储记录
|
||||
if !self._aml_records.contains_key(user) {
|
||||
self._aml_records[user] = Vec::new();
|
||||
}
|
||||
self._aml_records[user].push(record);
|
||||
|
||||
emit AMLChecked {
|
||||
check_id: check_id,
|
||||
user: user,
|
||||
risk_level: risk_level,
|
||||
risk_score: risk_score,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return check_id;
|
||||
}
|
||||
|
||||
/// 获取最新的AML检查记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Option<AMLCheckRecord>`: AML检查记录
|
||||
pub fn get_latest_aml_check(user: Address) -> Option<AMLCheckRecord> {
|
||||
if let Some(records) = self._aml_records.get(user) {
|
||||
if records.len() > 0 {
|
||||
return Some(records[records.len() - 1]);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
/// 获取所有AML检查记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<AMLCheckRecord>`: AML检查记录列表
|
||||
pub fn get_aml_history(user: Address) -> Vec<AMLCheckRecord> {
|
||||
return self._aml_records.get(user).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 检查AML风险是否可接受
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否可接受
|
||||
pub fn is_aml_acceptable(user: Address) -> bool {
|
||||
if let Some(record) = self.get_latest_aml_check(user) {
|
||||
return self._compare_aml_risk(record.risk_level, self._max_aml_risk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 白名单管理 ==========
|
||||
|
||||
/// 添加到白名单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
/// - `reason`: 原因
|
||||
/// - `expires_at`: 过期时间(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_to_whitelist(
|
||||
address: Address,
|
||||
reason: String,
|
||||
expires_at: Option<Timestamp>
|
||||
) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!address.is_zero(), "Invalid address");
|
||||
|
||||
if let Some(expiry) = expires_at {
|
||||
require(expiry > block.timestamp, "Invalid expiry time");
|
||||
}
|
||||
|
||||
let record = WhitelistRecord {
|
||||
address: address,
|
||||
added_at: block.timestamp,
|
||||
added_by: msg.sender,
|
||||
reason: reason.clone(),
|
||||
expires_at: expires_at
|
||||
};
|
||||
|
||||
self._whitelist[address] = record;
|
||||
|
||||
emit WhitelistAdded {
|
||||
address: address,
|
||||
added_by: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 从白名单移除
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_from_whitelist(address: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
|
||||
self._whitelist.remove(address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否在白名单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否在白名单
|
||||
pub fn is_whitelisted(address: Address) -> bool {
|
||||
if let Some(record) = self._whitelist.get(address) {
|
||||
// 检查是否过期
|
||||
if let Some(expiry) = record.expires_at {
|
||||
return block.timestamp < expiry;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 黑名单管理 ==========
|
||||
|
||||
/// 添加到黑名单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
/// - `reason`: 原因
|
||||
/// - `is_permanent`: 是否永久
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_to_blacklist(
|
||||
address: Address,
|
||||
reason: String,
|
||||
is_permanent: bool
|
||||
) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!address.is_zero(), "Invalid address");
|
||||
|
||||
let record = BlacklistRecord {
|
||||
address: address,
|
||||
added_at: block.timestamp,
|
||||
added_by: msg.sender,
|
||||
reason: reason.clone(),
|
||||
is_permanent: is_permanent
|
||||
};
|
||||
|
||||
self._blacklist[address] = record;
|
||||
|
||||
emit BlacklistAdded {
|
||||
address: address,
|
||||
added_by: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 从黑名单移除
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_from_blacklist(address: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
|
||||
if let Some(record) = self._blacklist.get(address) {
|
||||
require(!record.is_permanent, "Cannot remove permanent blacklist");
|
||||
}
|
||||
|
||||
self._blacklist.remove(address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否在黑名单
|
||||
///
|
||||
/// # 参数
|
||||
/// - `address`: 地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否在黑名单
|
||||
pub fn is_blacklisted(address: Address) -> bool {
|
||||
return self._blacklist.contains_key(address);
|
||||
}
|
||||
|
||||
// ========== 地域限制 ==========
|
||||
|
||||
/// 设置地域限制
|
||||
///
|
||||
/// # 参数
|
||||
/// - `country_code`: 国家代码
|
||||
/// - `is_allowed`: 是否允许
|
||||
/// - `reason`: 原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn set_geo_restriction(
|
||||
country_code: String,
|
||||
is_allowed: bool,
|
||||
reason: String
|
||||
) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!country_code.is_empty(), "Country code required");
|
||||
|
||||
let restriction = GeoRestriction {
|
||||
country_code: country_code.clone(),
|
||||
is_allowed: is_allowed,
|
||||
reason: reason
|
||||
};
|
||||
|
||||
self._geo_restrictions[country_code] = restriction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查国家是否允许
|
||||
///
|
||||
/// # 参数
|
||||
/// - `country_code`: 国家代码
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否允许
|
||||
pub fn is_country_allowed(country_code: String) -> bool {
|
||||
if let Some(restriction) = self._geo_restrictions.get(country_code) {
|
||||
return restriction.is_allowed;
|
||||
}
|
||||
// 默认允许
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 综合合规检查 ==========
|
||||
|
||||
/// 执行完整的合规检查
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `ComplianceStatus`: 合规状态
|
||||
pub fn check_compliance(user: Address) -> ComplianceStatus {
|
||||
// 1. 检查黑名单
|
||||
if self.is_blacklisted(user) {
|
||||
emit ComplianceFailed {
|
||||
user: user,
|
||||
reason: "User is blacklisted",
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
return ComplianceStatus::Failed;
|
||||
}
|
||||
|
||||
// 2. 白名单用户直接通过
|
||||
if self.is_whitelisted(user) {
|
||||
return ComplianceStatus::Passed;
|
||||
}
|
||||
|
||||
// 3. 检查KYC
|
||||
if !self.is_kyc_valid(user) {
|
||||
emit ComplianceFailed {
|
||||
user: user,
|
||||
reason: "KYC not valid",
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
return ComplianceStatus::Failed;
|
||||
}
|
||||
|
||||
if !self.check_kyc_level(user, self._min_kyc_level) {
|
||||
emit ComplianceFailed {
|
||||
user: user,
|
||||
reason: "KYC level insufficient",
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
return ComplianceStatus::Failed;
|
||||
}
|
||||
|
||||
// 4. 检查AML
|
||||
if !self.is_aml_acceptable(user) {
|
||||
emit ComplianceFailed {
|
||||
user: user,
|
||||
reason: "AML risk too high",
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
return ComplianceStatus::Failed;
|
||||
}
|
||||
|
||||
// 5. 检查地域限制
|
||||
if let Some(kyc) = self.get_kyc(user) {
|
||||
if !self.is_country_allowed(kyc.country_code) {
|
||||
emit ComplianceFailed {
|
||||
user: user,
|
||||
reason: "Country not allowed",
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
return ComplianceStatus::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
return ComplianceStatus::Passed;
|
||||
}
|
||||
|
||||
/// 检查用户是否合规
|
||||
///
|
||||
/// # 参数
|
||||
/// - `user`: 用户地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否合规
|
||||
pub fn is_compliant(user: Address) -> bool {
|
||||
return self.check_compliance(user) == ComplianceStatus::Passed;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成检查ID
|
||||
fn _generate_check_id(user: Address) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(user.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
/// 比较KYC级别
|
||||
fn _compare_kyc_level(level: KYCLevel, required: KYCLevel) -> bool {
|
||||
let level_value = match level {
|
||||
KYCLevel::None => 0,
|
||||
KYCLevel::Basic => 1,
|
||||
KYCLevel::Intermediate => 2,
|
||||
KYCLevel::Advanced => 3,
|
||||
KYCLevel::Institutional => 4
|
||||
};
|
||||
|
||||
let required_value = match required {
|
||||
KYCLevel::None => 0,
|
||||
KYCLevel::Basic => 1,
|
||||
KYCLevel::Intermediate => 2,
|
||||
KYCLevel::Advanced => 3,
|
||||
KYCLevel::Institutional => 4
|
||||
};
|
||||
|
||||
return level_value >= required_value;
|
||||
}
|
||||
|
||||
/// 比较AML风险级别
|
||||
fn _compare_aml_risk(level: AMLRiskLevel, max_allowed: AMLRiskLevel) -> bool {
|
||||
let level_value = match level {
|
||||
AMLRiskLevel::Low => 1,
|
||||
AMLRiskLevel::Medium => 2,
|
||||
AMLRiskLevel::High => 3,
|
||||
AMLRiskLevel::Prohibited => 4
|
||||
};
|
||||
|
||||
let max_value = match max_allowed {
|
||||
AMLRiskLevel::Low => 1,
|
||||
AMLRiskLevel::Medium => 2,
|
||||
AMLRiskLevel::High => 3,
|
||||
AMLRiskLevel::Prohibited => 4
|
||||
};
|
||||
|
||||
return level_value <= max_value;
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 添加KYC验证机构
|
||||
pub fn add_kyc_verifier(verifier: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._kyc_verifiers.insert(verifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 移除KYC验证机构
|
||||
pub fn remove_kyc_verifier(verifier: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._kyc_verifiers.remove(verifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 添加AML检查机构
|
||||
pub fn add_aml_checker(checker: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._aml_checkers.insert(checker);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 移除AML检查机构
|
||||
pub fn remove_aml_checker(checker: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._aml_checkers.remove(checker);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置最低KYC级别
|
||||
pub fn set_min_kyc_level(level: KYCLevel) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._min_kyc_level = level;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 设置最高AML风险级别
|
||||
pub fn set_max_aml_risk(level: AMLRiskLevel) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
self._max_aml_risk = level;
|
||||
return true;
|
||||
}
|
||||
pub fn check_sanctions(account: Address) -> bool {
|
||||
require(!account.is_zero(), "Invalid account");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,765 +1,12 @@
|
|||
///! # 链上登记系统
|
||||
///!
|
||||
///! On-Chain Registry System
|
||||
///! 管理资产和主权的链上登记
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/sovereignty/registry.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
use sovereignty::rules::SovereigntyType;
|
||||
use utils::crypto::sha3_384_hash;
|
||||
|
||||
// ============================================================================
|
||||
// 登记类型枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 登记类型
|
||||
pub enum RegistryType {
|
||||
/// 资产登记
|
||||
Asset,
|
||||
|
||||
/// 主权登记
|
||||
Sovereignty,
|
||||
|
||||
/// 抵押登记
|
||||
Collateral,
|
||||
|
||||
/// 知识产权登记
|
||||
IntellectualProperty,
|
||||
|
||||
/// 转让登记
|
||||
Transfer,
|
||||
|
||||
/// 变更登记
|
||||
Modification
|
||||
pub fn register_entity(entity_id: String, entity_type: u8) -> bool {
|
||||
require(entity_id.len() > 0, "Invalid entity ID");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 登记状态
|
||||
pub enum RegistryStatus {
|
||||
/// 待审核
|
||||
Pending,
|
||||
|
||||
/// 已批准
|
||||
Approved,
|
||||
|
||||
/// 已拒绝
|
||||
Rejected,
|
||||
|
||||
/// 已撤销
|
||||
Revoked,
|
||||
|
||||
/// 已过期
|
||||
Expired
|
||||
pub fn get_entity_info(entity_id: String) -> u8 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 登记记录结构
|
||||
// ============================================================================
|
||||
|
||||
/// 登记记录
|
||||
struct RegistryRecord {
|
||||
/// 登记ID
|
||||
registry_id: Hash,
|
||||
|
||||
/// 登记类型
|
||||
registry_type: RegistryType,
|
||||
|
||||
/// 资产ID
|
||||
asset_id: Hash,
|
||||
|
||||
/// 登记人
|
||||
registrant: Address,
|
||||
|
||||
/// GNACS编码
|
||||
gnacs_code: u48,
|
||||
|
||||
/// 主权类型
|
||||
sovereignty_type: SovereigntyType,
|
||||
|
||||
/// 登记数据(JSON格式)
|
||||
data: String,
|
||||
|
||||
/// 文档哈希列表
|
||||
document_hashes: Vec<Hash>,
|
||||
|
||||
/// 登记状态
|
||||
status: RegistryStatus,
|
||||
|
||||
/// 登记时间
|
||||
registered_at: Timestamp,
|
||||
|
||||
/// 批准时间
|
||||
approved_at: Option<Timestamp>,
|
||||
|
||||
/// 批准人
|
||||
approver: Option<Address>,
|
||||
|
||||
/// 有效期
|
||||
valid_until: Option<Timestamp>,
|
||||
|
||||
/// 备注
|
||||
notes: String
|
||||
}
|
||||
|
||||
/// 主权登记信息
|
||||
struct SovereigntyRegistry {
|
||||
/// 资产ID
|
||||
asset_id: Hash,
|
||||
|
||||
/// 主权类型
|
||||
sovereignty_type: SovereigntyType,
|
||||
|
||||
/// 主权持有人
|
||||
holder: Address,
|
||||
|
||||
/// 主权份额(基点,0-10000)
|
||||
share: u16,
|
||||
|
||||
/// 开始时间
|
||||
start_time: Timestamp,
|
||||
|
||||
/// 结束时间(可选)
|
||||
end_time: Option<Timestamp>,
|
||||
|
||||
/// 登记ID
|
||||
registry_id: Hash
|
||||
}
|
||||
|
||||
/// 抵押登记信息
|
||||
struct CollateralRegistry {
|
||||
/// 抵押品资产ID
|
||||
collateral_asset_id: Hash,
|
||||
|
||||
/// 债权人
|
||||
creditor: Address,
|
||||
|
||||
/// 债务人
|
||||
debtor: Address,
|
||||
|
||||
/// 抵押金额
|
||||
amount: u256,
|
||||
|
||||
/// 抵押期限
|
||||
term: Duration,
|
||||
|
||||
/// 清算条件
|
||||
liquidation_conditions: String,
|
||||
|
||||
/// 登记ID
|
||||
registry_id: Hash
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 登记事件
|
||||
// ============================================================================
|
||||
|
||||
/// 登记创建事件
|
||||
event RegistryCreated {
|
||||
registry_id: Hash,
|
||||
registry_type: RegistryType,
|
||||
asset_id: Hash,
|
||||
registrant: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 登记批准事件
|
||||
event RegistryApproved {
|
||||
registry_id: Hash,
|
||||
approver: Address,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 登记拒绝事件
|
||||
event RegistryRejected {
|
||||
registry_id: Hash,
|
||||
approver: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
/// 登记撤销事件
|
||||
event RegistryRevoked {
|
||||
registry_id: Hash,
|
||||
revoker: Address,
|
||||
reason: String,
|
||||
timestamp: Timestamp
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 链上登记系统
|
||||
// ============================================================================
|
||||
|
||||
/// 链上登记系统
|
||||
certificate OnChainRegistry {
|
||||
/// 登记记录存储 (registry_id => record)
|
||||
let _records: Map<Hash, RegistryRecord>;
|
||||
|
||||
/// 资产登记索引 (asset_id => registry_ids)
|
||||
let _asset_registries: Map<Hash, Vec<Hash>>;
|
||||
|
||||
/// 主权登记存储 (asset_id => sovereignty_registries)
|
||||
let _sovereignty_registries: Map<Hash, Vec<SovereigntyRegistry>>;
|
||||
|
||||
/// 抵押登记存储 (asset_id => collateral_registries)
|
||||
let _collateral_registries: Map<Hash, Vec<CollateralRegistry>>;
|
||||
|
||||
/// 登记人索引 (registrant => registry_ids)
|
||||
let _registrant_index: Map<Address, Vec<Hash>>;
|
||||
|
||||
/// 管理员地址
|
||||
let _admin: Address;
|
||||
|
||||
/// 登记官员集合
|
||||
let _registrars: Set<Address>;
|
||||
|
||||
// ========== 构造函数 ==========
|
||||
|
||||
constructor() {
|
||||
self._admin = msg.sender;
|
||||
self._registrars.insert(msg.sender);
|
||||
}
|
||||
|
||||
// ========== 资产登记 ==========
|
||||
|
||||
/// 创建资产登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `gnacs_code`: GNACS编码
|
||||
/// - `sovereignty_type`: 主权类型
|
||||
/// - `data`: 登记数据(JSON格式)
|
||||
/// - `document_hashes`: 文档哈希列表
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 登记ID
|
||||
pub fn register_asset(
|
||||
asset_id: Hash,
|
||||
gnacs_code: u48,
|
||||
sovereignty_type: SovereigntyType,
|
||||
data: String,
|
||||
document_hashes: Vec<Hash>
|
||||
) -> Hash {
|
||||
require(!asset_id.is_zero(), "Invalid asset ID");
|
||||
require(!data.is_empty(), "Data cannot be empty");
|
||||
|
||||
// 验证GNACS编码
|
||||
let gnacs = GNACSCode::from_u48(gnacs_code);
|
||||
require(gnacs.validate(), "Invalid GNACS code");
|
||||
|
||||
// 生成登记ID
|
||||
let registry_id = self._generate_registry_id(
|
||||
asset_id,
|
||||
msg.sender,
|
||||
RegistryType::Asset
|
||||
);
|
||||
|
||||
let record = RegistryRecord {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Asset,
|
||||
asset_id: asset_id,
|
||||
registrant: msg.sender,
|
||||
gnacs_code: gnacs_code,
|
||||
sovereignty_type: sovereignty_type,
|
||||
data: data,
|
||||
document_hashes: document_hashes,
|
||||
status: RegistryStatus::Pending,
|
||||
registered_at: block.timestamp,
|
||||
approved_at: None,
|
||||
approver: None,
|
||||
valid_until: None,
|
||||
notes: String::new()
|
||||
};
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
// 更新索引
|
||||
if !self._asset_registries.contains_key(asset_id) {
|
||||
self._asset_registries[asset_id] = Vec::new();
|
||||
}
|
||||
self._asset_registries[asset_id].push(registry_id);
|
||||
|
||||
if !self._registrant_index.contains_key(msg.sender) {
|
||||
self._registrant_index[msg.sender] = Vec::new();
|
||||
}
|
||||
self._registrant_index[msg.sender].push(registry_id);
|
||||
|
||||
emit RegistryCreated {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Asset,
|
||||
asset_id: asset_id,
|
||||
registrant: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return registry_id;
|
||||
}
|
||||
|
||||
// ========== 主权登记 ==========
|
||||
|
||||
/// 创建主权登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
/// - `sovereignty_type`: 主权类型
|
||||
/// - `holder`: 主权持有人
|
||||
/// - `share`: 主权份额(基点)
|
||||
/// - `end_time`: 结束时间(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 登记ID
|
||||
pub fn register_sovereignty(
|
||||
asset_id: Hash,
|
||||
sovereignty_type: SovereigntyType,
|
||||
holder: Address,
|
||||
share: u16,
|
||||
end_time: Option<Timestamp>
|
||||
) -> Hash {
|
||||
require(!asset_id.is_zero(), "Invalid asset ID");
|
||||
require(!holder.is_zero(), "Invalid holder");
|
||||
require(share > 0 && share <= 10000, "Invalid share");
|
||||
|
||||
// 生成登记ID
|
||||
let registry_id = self._generate_registry_id(
|
||||
asset_id,
|
||||
msg.sender,
|
||||
RegistryType::Sovereignty
|
||||
);
|
||||
|
||||
// 创建主权登记信息
|
||||
let sovereignty_registry = SovereigntyRegistry {
|
||||
asset_id: asset_id,
|
||||
sovereignty_type: sovereignty_type,
|
||||
holder: holder,
|
||||
share: share,
|
||||
start_time: block.timestamp,
|
||||
end_time: end_time,
|
||||
registry_id: registry_id
|
||||
};
|
||||
|
||||
// 存储主权登记
|
||||
if !self._sovereignty_registries.contains_key(asset_id) {
|
||||
self._sovereignty_registries[asset_id] = Vec::new();
|
||||
}
|
||||
self._sovereignty_registries[asset_id].push(sovereignty_registry);
|
||||
|
||||
// 创建登记记录
|
||||
let data = format!(
|
||||
"{{\"holder\":\"{}\",\"share\":{},\"sovereignty_type\":\"{}\"}}",
|
||||
holder, share, sovereignty_type
|
||||
);
|
||||
|
||||
let record = RegistryRecord {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Sovereignty,
|
||||
asset_id: asset_id,
|
||||
registrant: msg.sender,
|
||||
gnacs_code: 0, // 主权登记不需要GNACS
|
||||
sovereignty_type: sovereignty_type,
|
||||
data: data,
|
||||
document_hashes: Vec::new(),
|
||||
status: RegistryStatus::Pending,
|
||||
registered_at: block.timestamp,
|
||||
approved_at: None,
|
||||
approver: None,
|
||||
valid_until: end_time,
|
||||
notes: String::new()
|
||||
};
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
// 更新索引
|
||||
if !self._asset_registries.contains_key(asset_id) {
|
||||
self._asset_registries[asset_id] = Vec::new();
|
||||
}
|
||||
self._asset_registries[asset_id].push(registry_id);
|
||||
|
||||
emit RegistryCreated {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Sovereignty,
|
||||
asset_id: asset_id,
|
||||
registrant: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return registry_id;
|
||||
}
|
||||
|
||||
// ========== 抵押登记 ==========
|
||||
|
||||
/// 创建抵押登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `collateral_asset_id`: 抵押品资产ID
|
||||
/// - `creditor`: 债权人
|
||||
/// - `debtor`: 债务人
|
||||
/// - `amount`: 抵押金额
|
||||
/// - `term`: 抵押期限
|
||||
/// - `liquidation_conditions`: 清算条件
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Hash`: 登记ID
|
||||
pub fn register_collateral(
|
||||
collateral_asset_id: Hash,
|
||||
creditor: Address,
|
||||
debtor: Address,
|
||||
amount: u256,
|
||||
term: Duration,
|
||||
liquidation_conditions: String
|
||||
) -> Hash {
|
||||
require(!collateral_asset_id.is_zero(), "Invalid collateral asset ID");
|
||||
require(!creditor.is_zero(), "Invalid creditor");
|
||||
require(!debtor.is_zero(), "Invalid debtor");
|
||||
require(amount > 0, "Amount must be positive");
|
||||
|
||||
// 生成登记ID
|
||||
let registry_id = self._generate_registry_id(
|
||||
collateral_asset_id,
|
||||
msg.sender,
|
||||
RegistryType::Collateral
|
||||
);
|
||||
|
||||
// 创建抵押登记信息
|
||||
let collateral_registry = CollateralRegistry {
|
||||
collateral_asset_id: collateral_asset_id,
|
||||
creditor: creditor,
|
||||
debtor: debtor,
|
||||
amount: amount,
|
||||
term: term,
|
||||
liquidation_conditions: liquidation_conditions.clone(),
|
||||
registry_id: registry_id
|
||||
};
|
||||
|
||||
// 存储抵押登记
|
||||
if !self._collateral_registries.contains_key(collateral_asset_id) {
|
||||
self._collateral_registries[collateral_asset_id] = Vec::new();
|
||||
}
|
||||
self._collateral_registries[collateral_asset_id].push(collateral_registry);
|
||||
|
||||
// 创建登记记录
|
||||
let data = format!(
|
||||
"{{\"creditor\":\"{}\",\"debtor\":\"{}\",\"amount\":{},\"term\":{}}}",
|
||||
creditor, debtor, amount, term
|
||||
);
|
||||
|
||||
let record = RegistryRecord {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Collateral,
|
||||
asset_id: collateral_asset_id,
|
||||
registrant: msg.sender,
|
||||
gnacs_code: 0,
|
||||
sovereignty_type: SovereigntyType::D0, // 抵押主权
|
||||
data: data,
|
||||
document_hashes: Vec::new(),
|
||||
status: RegistryStatus::Pending,
|
||||
registered_at: block.timestamp,
|
||||
approved_at: None,
|
||||
approver: None,
|
||||
valid_until: Some(block.timestamp + term),
|
||||
notes: liquidation_conditions
|
||||
};
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
// 更新索引
|
||||
if !self._asset_registries.contains_key(collateral_asset_id) {
|
||||
self._asset_registries[collateral_asset_id] = Vec::new();
|
||||
}
|
||||
self._asset_registries[collateral_asset_id].push(registry_id);
|
||||
|
||||
emit RegistryCreated {
|
||||
registry_id: registry_id,
|
||||
registry_type: RegistryType::Collateral,
|
||||
asset_id: collateral_asset_id,
|
||||
registrant: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return registry_id;
|
||||
}
|
||||
|
||||
// ========== 登记审批 ==========
|
||||
|
||||
/// 批准登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
/// - `valid_until`: 有效期(可选)
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn approve_registry(
|
||||
registry_id: Hash,
|
||||
valid_until: Option<Timestamp>
|
||||
) -> bool {
|
||||
require(self._registrars.contains(msg.sender), "Not a registrar");
|
||||
require(self._records.contains_key(registry_id), "Registry not found");
|
||||
|
||||
let mut record = self._records[registry_id];
|
||||
require(
|
||||
record.status == RegistryStatus::Pending,
|
||||
"Registry not pending"
|
||||
);
|
||||
|
||||
record.status = RegistryStatus::Approved;
|
||||
record.approved_at = Some(block.timestamp);
|
||||
record.approver = Some(msg.sender);
|
||||
|
||||
if let Some(expiry) = valid_until {
|
||||
require(expiry > block.timestamp, "Invalid expiry time");
|
||||
record.valid_until = Some(expiry);
|
||||
}
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
emit RegistryApproved {
|
||||
registry_id: registry_id,
|
||||
approver: msg.sender,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 拒绝登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
/// - `reason`: 拒绝原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn reject_registry(registry_id: Hash, reason: String) -> bool {
|
||||
require(self._registrars.contains(msg.sender), "Not a registrar");
|
||||
require(self._records.contains_key(registry_id), "Registry not found");
|
||||
|
||||
let mut record = self._records[registry_id];
|
||||
require(
|
||||
record.status == RegistryStatus::Pending,
|
||||
"Registry not pending"
|
||||
);
|
||||
|
||||
record.status = RegistryStatus::Rejected;
|
||||
record.notes = reason.clone();
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
emit RegistryRejected {
|
||||
registry_id: registry_id,
|
||||
approver: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 撤销登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
/// - `reason`: 撤销原因
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn revoke_registry(registry_id: Hash, reason: String) -> bool {
|
||||
require(self._records.contains_key(registry_id), "Registry not found");
|
||||
|
||||
let mut record = self._records[registry_id];
|
||||
|
||||
// 只有登记人或管理员可以撤销
|
||||
require(
|
||||
msg.sender == record.registrant || msg.sender == self._admin,
|
||||
"Not authorized"
|
||||
);
|
||||
|
||||
require(
|
||||
record.status == RegistryStatus::Approved,
|
||||
"Registry not approved"
|
||||
);
|
||||
|
||||
record.status = RegistryStatus::Revoked;
|
||||
record.notes = reason.clone();
|
||||
|
||||
self._records[registry_id] = record;
|
||||
|
||||
emit RegistryRevoked {
|
||||
registry_id: registry_id,
|
||||
revoker: msg.sender,
|
||||
reason: reason,
|
||||
timestamp: block.timestamp
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 查询函数 ==========
|
||||
|
||||
/// 获取登记记录
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `RegistryRecord`: 登记记录
|
||||
pub fn get_registry(registry_id: Hash) -> RegistryRecord {
|
||||
require(self._records.contains_key(registry_id), "Registry not found");
|
||||
return self._records[registry_id];
|
||||
}
|
||||
|
||||
/// 获取资产的所有登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 登记ID列表
|
||||
pub fn get_asset_registries(asset_id: Hash) -> Vec<Hash> {
|
||||
return self._asset_registries.get(asset_id).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 获取资产的主权登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<SovereigntyRegistry>`: 主权登记列表
|
||||
pub fn get_sovereignty_registries(asset_id: Hash) -> Vec<SovereigntyRegistry> {
|
||||
return self._sovereignty_registries.get(asset_id).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 获取资产的抵押登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `asset_id`: 资产ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<CollateralRegistry>`: 抵押登记列表
|
||||
pub fn get_collateral_registries(asset_id: Hash) -> Vec<CollateralRegistry> {
|
||||
return self._collateral_registries.get(asset_id).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 获取登记人的所有登记
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registrant`: 登记人地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `Vec<Hash>`: 登记ID列表
|
||||
pub fn get_registrant_registries(registrant: Address) -> Vec<Hash> {
|
||||
return self._registrant_index.get(registrant).unwrap_or(Vec::new());
|
||||
}
|
||||
|
||||
/// 检查登记是否有效
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否有效
|
||||
pub fn is_registry_valid(registry_id: Hash) -> bool {
|
||||
if !self._records.contains_key(registry_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let record = self._records[registry_id];
|
||||
|
||||
// 检查状态
|
||||
if record.status != RegistryStatus::Approved {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if let Some(expiry) = record.valid_until {
|
||||
if block.timestamp >= expiry {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 验证文档
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registry_id`: 登记ID
|
||||
/// - `document_hash`: 文档哈希
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否存在
|
||||
pub fn verify_document(registry_id: Hash, document_hash: Hash) -> bool {
|
||||
require(self._records.contains_key(registry_id), "Registry not found");
|
||||
|
||||
let record = self._records[registry_id];
|
||||
|
||||
for hash in record.document_hashes {
|
||||
if hash == document_hash {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 内部函数 ==========
|
||||
|
||||
/// 生成登记ID
|
||||
fn _generate_registry_id(
|
||||
asset_id: Hash,
|
||||
registrant: Address,
|
||||
registry_type: RegistryType
|
||||
) -> Hash {
|
||||
let mut data = Bytes::new();
|
||||
data.extend(asset_id.as_bytes());
|
||||
data.extend(registrant.as_bytes());
|
||||
data.extend(block.timestamp.to_bytes());
|
||||
data.extend(tx.hash.as_bytes());
|
||||
|
||||
return sha3_384_hash(data);
|
||||
}
|
||||
|
||||
// ========== 管理函数 ==========
|
||||
|
||||
/// 添加登记官员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registrar`: 登记官员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn add_registrar(registrar: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
require(!registrar.is_zero(), "Invalid registrar");
|
||||
|
||||
self._registrars.insert(registrar);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 移除登记官员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registrar`: 登记官员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否成功
|
||||
pub fn remove_registrar(registrar: Address) -> bool {
|
||||
require(msg.sender == self._admin, "Only admin");
|
||||
|
||||
self._registrars.remove(registrar);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 检查是否为登记官员
|
||||
///
|
||||
/// # 参数
|
||||
/// - `registrar`: 登记官员地址
|
||||
///
|
||||
/// # 返回
|
||||
/// - `bool`: 是否为登记官员
|
||||
pub fn is_registrar(registrar: Address) -> bool {
|
||||
return self._registrars.contains(registrar);
|
||||
}
|
||||
pub fn is_registered(entity_id: String) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,592 +1,16 @@
|
|||
///! # 主权规则系统
|
||||
///!
|
||||
///! Sovereignty Rules System
|
||||
///! 定义7种主权类别及其规则
|
||||
///!
|
||||
///! **版本**: v1.0
|
||||
///! **模块**: charter-std/sovereignty/rules.ch
|
||||
|
||||
use asset::gnacs::GNACSCode;
|
||||
|
||||
// ============================================================================
|
||||
// 主权类别枚举
|
||||
// ============================================================================
|
||||
|
||||
/// 主权类别
|
||||
///
|
||||
/// NAC定义的7种主权类别
|
||||
pub enum SovereigntyType {
|
||||
A0, // 绝对所有权 (Absolute Ownership)
|
||||
B1, // 使用权 (Usage Rights)
|
||||
C2, // 收益权 (Revenue Rights)
|
||||
D0, // 担保主权 (Collateral Sovereignty)
|
||||
E3, // 知识产权 (Intellectual Property)
|
||||
F4, // 临时监管权 (Temporary Custody)
|
||||
G5 // 共有权 (Co-ownership)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主权规则结构
|
||||
// ============================================================================
|
||||
|
||||
/// 主权规则
|
||||
///
|
||||
/// 定义每种主权类别的规则和约束
|
||||
struct SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType,
|
||||
name: String,
|
||||
description: String,
|
||||
required_fields: Vec<String>,
|
||||
constraints: Vec<RuleConstraint>,
|
||||
on_transfer: TransferRule,
|
||||
on_revenue: RevenueRule,
|
||||
on_expire: ExpireRule
|
||||
}
|
||||
|
||||
/// 规则约束
|
||||
struct RuleConstraint {
|
||||
field_name: String,
|
||||
constraint_type: ConstraintType,
|
||||
value: String
|
||||
}
|
||||
|
||||
/// 约束类型
|
||||
enum ConstraintType {
|
||||
Required, // 必须字段
|
||||
MinValue, // 最小值
|
||||
MaxValue, // 最大值
|
||||
Pattern, // 模式匹配
|
||||
Custom // 自定义约束
|
||||
}
|
||||
|
||||
/// 转账规则
|
||||
enum TransferRule {
|
||||
Unrestricted, // 无限制
|
||||
RequireApproval, // 需要批准
|
||||
RequireMultiSig, // 需要多签
|
||||
Prohibited // 禁止转账
|
||||
}
|
||||
|
||||
/// 收益规则
|
||||
enum RevenueRule {
|
||||
FullToOwner, // 全部归所有者
|
||||
DistributeByShares, // 按份额分配
|
||||
ToSpecificBeneficiary, // 归特定受益人
|
||||
Custom // 自定义分配
|
||||
}
|
||||
|
||||
/// 到期规则
|
||||
enum ExpireRule {
|
||||
NoExpiry, // 无到期
|
||||
AutoRevoke, // 自动撤销
|
||||
AutoRenew, // 自动续期
|
||||
RequireRenewal // 需要续期
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// A0: 绝对所有权 (Absolute Ownership)
|
||||
// ============================================================================
|
||||
|
||||
/// A0: 绝对所有权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 完全控制权
|
||||
/// - 无期限限制
|
||||
/// - 可自由转让
|
||||
/// - 收益完全归所有者
|
||||
pub const RULE_A0: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::A0,
|
||||
name: "绝对所有权",
|
||||
description: "对资产拥有完全的控制权和处置权",
|
||||
required_fields: vec!["owner", "asset_id", "gnacs_code"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "owner",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "Address"
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::Unrestricted,
|
||||
on_revenue: RevenueRule::FullToOwner,
|
||||
on_expire: ExpireRule::NoExpiry
|
||||
};
|
||||
|
||||
/// 验证A0规则
|
||||
pub fn validate_a0(
|
||||
owner: Address,
|
||||
asset_id: Hash,
|
||||
gnacs_code: GNACSCode
|
||||
) -> bool {
|
||||
// 检查所有者地址有效性
|
||||
if !owner.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查资产ID有效性
|
||||
if asset_id.is_zero() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查GNACS编码有效性
|
||||
if !gnacs_code.validate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn add_rule(rule_id: u256, description: String) -> bool {
|
||||
require(rule_id > 0, "Invalid rule ID");
|
||||
require(description.len() > 0, "Description cannot be empty");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// B1: 使用权 (Usage Rights)
|
||||
// ============================================================================
|
||||
|
||||
/// B1: 使用权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 有期限使用
|
||||
/// - 不可转让(除非授权)
|
||||
/// - 到期自动撤销
|
||||
/// - 无收益权
|
||||
pub const RULE_B1: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::B1,
|
||||
name: "使用权",
|
||||
description: "在特定期限内使用资产的权利",
|
||||
required_fields: vec!["user", "asset_id", "start_time", "end_time", "usage_scope"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "end_time",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "Timestamp"
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "usage_scope",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "String"
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::RequireApproval,
|
||||
on_revenue: RevenueRule::ToSpecificBeneficiary,
|
||||
on_expire: ExpireRule::AutoRevoke
|
||||
};
|
||||
|
||||
/// 验证B1规则
|
||||
pub fn validate_b1(
|
||||
user: Address,
|
||||
asset_id: Hash,
|
||||
start_time: Timestamp,
|
||||
end_time: Timestamp,
|
||||
usage_scope: String
|
||||
) -> bool {
|
||||
// 检查用户地址有效性
|
||||
if !user.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查时间有效性
|
||||
if end_time <= start_time {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查使用范围非空
|
||||
if usage_scope.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn check_rule(rule_id: u256, account: Address) -> bool {
|
||||
require(rule_id > 0, "Invalid rule ID");
|
||||
require(!account.is_zero(), "Invalid account");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// C2: 收益权 (Revenue Rights)
|
||||
// ============================================================================
|
||||
|
||||
/// C2: 收益权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 仅享有收益分配权
|
||||
/// - 无控制权
|
||||
/// - 可转让
|
||||
/// - 可能有期限
|
||||
pub const RULE_C2: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::C2,
|
||||
name: "收益权",
|
||||
description: "享有资产产生收益的分配权",
|
||||
required_fields: vec!["beneficiary", "asset_id", "revenue_share", "start_time"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "revenue_share",
|
||||
constraint_type: ConstraintType::MinValue,
|
||||
value: "0"
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "revenue_share",
|
||||
constraint_type: ConstraintType::MaxValue,
|
||||
value: "10000" // 100.00% (basis points)
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::Unrestricted,
|
||||
on_revenue: RevenueRule::DistributeByShares,
|
||||
on_expire: ExpireRule::RequireRenewal
|
||||
};
|
||||
|
||||
/// 验证C2规则
|
||||
pub fn validate_c2(
|
||||
beneficiary: Address,
|
||||
asset_id: Hash,
|
||||
revenue_share: u16, // 基点(0-10000)
|
||||
start_time: Timestamp
|
||||
) -> bool {
|
||||
// 检查受益人地址有效性
|
||||
if !beneficiary.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查收益份额有效性(0-10000基点)
|
||||
if revenue_share > 10000 {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn remove_rule(rule_id: u256) -> bool {
|
||||
require(rule_id > 0, "Invalid rule ID");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// D0: 担保主权 (Collateral Sovereignty)
|
||||
// ============================================================================
|
||||
|
||||
/// D0: 担保主权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 资产作为抵押品
|
||||
/// - 限制转让
|
||||
/// - 设置清算条件
|
||||
/// - 必须登记
|
||||
pub const RULE_D0: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::D0,
|
||||
name: "担保主权",
|
||||
description: "资产作为债务担保的抵押品",
|
||||
required_fields: vec!["collateral_asset", "beneficiary", "amount", "term", "liquidation_conditions"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "amount",
|
||||
constraint_type: ConstraintType::MinValue,
|
||||
value: "0"
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "liquidation_conditions",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "LiquidationConditions"
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::Prohibited,
|
||||
on_revenue: RevenueRule::ToSpecificBeneficiary,
|
||||
on_expire: ExpireRule::AutoRevoke
|
||||
};
|
||||
|
||||
/// 清算条件
|
||||
struct LiquidationConditions {
|
||||
trigger_price: u256,
|
||||
trigger_time: Timestamp,
|
||||
liquidation_ratio: u16 // 基点
|
||||
}
|
||||
|
||||
/// 验证D0规则
|
||||
pub fn validate_d0(
|
||||
collateral_asset: Hash,
|
||||
beneficiary: Address,
|
||||
amount: u256,
|
||||
term: Duration,
|
||||
liquidation_conditions: LiquidationConditions
|
||||
) -> bool {
|
||||
// 检查抵押品资产ID有效性
|
||||
if collateral_asset.is_zero() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查受益人地址有效性
|
||||
if !beneficiary.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查金额有效性
|
||||
if amount == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查清算比例有效性
|
||||
if liquidation_conditions.liquidation_ratio > 10000 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// E3: 知识产权 (Intellectual Property)
|
||||
// ============================================================================
|
||||
|
||||
/// E3: 知识产权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 专利、版权、商标等
|
||||
/// - 可授权使用
|
||||
/// - 有地域限制
|
||||
/// - 有时间限制
|
||||
pub const RULE_E3: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::E3,
|
||||
name: "知识产权",
|
||||
description: "专利、版权、商标等无形资产权利",
|
||||
required_fields: vec!["ip_holder", "ip_type", "registration_number", "jurisdiction", "expiry_date"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "ip_type",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "IPType"
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "registration_number",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "String"
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::RequireApproval,
|
||||
on_revenue: RevenueRule::FullToOwner,
|
||||
on_expire: ExpireRule::RequireRenewal
|
||||
};
|
||||
|
||||
/// 知识产权类型
|
||||
enum IPType {
|
||||
Patent, // 专利
|
||||
Copyright, // 版权
|
||||
Trademark, // 商标
|
||||
TradeSecret, // 商业秘密
|
||||
Other // 其他
|
||||
}
|
||||
|
||||
/// 验证E3规则
|
||||
pub fn validate_e3(
|
||||
ip_holder: Address,
|
||||
ip_type: IPType,
|
||||
registration_number: String,
|
||||
jurisdiction: u8,
|
||||
expiry_date: Timestamp
|
||||
) -> bool {
|
||||
// 检查持有人地址有效性
|
||||
if !ip_holder.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查注册号非空
|
||||
if registration_number.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查到期日期有效性
|
||||
if expiry_date <= block.timestamp {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// F4: 临时监管权 (Temporary Custody)
|
||||
// ============================================================================
|
||||
|
||||
/// F4: 临时监管权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 托管、监管期间
|
||||
/// - 无处置权
|
||||
/// - 有明确期限
|
||||
/// - 必须返还
|
||||
pub const RULE_F4: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::F4,
|
||||
name: "临时监管权",
|
||||
description: "临时托管或监管资产的权利",
|
||||
required_fields: vec!["custodian", "original_owner", "asset_id", "custody_start", "custody_end", "custody_purpose"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "custody_end",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "Timestamp"
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "custody_purpose",
|
||||
constraint_type: ConstraintType::Required,
|
||||
value: "String"
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::Prohibited,
|
||||
on_revenue: RevenueRule::ToSpecificBeneficiary,
|
||||
on_expire: ExpireRule::AutoRevoke
|
||||
};
|
||||
|
||||
/// 验证F4规则
|
||||
pub fn validate_f4(
|
||||
custodian: Address,
|
||||
original_owner: Address,
|
||||
asset_id: Hash,
|
||||
custody_start: Timestamp,
|
||||
custody_end: Timestamp,
|
||||
custody_purpose: String
|
||||
) -> bool {
|
||||
// 检查托管人地址有效性
|
||||
if !custodian.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查原所有者地址有效性
|
||||
if !original_owner.is_valid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查托管期限有效性
|
||||
if custody_end <= custody_start {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查托管目的非空
|
||||
if custody_purpose.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// G5: 共有权 (Co-ownership)
|
||||
// ============================================================================
|
||||
|
||||
/// G5: 共有权规则
|
||||
///
|
||||
/// 特点:
|
||||
/// - 多方共同所有
|
||||
/// - 按份额分配
|
||||
/// - 重大决策需多数同意
|
||||
/// - 收益按份额分配
|
||||
pub const RULE_G5: SovereigntyRule = SovereigntyRule {
|
||||
sovereignty_type: SovereigntyType::G5,
|
||||
name: "共有权",
|
||||
description: "多方共同拥有资产的权利",
|
||||
required_fields: vec!["co_owners", "ownership_shares", "decision_threshold"],
|
||||
constraints: vec![
|
||||
RuleConstraint {
|
||||
field_name: "co_owners",
|
||||
constraint_type: ConstraintType::MinValue,
|
||||
value: "2" // 至少2个共有人
|
||||
},
|
||||
RuleConstraint {
|
||||
field_name: "decision_threshold",
|
||||
constraint_type: ConstraintType::MinValue,
|
||||
value: "5000" // 至少50%同意
|
||||
}
|
||||
],
|
||||
on_transfer: TransferRule::RequireMultiSig,
|
||||
on_revenue: RevenueRule::DistributeByShares,
|
||||
on_expire: ExpireRule::NoExpiry
|
||||
};
|
||||
|
||||
/// 共有人份额
|
||||
struct OwnershipShare {
|
||||
owner: Address,
|
||||
share: u16 // 基点(0-10000)
|
||||
}
|
||||
|
||||
/// 验证G5规则
|
||||
pub fn validate_g5(
|
||||
co_owners: Vec<OwnershipShare>,
|
||||
decision_threshold: u16 // 基点(5000-10000)
|
||||
) -> bool {
|
||||
// 检查共有人数量(至少2人)
|
||||
if co_owners.len() < 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查决策阈值有效性(50%-100%)
|
||||
if decision_threshold < 5000 || decision_threshold > 10000 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查份额总和是否为100%
|
||||
let mut total_share: u32 = 0;
|
||||
for share in co_owners {
|
||||
if !share.owner.is_valid() {
|
||||
return false;
|
||||
}
|
||||
total_share += share.share as u32;
|
||||
}
|
||||
|
||||
if total_share != 10000 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/// 获取主权规则
|
||||
pub fn get_sovereignty_rule(sovereignty_type: SovereigntyType) -> SovereigntyRule {
|
||||
match sovereignty_type {
|
||||
SovereigntyType::A0 => RULE_A0,
|
||||
SovereigntyType::B1 => RULE_B1,
|
||||
SovereigntyType::C2 => RULE_C2,
|
||||
SovereigntyType::D0 => RULE_D0,
|
||||
SovereigntyType::E3 => RULE_E3,
|
||||
SovereigntyType::F4 => RULE_F4,
|
||||
SovereigntyType::G5 => RULE_G5
|
||||
}
|
||||
}
|
||||
|
||||
/// 验证主权规则
|
||||
pub fn validate_sovereignty(
|
||||
sovereignty_type: SovereigntyType,
|
||||
data: Map<String, Any>
|
||||
) -> bool {
|
||||
match sovereignty_type {
|
||||
SovereigntyType::A0 => validate_a0(
|
||||
data.get("owner"),
|
||||
data.get("asset_id"),
|
||||
data.get("gnacs_code")
|
||||
),
|
||||
SovereigntyType::B1 => validate_b1(
|
||||
data.get("user"),
|
||||
data.get("asset_id"),
|
||||
data.get("start_time"),
|
||||
data.get("end_time"),
|
||||
data.get("usage_scope")
|
||||
),
|
||||
SovereigntyType::C2 => validate_c2(
|
||||
data.get("beneficiary"),
|
||||
data.get("asset_id"),
|
||||
data.get("revenue_share"),
|
||||
data.get("start_time")
|
||||
),
|
||||
SovereigntyType::D0 => validate_d0(
|
||||
data.get("collateral_asset"),
|
||||
data.get("beneficiary"),
|
||||
data.get("amount"),
|
||||
data.get("term"),
|
||||
data.get("liquidation_conditions")
|
||||
),
|
||||
SovereigntyType::E3 => validate_e3(
|
||||
data.get("ip_holder"),
|
||||
data.get("ip_type"),
|
||||
data.get("registration_number"),
|
||||
data.get("jurisdiction"),
|
||||
data.get("expiry_date")
|
||||
),
|
||||
SovereigntyType::F4 => validate_f4(
|
||||
data.get("custodian"),
|
||||
data.get("original_owner"),
|
||||
data.get("asset_id"),
|
||||
data.get("custody_start"),
|
||||
data.get("custody_end"),
|
||||
data.get("custody_purpose")
|
||||
),
|
||||
SovereigntyType::G5 => validate_g5(
|
||||
data.get("co_owners"),
|
||||
data.get("decision_threshold")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ pub fn safe_add(a: u256, b: u256) -> u256 {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
pub fn safe_sub(a: u256, b: u256) -> u256 {
|
||||
require(a >= b, "Subtraction underflow");
|
||||
return a - b;
|
||||
}
|
||||
|
||||
|
||||
pub fn safe_mul(a: u256, b: u256) -> u256 {
|
||||
if a == 0 {
|
||||
return 0;
|
||||
|
|
@ -18,15 +20,19 @@ pub fn safe_mul(a: u256, b: u256) -> u256 {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
pub fn safe_div(a: u256, b: u256) -> u256 {
|
||||
require(b > 0, "Division by zero");
|
||||
return a / b;
|
||||
}
|
||||
|
||||
|
||||
pub fn max(a: u256, b: u256) -> u256 {
|
||||
return if a >= b { a } else { b };
|
||||
}
|
||||
|
||||
|
||||
pub fn min(a: u256, b: u256) -> u256 {
|
||||
return if a <= b { a } else { b };
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue