///! DeFi模块: 去中心化金融协议 ///! NAC的DeFi标准协议(专为RWA设计) ///! ///! **版本**: v1.0 ///! **模块**: charter-std-zh/defi/defi.ch 使用 资产::gnacs::GNACS编码; 使用 主权::规则::主权类型; 使用 acc::acc20::ACC20; // ============================================================================ // 流动性池接口 // ============================================================================ /// 流动性池接口 /// /// 定义自动做市商(AMM)的标准操作 接口 流动性池 { // ========== 查询函数 ========== /// 查询资产A地址 函数 资产A() -> 地址; /// 查询资产B地址 函数 资产B() -> 地址; /// 查询资产A储备量 函数 储备量A() -> u256; /// 查询资产B储备量 函数 储备量B() -> u256; /// 查询流动性代币总供应量 函数 流动性总量() -> u256; /// 查询用户流动性 /// /// # 参数 /// - `提供者`: 流动性提供者地址 函数 用户流动性(提供者: 地址) -> u256; /// 计算兑换输出 /// /// # 参数 /// - `输入量`: 输入资产数量 /// - `输入储备`: 输入资产储备量 /// - `输出储备`: 输出资产储备量 /// /// # 返回 /// - `u256`: 输出资产数量 函数 计算输出量(输入量: u256, 输入储备: u256, 输出储备: u256) -> u256; // ========== 状态变更函数 ========== /// 添加流动性 /// /// # 参数 /// - `数量A`: 资产A数量 /// - `数量B`: 资产B数量 /// - `最小数量A`: 最小资产A数量 /// - `最小数量B`: 最小资产B数量 /// - `到`: 接收流动性代币的地址 /// /// # 返回 /// - `u256`: 铸造的流动性代币数量 /// /// # 事件 /// - `添加流动性事件` 函数 添加流动性( 数量A: u256, 数量B: u256, 最小数量A: u256, 最小数量B: u256, 到: 地址 ) -> u256; /// 移除流动性 /// /// # 参数 /// - `流动性`: 流动性代币数量 /// - `最小数量A`: 最小资产A数量 /// - `最小数量B`: 最小资产B数量 /// - `到`: 接收资产的地址 /// /// # 返回 /// - `(u256, u256)`: 返回的资产A和B数量 /// /// # 事件 /// - `移除流动性事件` 函数 移除流动性( 流动性: u256, 最小数量A: u256, 最小数量B: u256, 到: 地址 ) -> (u256, u256); /// 兑换资产 /// /// # 参数 /// - `输入量`: 输入资产数量 /// - `最小输出量`: 最小输出资产数量 /// - `路径`: 兑换路径(资产地址数组) /// - `到`: 接收资产的地址 /// /// # 返回 /// - `u256`: 实际输出数量 /// /// # 事件 /// - `兑换事件` 函数 兑换( 输入量: u256, 最小输出量: u256, 路径: 数组<地址>, 到: 地址 ) -> u256; } // ============================================================================ // 借贷协议接口 // ============================================================================ /// 借贷协议接口 /// /// 定义借贷市场的标准操作 接口 借贷协议 { // ========== 查询函数 ========== /// 查询资产地址 函数 资产() -> 地址; /// 查询总存款 函数 总存款() -> u256; /// 查询总借款 函数 总借款() -> u256; /// 查询用户存款 /// /// # 参数 /// - `用户`: 用户地址 函数 用户存款(用户: 地址) -> u256; /// 查询用户借款 /// /// # 参数 /// - `用户`: 用户地址 函数 用户借款(用户: 地址) -> u256; /// 查询用户抵押品 /// /// # 参数 /// - `用户`: 用户地址 函数 用户抵押品(用户: 地址) -> u256; /// 查询存款利率 函数 存款利率() -> u256; /// 查询借款利率 函数 借款利率() -> u256; /// 查询抵押率 函数 抵押率() -> u256; /// 查询清算阈值 函数 清算阈值() -> u256; // ========== 状态变更函数 ========== /// 存款 /// /// # 参数 /// - `数量`: 存款数量 /// /// # 事件 /// - `存款事件` 函数 存款(数量: u256); /// 取款 /// /// # 参数 /// - `数量`: 取款数量 /// /// # 事件 /// - `取款事件` 函数 取款(数量: u256); /// 借款 /// /// # 参数 /// - `数量`: 借款数量 /// /// # 事件 /// - `借款事件` 函数 借款(数量: u256); /// 还款 /// /// # 参数 /// - `数量`: 还款数量 /// /// # 事件 /// - `还款事件` 函数 还款(数量: u256); /// 存入抵押品 /// /// # 参数 /// - `数量`: 抵押品数量 /// /// # 事件 /// - `抵押事件` 函数 抵押(数量: u256); /// 取出抵押品 /// /// # 参数 /// - `数量`: 抵押品数量 /// /// # 事件 /// - `取消抵押事件` 函数 取消抵押(数量: u256); /// 清算 /// /// # 参数 /// - `借款人`: 被清算的借款人地址 /// - `数量`: 清算数量 /// /// # 事件 /// - `清算事件` 函数 清算(借款人: 地址, 数量: u256); } // ============================================================================ // 质押协议接口 // ============================================================================ /// 质押协议接口 /// /// 定义质押挖矿的标准操作 接口 质押协议 { // ========== 查询函数 ========== /// 查询质押资产地址 函数 质押资产() -> 地址; /// 查询奖励资产地址 函数 奖励资产() -> 地址; /// 查询总质押量 函数 总质押量() -> u256; /// 查询用户质押量 /// /// # 参数 /// - `用户`: 用户地址 函数 用户质押量(用户: 地址) -> u256; /// 查询待领取奖励 /// /// # 参数 /// - `用户`: 用户地址 函数 待领取奖励(用户: 地址) -> u256; /// 查询奖励速率 函数 奖励速率() -> u256; // ========== 状态变更函数 ========== /// 质押 /// /// # 参数 /// - `数量`: 质押数量 /// /// # 事件 /// - `质押事件` 函数 质押(数量: u256); /// 取消质押 /// /// # 参数 /// - `数量`: 取消质押数量 /// /// # 事件 /// - `取消质押事件` 函数 取消质押(数量: u256); /// 领取奖励 /// /// # 事件 /// - `领取奖励事件` 函数 领取奖励(); } // ============================================================================ // DeFi事件定义 // ============================================================================ /// 添加流动性事件 事件 添加流动性事件 { 提供者: 地址, 数量A: u256, 数量B: u256, 流动性: u256 } /// 移除流动性事件 事件 移除流动性事件 { 提供者: 地址, 数量A: u256, 数量B: u256, 流动性: u256 } /// 兑换事件 事件 兑换事件 { 发送者: 地址, 输入量: u256, 输出量: u256, 到: 地址 } /// 存款事件 事件 存款事件 { 用户: 地址, 数量: u256 } /// 取款事件 事件 取款事件 { 用户: 地址, 数量: u256 } /// 借款事件 事件 借款事件 { 借款人: 地址, 数量: u256 } /// 还款事件 事件 还款事件 { 借款人: 地址, 数量: u256 } /// 抵押事件 事件 抵押事件 { 用户: 地址, 数量: u256 } /// 取消抵押事件 事件 取消抵押事件 { 用户: 地址, 数量: u256 } /// 清算事件 事件 清算事件 { 清算人: 地址, 借款人: 地址, 数量: u256, 抵押品数量: u256 } /// 质押事件 事件 质押事件 { 用户: 地址, 数量: u256 } /// 取消质押事件 事件 取消质押事件 { 用户: 地址, 数量: u256 } /// 领取奖励事件 事件 领取奖励事件 { 用户: 地址, 数量: u256 } // ============================================================================ // 流动性池基础实现 // ============================================================================ /// 流动性池基础实现 合约 流动性池基础 实现 流动性池 { // ========== 状态变量 ========== 私有 _资产A: 地址; 私有 _资产B: 地址; 私有 _储备量A: u256; 私有 _储备量B: u256; 私有 _流动性总量: u256; 私有 _用户流动性: 映射<地址, u256>; 私有 常量 _最小流动性: u256 = 1000; 私有 常量 _手续费率: u256 = 3; // 0.3% // ========== 构造函数 ========== 构造函数(资产A: 地址, 资产B: 地址) { 要求(资产A != 地址::零地址() && 资产B != 地址::零地址(), "流动性池: 资产地址无效"); 要求(资产A != 资产B, "流动性池: 资产相同"); _资产A = 资产A; _资产B = 资产B; _储备量A = 0; _储备量B = 0; _流动性总量 = 0; } // ========== 查询函数实现 ========== 函数 资产A() -> 地址 { 返回 _资产A; } 函数 资产B() -> 地址 { 返回 _资产B; } 函数 储备量A() -> u256 { 返回 _储备量A; } 函数 储备量B() -> u256 { 返回 _储备量B; } 函数 流动性总量() -> u256 { 返回 _流动性总量; } 函数 用户流动性(提供者: 地址) -> u256 { 返回 _用户流动性.获取或默认(提供者, 0); } 函数 计算输出量(输入量: u256, 输入储备: u256, 输出储备: u256) -> u256 { 要求(输入量 > 0, "流动性池: 输入量无效"); 要求(输入储备 > 0 && 输出储备 > 0, "流动性池: 储备量无效"); 让 扣除手续费输入 = 输入量 * (1000 - _手续费率); 让 分子 = 扣除手续费输入 * 输出储备; 让 分母 = 输入储备 * 1000 + 扣除手续费输入; 返回 分子 / 分母; } // ========== 状态变更函数实现 ========== 函数 添加流动性( 数量A: u256, 数量B: u256, 最小数量A: u256, 最小数量B: u256, 到: 地址 ) -> u256 { 要求(数量A >= 最小数量A && 数量B >= 最小数量B, "流动性池: 数量不足"); 要求(到 != 地址::零地址(), "流动性池: 接收地址无效"); 让 流动性: u256; 如果 _流动性总量 == 0 { // 首次添加流动性 流动性 = (数量A * 数量B).开平方根() - _最小流动性; _流动性总量 = _最小流动性; // 锁定最小流动性 } 否则 { // 后续添加流动性 让 流动性A = 数量A * _流动性总量 / _储备量A; 让 流动性B = 数量B * _流动性总量 / _储备量B; 流动性 = 如果 流动性A < 流动性B { 流动性A } 否则 { 流动性B }; } 要求(流动性 > 0, "流动性池: 流动性不足"); // 转入资产 ACC20(_资产A).转移从(消息::发送者(), 本合约::地址(), 数量A); ACC20(_资产B).转移从(消息::发送者(), 本合约::地址(), 数量B); // 更新状态 _储备量A = _储备量A + 数量A; _储备量B = _储备量B + 数量B; _流动性总量 = _流动性总量 + 流动性; _用户流动性.插入(到, 用户流动性(到) + 流动性); 触发 添加流动性事件 { 提供者: 到, 数量A: 数量A, 数量B: 数量B, 流动性: 流动性 }; 返回 流动性; } 函数 移除流动性( 流动性: u256, 最小数量A: u256, 最小数量B: u256, 到: 地址 ) -> (u256, u256) { 要求(流动性 > 0, "流动性池: 流动性无效"); 要求(到 != 地址::零地址(), "流动性池: 接收地址无效"); 要求(用户流动性(消息::发送者()) >= 流动性, "流动性池: 流动性不足"); // 计算返还数量 让 数量A = 流动性 * _储备量A / _流动性总量; 让 数量B = 流动性 * _储备量B / _流动性总量; 要求(数量A >= 最小数量A && 数量B >= 最小数量B, "流动性池: 数量不足"); // 更新状态 _用户流动性.插入(消息::发送者(), 用户流动性(消息::发送者()) - 流动性); _流动性总量 = _流动性总量 - 流动性; _储备量A = _储备量A - 数量A; _储备量B = _储备量B - 数量B; // 转出资产 ACC20(_资产A).转移(到, 数量A); ACC20(_资产B).转移(到, 数量B); 触发 移除流动性事件 { 提供者: 消息::发送者(), 数量A: 数量A, 数量B: 数量B, 流动性: 流动性 }; 返回 (数量A, 数量B); } 函数 兑换( 输入量: u256, 最小输出量: u256, 路径: 数组<地址>, 到: 地址 ) -> u256 { 要求(路径.长度() >= 2, "流动性池: 路径无效"); 要求(输入量 > 0, "流动性池: 输入量无效"); 要求(到 != 地址::零地址(), "流动性池: 接收地址无效"); // 简化实现:只支持直接兑换 要求(路径.长度() == 2, "流动性池: 只支持直接兑换"); 要求((路径[0] == _资产A && 路径[1] == _资产B) || (路径[0] == _资产B && 路径[1] == _资产A), "流动性池: 路径不匹配"); 让 输出量: u256; 如果 路径[0] == _资产A { // A -> B 输出量 = 计算输出量(输入量, _储备量A, _储备量B); 要求(输出量 >= 最小输出量, "流动性池: 输出量不足"); // 转入A,转出B ACC20(_资产A).转移从(消息::发送者(), 本合约::地址(), 输入量); ACC20(_资产B).转移(到, 输出量); // 更新储备 _储备量A = _储备量A + 输入量; _储备量B = _储备量B - 输出量; } 否则 { // B -> A 输出量 = 计算输出量(输入量, _储备量B, _储备量A); 要求(输出量 >= 最小输出量, "流动性池: 输出量不足"); // 转入B,转出A ACC20(_资产B).转移从(消息::发送者(), 本合约::地址(), 输入量); ACC20(_资产A).转移(到, 输出量); // 更新储备 _储备量B = _储备量B + 输入量; _储备量A = _储备量A - 输出量; } 触发 兑换事件 { 发送者: 消息::发送者(), 输入量: 输入量, 输出量: 输出量, 到: 到 }; 返回 输出量; } }