557 lines
14 KiB
Plaintext
557 lines
14 KiB
Plaintext
///! # 资产元数据管理
|
||
///!
|
||
///! 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>
|
||
}
|
||
|
||
/// 属性值
|
||
///
|
||
/// 支持多种类型的属性值
|
||
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);
|
||
}
|
||
}
|