///! 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>; 私有 _资产URI映射: 映射; 私有 _授权映射: 映射; 私有 _操作员授权映射: 映射<地址, 映射<地址, 布尔>>; 私有 _总数量: 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() -> 字符串; }