585 lines
17 KiB
Plaintext
585 lines
17 KiB
Plaintext
///! 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(());
|
||
}
|
||
}
|
||
|
||
// ========== 辅助结构体 ==========
|
||
|
||
/// 包装器配置
|
||
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,
|
||
}
|
||
|
||
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(),
|
||
};
|
||
}
|
||
}
|
||
|
||
/// 包装资产
|
||
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,
|
||
}
|
||
|
||
/// 合规快照
|
||
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,
|
||
);
|