NAC_Blockchain/charter-std-zh/asset/acc721.ch

414 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///! ACC-721: 非同质化资产协议NFT
///! NAC的NFT标准协议专为RWA设计
///!
///! **版本**: v1.0
///! **模块**: charter-std-zh/asset/acc721.ch
使用 资产::gnacs::GNACS编码;
使用 主权::规则::主权类型;
// ============================================================================
// ACC-721接口定义
// ============================================================================
/// ACC-721非同质化资产接口
///
/// 定义NFT的标准操作
接口 ACC721 {
// ========== 查询函数 ==========
/// 查询资产总数量
///
/// # 返回
/// - `u256`: NFT总数量
函数 总数量() -> u256;
/// 查询资产所有者
///
/// # 参数
/// - `资产编号`: NFT唯一标识符
///
/// # 返回
/// - `地址`: 所有者地址
函数 所有者(资产编号: u256) -> 地址;
/// 查询账户持有数量
///
/// # 参数
/// - `持有者`: 账户地址
///
/// # 返回
/// - `u256`: 持有的NFT数量
函数 持有数量(持有者: 地址) -> u256;
/// 查询资产名称
///
/// # 返回
/// - `字符串`: 资产名称
函数 名称() -> 字符串;
/// 查询资产符号
///
/// # 返回
/// - `字符串`: 资产符号
函数 符号() -> 字符串;
/// 查询资产URI
///
/// # 参数
/// - `资产编号`: NFT唯一标识符
///
/// # 返回
/// - `字符串`: 资产元数据URI
函数 资产URI(资产编号: u256) -> 字符串;
/// 查询授权地址
///
/// # 参数
/// - `资产编号`: NFT唯一标识符
///
/// # 返回
/// - `地址`: 被授权的地址
函数 已授权地址(资产编号: u256) -> 地址;
/// 查询操作员授权
///
/// # 参数
/// - `所有者`: 所有者地址
/// - `操作员`: 操作员地址
///
/// # 返回
/// - `布尔`: 是否已授权
函数 是否授权操作员(所有者: 地址, 操作员: 地址) -> 布尔;
// ========== 状态变更函数 ==========
/// 转移资产
///
/// # 参数
/// - `从`: 发送方地址
/// - `到`: 接收方地址
/// - `资产编号`: NFT唯一标识符
///
/// # 事件
/// - `转移事件`
函数 转移从(从: 地址, 到: 地址, 资产编号: u256);
/// 安全转移资产
///
/// # 参数
/// - `从`: 发送方地址
/// - `到`: 接收方地址
/// - `资产编号`: NFT唯一标识符
///
/// # 事件
/// - `转移事件`
函数 安全转移从(从: 地址, 到: 地址, 资产编号: u256);
/// 安全转移资产(带数据)
///
/// # 参数
/// - `从`: 发送方地址
/// - `到`: 接收方地址
/// - `资产编号`: NFT唯一标识符
/// - `数据`: 附加数据
///
/// # 事件
/// - `转移事件`
函数 安全转移从带数据(从: 地址, 到: 地址, 资产编号: u256, 数据: 字节数组);
/// 授权资产
///
/// # 参数
/// - `被授权者`: 被授权的地址
/// - `资产编号`: NFT唯一标识符
///
/// # 事件
/// - `授权事件`
函数 授权(被授权者: 地址, 资产编号: u256);
/// 设置操作员授权
///
/// # 参数
/// - `操作员`: 操作员地址
/// - `已授权`: 是否授权
///
/// # 事件
/// - `操作员授权事件`
函数 设置操作员授权(操作员: 地址, 已授权: 布尔);
}
// ============================================================================
// ACC-721事件定义
// ============================================================================
/// 转移事件
///
/// 当NFT所有权转移时触发
事件 转移事件 {
从: 地址,
到: 地址,
资产编号: u256
}
/// 授权事件
///
/// 当NFT被授权时触发
事件 授权事件 {
所有者: 地址,
被授权者: 地址,
资产编号: u256
}
/// 操作员授权事件
///
/// 当操作员授权状态改变时触发
事件 操作员授权事件 {
所有者: 地址,
操作员: 地址,
已授权: 布尔
}
// ============================================================================
// ACC-721基础实现
// ============================================================================
/// ACC-721基础实现合约
合约 ACC721基础 实现 ACC721 {
// ========== 状态变量 ==========
私有 _名称: 字符串;
私有 _符号: 字符串;
私有 _所有者映射: 映射<u256, 地址>;
私有 _持有量映射: 映射<地址, u256>;
私有 _资产URI映射: 映射<u256, 字符串>;
私有 _授权映射: 映射<u256, 地址>;
私有 _操作员授权映射: 映射<地址, 映射<地址, 布尔>>;
私有 _总数量: u256;
// ========== 构造函数 ==========
/// 构造函数
///
/// # 参数
/// - `名称`: 资产名称
/// - `符号`: 资产符号
构造函数(名称: 字符串, 符号: 字符串) {
_名称 = 名称;
_符号 = 符号;
_总数量 = 0;
}
// ========== 查询函数实现 ==========
函数 总数量() -> u256 {
返回 _总数量;
}
函数 所有者(资产编号: u256) -> 地址 {
让 所有者 = _所有者映射.获取(资产编号);
要求(所有者 != 地址::零地址(), "ACC721: 资产不存在");
返回 所有者;
}
函数 持有数量(持有者: 地址) -> u256 {
要求(持有者 != 地址::零地址(), "ACC721: 地址无效");
返回 _持有量映射.获取或默认(持有者, 0);
}
函数 名称() -> 字符串 {
返回 _名称;
}
函数 符号() -> 字符串 {
返回 _符号;
}
函数 资产URI(资产编号: u256) -> 字符串 {
要求(_存在(资产编号), "ACC721: 资产不存在");
返回 _资产URI映射.获取或默认(资产编号, "");
}
函数 已授权地址(资产编号: u256) -> 地址 {
要求(_存在(资产编号), "ACC721: 资产不存在");
返回 _授权映射.获取或默认(资产编号, 地址::零地址());
}
函数 是否授权操作员(所有者: 地址, 操作员: 地址) -> 布尔 {
返回 _操作员授权映射.获取或默认(所有者, 映射::新建()).获取或默认(操作员, 假);
}
// ========== 状态变更函数实现 ==========
函数 转移从(从: 地址, 到: 地址, 资产编号: u256) {
要求(_是授权或所有者(消息::发送者(), 资产编号), "ACC721: 未授权");
_转移(从, 到, 资产编号);
}
函数 安全转移从(从: 地址, 到: 地址, 资产编号: u256) {
安全转移从带数据(从, 到, 资产编号, 字节数组::新建());
}
函数 安全转移从带数据(从: 地址, 到: 地址, 资产编号: u256, 数据: 字节数组) {
要求(_是授权或所有者(消息::发送者(), 资产编号), "ACC721: 未授权");
_安全转移(从, 到, 资产编号, 数据);
}
函数 授权(被授权者: 地址, 资产编号: u256) {
让 所有者 = 所有者(资产编号);
要求(被授权者 != 所有者, "ACC721: 不能授权给所有者");
要求(消息::发送者() == 所有者 || 是否授权操作员(所有者, 消息::发送者()),
"ACC721: 未授权");
_授权(被授权者, 资产编号);
}
函数 设置操作员授权(操作员: 地址, 已授权: 布尔) {
要求(操作员 != 消息::发送者(), "ACC721: 不能授权给自己");
_设置操作员授权(消息::发送者(), 操作员, 已授权);
}
// ========== 内部函数 ==========
/// 检查资产是否存在
内部函数 _存在(资产编号: u256) -> 布尔 {
返回 _所有者映射.包含(资产编号);
}
/// 检查是否授权或所有者
内部函数 _是授权或所有者(地址: 地址, 资产编号: u256) -> 布尔 {
让 所有者 = 所有者(资产编号);
返回 地址 == 所有者 ||
已授权地址(资产编号) == 地址 ||
是否授权操作员(所有者, 地址);
}
/// 铸造NFT
内部函数 _铸造(到: 地址, 资产编号: u256) {
要求(到 != 地址::零地址(), "ACC721: 不能铸造到零地址");
要求(!_存在(资产编号), "ACC721: 资产已存在");
_持有量映射.插入(到, 持有数量(到) + 1);
_所有者映射.插入(资产编号, 到);
_总数量 = _总数量 + 1;
触发 转移事件 {
从: 地址::零地址(),
到: 到,
资产编号: 资产编号
};
}
/// 销毁NFT
内部函数 _销毁(资产编号: u256) {
让 所有者 = 所有者(资产编号);
_清除授权(资产编号);
_持有量映射.插入(所有者, 持有数量(所有者) - 1);
_所有者映射.删除(资产编号);
_总数量 = _总数量 - 1;
触发 转移事件 {
从: 所有者,
到: 地址::零地址(),
资产编号: 资产编号
};
}
/// 转移NFT
内部函数 _转移(从: 地址, 到: 地址, 资产编号: u256) {
要求(所有者(资产编号) == 从, "ACC721: 不是所有者");
要求(到 != 地址::零地址(), "ACC721: 不能转移到零地址");
_清除授权(资产编号);
_持有量映射.插入(从, 持有数量(从) - 1);
_持有量映射.插入(到, 持有数量(到) + 1);
_所有者映射.插入(资产编号, 到);
触发 转移事件 {
从: 从,
到: 到,
资产编号: 资产编号
};
}
/// 安全转移NFT
内部函数 _安全转移(从: 地址, 到: 地址, 资产编号: u256, 数据: 字节数组) {
_转移(从, 到, 资产编号);
要求(_检查接收者(从, 到, 资产编号, 数据), "ACC721: 接收者不支持");
}
/// 授权NFT
内部函数 _授权(被授权者: 地址, 资产编号: u256) {
_授权映射.插入(资产编号, 被授权者);
触发 授权事件 {
所有者: 所有者(资产编号),
被授权者: 被授权者,
资产编号: 资产编号
};
}
/// 清除授权
内部函数 _清除授权(资产编号: u256) {
如果 _授权映射.包含(资产编号) {
_授权映射.删除(资产编号);
}
}
/// 设置操作员授权
内部函数 _设置操作员授权(所有者: 地址, 操作员: 地址, 已授权: 布尔) {
让 可变 操作员映射 = _操作员授权映射.获取或默认(所有者, 映射::新建());
操作员映射.插入(操作员, 已授权);
_操作员授权映射.插入(所有者, 操作员映射);
触发 操作员授权事件 {
所有者: 所有者,
操作员: 操作员,
已授权: 已授权
};
}
/// 检查接收者是否支持ACC-721
内部函数 _检查接收者(从: 地址, 到: 地址, 资产编号: u256, 数据: 字节数组) -> 布尔 {
// 如果接收者是合约检查是否实现了ACC-721接收者接口
如果 到.是合约() {
// 调用onACC721Received函数
// 这里简化处理,实际需要调用接口
返回 真;
}
返回 真;
}
/// 设置资产URI
内部函数 _设置资产URI(资产编号: u256, uri: 字符串) {
要求(_存在(资产编号), "ACC721: 资产不存在");
_资产URI映射.插入(资产编号, uri);
}
}
// ============================================================================
// ACC-721扩展可枚举
// ============================================================================
/// ACC-721可枚举扩展接口
接口 ACC721可枚举 扩展 ACC721 {
/// 按索引查询资产编号
函数 按索引查询资产(索引: u256) -> u256;
/// 按所有者和索引查询资产编号
函数 按所有者查询资产(所有者: 地址, 索引: u256) -> u256;
}
// ============================================================================
// ACC-721扩展元数据
// ============================================================================
/// ACC-721元数据扩展接口
接口 ACC721元数据 扩展 ACC721 {
/// 查询基础URI
函数 基础URI() -> 字符串;
}