代码质量检查清单
本附录提供一份全面的代码质量检查清单,用于在发布 Move 合约前系统性地审查代码。
包配置
-
使用
edition = "2024"或更新 - 移除了不必要的显式框架依赖(Sui 1.45+)
- 命名地址有项目前缀,避免冲突
-
Move.toml中没有硬编码的非零地址(应使用"0x0")
模块结构
- 使用模块标签语法(不用大括号包裹)
-
use语句合理分组,使用{Self, Member}合并导入 -
没有多余的
{Self}单独导入 - 模块内代码组织清晰:常量 → 结构体 → init → 公共函数 → 包可见函数 → 私有函数
命名规范
-
错误常量使用
EPascalCase(如ENotAuthorized) -
普通常量使用
ALL_CAPS(如MAX_SUPPLY) -
Capability 类型以
Cap结尾(如AdminCap) -
事件类型使用过去时(如
HeroCreated,不是CreateHero) -
动态字段键使用
Key后缀和位置结构体 - Hot Potato 类型名称不包含 "Potato"
-
访问器函数直接用字段名,不加
get_前缀 -
可变访问器加
_mut后缀
函数设计
-
没有
public entry函数(使用public或entry) - 公共函数设计为可组合(返回对象而非内部 transfer)
- 参数顺序:对象 → Capability → 值 → Clock → ctx
- Capability 作为第二个参数(对象之后)
-
public函数签名已确认不再变动(升级后不可改) -
需要冻结的便捷函数使用
entry(不是public)
现代语法
-
使用
b"...".to_string()而非utf8(b"...") -
使用
id.delete()而非object::delete(id) -
使用
ctx.sender()而非tx_context::sender(ctx) -
使用 vector 字面量
vector[1, 2, 3] -
使用方法语法
v.length()而非vector::length(&v) -
使用索引语法
v[0]而非vector::borrow(&v, 0) -
使用集合索引
&map[&key]而非map.get(&key) - Coin 操作使用链式调用
宏使用
-
使用
opt.do!(|v| ...)而非 if-is_some-extract -
使用
opt.destroy_or!(default)处理默认值 -
使用
n.do!(|_| ...)而非 while 循环计数 -
使用
vec.do_ref!(|e| ...)遍历 vector -
使用
vec.destroy!(|e| ...)消费 vector -
使用
vec.fold!(init, |acc, v| ...)折叠 -
使用
vec.filter!(|e| ...)过滤 -
使用
vector::tabulate!(n, |i| ...)生成 vector
解构
-
使用
let Struct { field, .. } = value;忽略不需要的字段 -
不使用
field_1: _, field_2: _逐个忽略
安全检查
- 所有特权操作有权限控制(Capability / ACL / 签名验证)
- Capability 绑定了 Referent ID
- Hot Potato 绑定到特定对象
- 所有用户输入经过验证(范围、长度、类型)
- 整数运算有溢出检查
- 除法前检查分母非零
- 共享对象有版本控制
-
seal_approve*函数是entry(非public),支持升级 - 无硬编码的测试密钥或地址
-
可中止错误使用
#[error]与可读消息;语义唯一、可区分场景(避免裸数字第二参数)
升级准备
-
public函数签名稳定,不会在未来变更 -
共享对象包含
version字段 -
有
migrate函数用于版本升级 -
init中不包含升级后需要重新执行的逻辑 - 使用动态字段存储可变配置
- UpgradeCap 安全存储(考虑多签)
- 确定升级策略(compatible / additive / immutable)
测试
- 所有核心功能有单元测试
- 测试覆盖正常路径和错误路径
-
错误路径用
#[test, expected_failure]覆盖(对#[error]不写abort_code,避免 clever 数值随行号变化) - expected_failure 测试不做不必要的清理
-
使用
assert_eq!而非裸assert!(a == b)(比较失败时前者会打印两侧值);需要具名错误时用#[error]常量作第二参数 -
测试中避免依赖易变的字面量中止码;生产代码优先具名
#[error]常量 -
使用
tx_context::dummy()而非不必要的 TestScenario -
使用
sui::test_utils::destroy清理测试对象 -
测试模块中函数名不加
test_前缀
注释
-
文档注释使用
///(不是/** */) - 复杂逻辑有解释性注释
- 没有多余的显而易见的注释
- TODO 和已知问题有注释标记
协议限制
- 单笔交易创建的对象不超过 2048 个
- 单个对象大小不超过 256KB
- 单笔交易访问的动态字段不超过 1000 个
- 单笔交易发射的事件不超过 1024 个
-
大集合使用
Table而非vector - 批量操作分批处理
前端集成
- 合约暴露了前端需要的所有查询函数
- 事件结构清晰,便于索引和展示
- Display 标准已配置(如适用)
- 链上错误能在产品侧映射为用户可读文案(Clever Errors 可由工具链展示常量名与消息)
工具使用
- 使用 Move Formatter 格式化代码
- CI 中集成了格式化检查
-
使用
sui move test运行完整测试套件 - 在 testnet 上完成集成测试
小结
这份检查清单涵盖了从代码风格到安全性的各个方面。建议在以下时机使用:
- 代码审查前:自查代码是否符合规范
- 发布前:系统性检查所有安全和兼容性要求
- 升级前:确认升级兼容性和迁移逻辑
- 团队新人入职:作为编码标准的参考文档