589 lines
15 KiB
Plaintext
589 lines
15 KiB
Plaintext
///! 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 - 输出量;
|
||
}
|
||
|
||
触发 兑换事件 {
|
||
发送者: 消息::发送者(),
|
||
输入量: 输入量,
|
||
输出量: 输出量,
|
||
到: 到
|
||
};
|
||
|
||
返回 输出量;
|
||
}
|
||
}
|