554 lines
13 KiB
Plaintext
554 lines
13 KiB
Plaintext
///! 工具模块: 常用工具库
|
||
///! NAC的通用工具函数集合
|
||
///!
|
||
///! **版本**: v1.0
|
||
///! **模块**: charter-std-zh/utils/utils.ch
|
||
|
||
使用 资产::gnacs::GNACS编码;
|
||
|
||
// ============================================================================
|
||
// 数学工具库
|
||
// ============================================================================
|
||
|
||
/// 数学工具库
|
||
库 数学 {
|
||
/// 最小值
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个数
|
||
/// - `b`: 第二个数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 较小的数
|
||
函数 最小值(a: u256, b: u256) -> u256 {
|
||
如果 a < b {
|
||
返回 a;
|
||
} 否则 {
|
||
返回 b;
|
||
}
|
||
}
|
||
|
||
/// 最大值
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个数
|
||
/// - `b`: 第二个数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 较大的数
|
||
函数 最大值(a: u256, b: u256) -> u256 {
|
||
如果 a > b {
|
||
返回 a;
|
||
} 否则 {
|
||
返回 b;
|
||
}
|
||
}
|
||
|
||
/// 平方根(牛顿迭代法)
|
||
///
|
||
/// # 参数
|
||
/// - `x`: 输入值
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 平方根(向下取整)
|
||
函数 平方根(x: u256) -> u256 {
|
||
如果 x == 0 {
|
||
返回 0;
|
||
}
|
||
|
||
让 可变 z = (x + 1) / 2;
|
||
让 可变 y = x;
|
||
|
||
循环 y > z {
|
||
y = z;
|
||
z = (x / z + z) / 2;
|
||
}
|
||
|
||
返回 y;
|
||
}
|
||
|
||
/// 安全加法
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个数
|
||
/// - `b`: 第二个数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 和
|
||
函数 安全加(a: u256, b: u256) -> u256 {
|
||
让 c = a + b;
|
||
要求(c >= a, "数学: 加法溢出");
|
||
返回 c;
|
||
}
|
||
|
||
/// 安全减法
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 被减数
|
||
/// - `b`: 减数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 差
|
||
函数 安全减(a: u256, b: u256) -> u256 {
|
||
要求(b <= a, "数学: 减法下溢");
|
||
返回 a - b;
|
||
}
|
||
|
||
/// 安全乘法
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个数
|
||
/// - `b`: 第二个数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 积
|
||
函数 安全乘(a: u256, b: u256) -> u256 {
|
||
如果 a == 0 {
|
||
返回 0;
|
||
}
|
||
让 c = a * b;
|
||
要求(c / a == b, "数学: 乘法溢出");
|
||
返回 c;
|
||
}
|
||
|
||
/// 安全除法
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 被除数
|
||
/// - `b`: 除数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 商
|
||
函数 安全除(a: u256, b: u256) -> u256 {
|
||
要求(b > 0, "数学: 除数为零");
|
||
返回 a / b;
|
||
}
|
||
|
||
/// 百分比计算
|
||
///
|
||
/// # 参数
|
||
/// - `数值`: 基数
|
||
/// - `百分比`: 百分比(基点,10000=100%)
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 计算结果
|
||
函数 百分比(数值: u256, 百分比: u256) -> u256 {
|
||
返回 数值 * 百分比 / 10000;
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 地址工具库
|
||
// ============================================================================
|
||
|
||
/// 地址工具库
|
||
库 地址工具 {
|
||
/// 判断是否为合约地址
|
||
///
|
||
/// # 参数
|
||
/// - `地址`: 待检查的地址
|
||
///
|
||
/// # 返回
|
||
/// - `布尔`: 是否为合约地址
|
||
函数 是否为合约(地址: 地址) -> 布尔 {
|
||
让 代码大小 = 地址.代码大小();
|
||
返回 代码大小 > 0;
|
||
}
|
||
|
||
/// 判断是否为零地址
|
||
///
|
||
/// # 参数
|
||
/// - `地址`: 待检查的地址
|
||
///
|
||
/// # 返回
|
||
/// - `布尔`: 是否为零地址
|
||
函数 是否为零地址(地址: 地址) -> 布尔 {
|
||
返回 地址 == 地址::零地址();
|
||
}
|
||
|
||
/// 发送NAC币
|
||
///
|
||
/// # 参数
|
||
/// - `接收者`: 接收者地址
|
||
/// - `数量`: 发送数量
|
||
///
|
||
/// # 返回
|
||
/// - `布尔`: 是否发送成功
|
||
函数 发送(接收者: 地址, 数量: u256) -> 布尔 {
|
||
让 (成功, _) = 接收者.调用带值(数量, 字节数组::新建());
|
||
返回 成功;
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 字符串工具库
|
||
// ============================================================================
|
||
|
||
/// 字符串工具库
|
||
库 字符串工具 {
|
||
/// 字符串长度
|
||
///
|
||
/// # 参数
|
||
/// - `字符串`: 输入字符串
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 字符串长度
|
||
函数 长度(字符串: 字符串) -> u256 {
|
||
返回 字符串.长度();
|
||
}
|
||
|
||
/// 字符串拼接
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个字符串
|
||
/// - `b`: 第二个字符串
|
||
///
|
||
/// # 返回
|
||
/// - `字符串`: 拼接后的字符串
|
||
函数 拼接(a: 字符串, b: 字符串) -> 字符串 {
|
||
返回 a + b;
|
||
}
|
||
|
||
/// 字符串比较
|
||
///
|
||
/// # 参数
|
||
/// - `a`: 第一个字符串
|
||
/// - `b`: 第二个字符串
|
||
///
|
||
/// # 返回
|
||
/// - `布尔`: 是否相等
|
||
函数 相等(a: 字符串, b: 字符串) -> 布尔 {
|
||
返回 a == b;
|
||
}
|
||
|
||
/// 数字转字符串
|
||
///
|
||
/// # 参数
|
||
/// - `数字`: 输入数字
|
||
///
|
||
/// # 返回
|
||
/// - `字符串`: 字符串表示
|
||
函数 数字转字符串(数字: u256) -> 字符串 {
|
||
如果 数字 == 0 {
|
||
返回 "0";
|
||
}
|
||
|
||
让 可变 临时 = 数字;
|
||
让 可变 位数 = 0;
|
||
|
||
循环 临时 != 0 {
|
||
位数 = 位数 + 1;
|
||
临时 = 临时 / 10;
|
||
}
|
||
|
||
让 可变 字节 = 字节数组::新建带容量(位数);
|
||
临时 = 数字;
|
||
|
||
对于 i 在 0..位数 {
|
||
字节[位数 - 1 - i] = (临时 % 10 + 48) 作为 u8;
|
||
临时 = 临时 / 10;
|
||
}
|
||
|
||
返回 字符串::从字节(字节);
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 数组工具库
|
||
// ============================================================================
|
||
|
||
/// 数组工具库
|
||
库 数组工具 {
|
||
/// 数组求和
|
||
///
|
||
/// # 参数
|
||
/// - `数组`: 输入数组
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 数组元素之和
|
||
函数 求和(数组: 数组<u256>) -> u256 {
|
||
让 可变 总和 = 0;
|
||
对于 i 在 0..数组.长度() {
|
||
总和 = 总和 + 数组[i];
|
||
}
|
||
返回 总和;
|
||
}
|
||
|
||
/// 数组平均值
|
||
///
|
||
/// # 参数
|
||
/// - `数组`: 输入数组
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 数组元素平均值
|
||
函数 平均值(数组: 数组<u256>) -> u256 {
|
||
要求(数组.长度() > 0, "数组工具: 数组为空");
|
||
返回 求和(数组) / 数组.长度();
|
||
}
|
||
|
||
/// 数组最大值
|
||
///
|
||
/// # 参数
|
||
/// - `数组`: 输入数组
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 数组最大值
|
||
函数 最大值(数组: 数组<u256>) -> u256 {
|
||
要求(数组.长度() > 0, "数组工具: 数组为空");
|
||
|
||
让 可变 最大 = 数组[0];
|
||
对于 i 在 1..数组.长度() {
|
||
如果 数组[i] > 最大 {
|
||
最大 = 数组[i];
|
||
}
|
||
}
|
||
返回 最大;
|
||
}
|
||
|
||
/// 数组最小值
|
||
///
|
||
/// # 参数
|
||
/// - `数组`: 输入数组
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 数组最小值
|
||
函数 最小值(数组: 数组<u256>) -> u256 {
|
||
要求(数组.长度() > 0, "数组工具: 数组为空");
|
||
|
||
让 可变 最小 = 数组[0];
|
||
对于 i 在 1..数组.长度() {
|
||
如果 数组[i] < 最小 {
|
||
最小 = 数组[i];
|
||
}
|
||
}
|
||
返回 最小;
|
||
}
|
||
|
||
/// 数组包含元素
|
||
///
|
||
/// # 参数
|
||
/// - `数组`: 输入数组
|
||
/// - `元素`: 待查找元素
|
||
///
|
||
/// # 返回
|
||
/// - `布尔`: 是否包含
|
||
函数 包含(数组: 数组<u256>, 元素: u256) -> 布尔 {
|
||
对于 i 在 0..数组.长度() {
|
||
如果 数组[i] == 元素 {
|
||
返回 真;
|
||
}
|
||
}
|
||
返回 假;
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 哈希工具库
|
||
// ============================================================================
|
||
|
||
/// 哈希工具库
|
||
库 哈希工具 {
|
||
/// 计算SHA3-384哈希
|
||
///
|
||
/// # 参数
|
||
/// - `数据`: 输入数据
|
||
///
|
||
/// # 返回
|
||
/// - `哈希`: 48字节哈希值
|
||
函数 哈希384(数据: 字节数组) -> 哈希 {
|
||
返回 哈希::从字节(密码学::sha3_384(数据));
|
||
}
|
||
|
||
/// 计算消息哈希
|
||
///
|
||
/// # 参数
|
||
/// - `消息`: 消息内容
|
||
///
|
||
/// # 返回
|
||
/// - `哈希`: 消息哈希
|
||
函数 消息哈希(消息: 字符串) -> 哈希 {
|
||
返回 哈希384(消息.作为字节());
|
||
}
|
||
|
||
/// 计算地址哈希
|
||
///
|
||
/// # 参数
|
||
/// - `地址`: 地址
|
||
///
|
||
/// # 返回
|
||
/// - `哈希`: 地址哈希
|
||
函数 地址哈希(地址: 地址) -> 哈希 {
|
||
返回 哈希384(地址.作为字节());
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 时间工具库
|
||
// ============================================================================
|
||
|
||
/// 时间工具库
|
||
库 时间工具 {
|
||
/// 获取当前时间戳
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 当前时间戳(秒)
|
||
函数 当前时间() -> u256 {
|
||
返回 区块::时间戳();
|
||
}
|
||
|
||
/// 获取当前区块号
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 当前区块号
|
||
函数 当前区块() -> u256 {
|
||
返回 区块::号();
|
||
}
|
||
|
||
/// 计算天数
|
||
///
|
||
/// # 参数
|
||
/// - `秒数`: 秒数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 天数
|
||
函数 秒转天(秒数: u256) -> u256 {
|
||
返回 秒数 / 86400;
|
||
}
|
||
|
||
/// 计算小时数
|
||
///
|
||
/// # 参数
|
||
/// - `秒数`: 秒数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 小时数
|
||
函数 秒转小时(秒数: u256) -> u256 {
|
||
返回 秒数 / 3600;
|
||
}
|
||
|
||
/// 计算分钟数
|
||
///
|
||
/// # 参数
|
||
/// - `秒数`: 秒数
|
||
///
|
||
/// # 返回
|
||
/// - `u256`: 分钟数
|
||
函数 秒转分钟(秒数: u256) -> u256 {
|
||
返回 秒数 / 60;
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 权限控制工具
|
||
// ============================================================================
|
||
|
||
/// 可拥有合约
|
||
///
|
||
/// 提供基础的所有权管理功能
|
||
合约 可拥有 {
|
||
私有 _所有者: 地址;
|
||
|
||
事件 所有权转移 {
|
||
前所有者: 地址,
|
||
新所有者: 地址
|
||
}
|
||
|
||
构造函数() {
|
||
_所有者 = 消息::发送者();
|
||
}
|
||
|
||
修饰符 仅所有者() {
|
||
要求(消息::发送者() == _所有者, "可拥有: 非所有者");
|
||
_;
|
||
}
|
||
|
||
函数 所有者() -> 地址 {
|
||
返回 _所有者;
|
||
}
|
||
|
||
函数 转移所有权(新所有者: 地址) 仅所有者 {
|
||
要求(新所有者 != 地址::零地址(), "可拥有: 新所有者地址无效");
|
||
|
||
让 旧所有者 = _所有者;
|
||
_所有者 = 新所有者;
|
||
|
||
触发 所有权转移 {
|
||
前所有者: 旧所有者,
|
||
新所有者: 新所有者
|
||
};
|
||
}
|
||
|
||
函数 放弃所有权() 仅所有者 {
|
||
让 旧所有者 = _所有者;
|
||
_所有者 = 地址::零地址();
|
||
|
||
触发 所有权转移 {
|
||
前所有者: 旧所有者,
|
||
新所有者: 地址::零地址()
|
||
};
|
||
}
|
||
}
|
||
|
||
/// 可暂停合约
|
||
///
|
||
/// 提供暂停和恢复功能
|
||
合约 可暂停 实现 可拥有 {
|
||
私有 _已暂停: 布尔;
|
||
|
||
事件 暂停 {}
|
||
事件 恢复 {}
|
||
|
||
构造函数() {
|
||
_已暂停 = 假;
|
||
}
|
||
|
||
修饰符 未暂停() {
|
||
要求(!_已暂停, "可暂停: 已暂停");
|
||
_;
|
||
}
|
||
|
||
修饰符 已暂停() {
|
||
要求(_已暂停, "可暂停: 未暂停");
|
||
_;
|
||
}
|
||
|
||
函数 是否已暂停() -> 布尔 {
|
||
返回 _已暂停;
|
||
}
|
||
|
||
函数 暂停() 仅所有者 未暂停 {
|
||
_已暂停 = 真;
|
||
触发 暂停 {};
|
||
}
|
||
|
||
函数 恢复() 仅所有者 已暂停 {
|
||
_已暂停 = 假;
|
||
触发 恢复 {};
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 重入保护
|
||
// ============================================================================
|
||
|
||
/// 重入保护合约
|
||
///
|
||
/// 防止重入攻击
|
||
合约 重入保护 {
|
||
私有 _状态: u256;
|
||
|
||
常量 未进入: u256 = 1;
|
||
常量 已进入: u256 = 2;
|
||
|
||
构造函数() {
|
||
_状态 = 未进入;
|
||
}
|
||
|
||
修饰符 防重入() {
|
||
要求(_状态 != 已进入, "重入保护: 重入调用");
|
||
_状态 = 已进入;
|
||
_;
|
||
_状态 = 未进入;
|
||
}
|
||
}
|