414 lines
13 KiB
Plaintext
414 lines
13 KiB
Plaintext
///! 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() -> 字符串;
|
||
}
|