搜索/修改供其他项目继承的智能合约库,且不破坏这些项目

修改供其他项目继承的智能合约库,且不破坏这些项目

当AI编码代理修改供其他项目继承的智能合约库时使用。它会修改真正负责该行为的文件,遵循linter,不改动现有函数、事件和存储布局,并对密码学、升级等AI容易出错的代码亲自重读核实。

要使用这个AI规则
## 按供其他项目继承的方式设计,改动前先在issue中达成一致 - 本仓库是一个智能合约库:其中包含可复用的抽象合约和库,供下游项目继承和扩展,而不是一个已部署的应用程序。大多数约定的存在,是因为这些代码是他人代码的基础。 - 由于继承者依赖于它,设计时必须考虑可扩展性:在预期需要扩展的地方,函数必须可被重写;参数类型不能对继承者施加过度约束;公共API也不能将特定的调用上下文强加给子合约。 - 请先阅读仓库中面向人类贡献者的权威指南,它才是最终依据。AI助手指南仅涵盖辅助工作特有的内容,以及未在别处记录的约定。若两者出现冲突,以人类贡献者指南为准。 - 在提交拉取请求之前,先在issue中讨论任何非小的改动。先就方向达成一致,而不是未经提示就直接实现,然后再针对已商定的范围提交PR。 ## 修改负责该行为的文件,绝不手动修改自动生成的文件 - 一个库仓库包含多个不同的层面:库源码(公共API)、与之对应的仅用于测试的mock、纯净的接口定义、自动生成的包装器、形式化验证规范、文档源文件,以及历史审计报告。编辑文件之前,先确认这个文件属于哪个层面,并修改真正拥有该行为的层面,而不是相邻的层面。单个任务可能同时涉及多个层面,因此在未核实之前,不要想当然地认为某项改动"只是代码"或"只是文档"。 - 绝不要手动编辑自动生成或由工具管理的文件。由模板程序化生成的文件会在文件头注明这一点:此时应编辑模板并重新生成,因为CI会通过生成差异检查来强制保证文件是最新的,手动修改会被覆盖。自动生成的包装器通常会被gitignore排除,并按需重新构建。 - 由工具维护的元数据,应交给对应的工具处理。每个文件头部的"最后更新版本"这一行,是发布工具根据版本控制历史自动维护的,不要手动添加或修改。你的职责仅限于工具未负责的部分,例如许可证标识行。 ## 命名和可见性规则交给linter,不在代码审查中重复 - 已配置的linter已经在库源码上强制执行了机械性的约定(mock和测试通常不受此约束):状态变量默认为private,唯一的例外是`constant`和`immutable`;下划线前缀与可见性对应,因此private和internal的状态变量与函数需带前导下划线,而public和external成员则不带;接口名称以`I`为前缀;合约和事件使用大驼峰命名(CapWords);参数和修饰符使用小驼峰命名(mixedCase);库(library)只暴露internal或private函数。 - 如果某个问题已经被lint规则捕获,就不要在代码评审中花费篇幅解释它,直接修复并继续即可。在评审意见中重复陈述一条已由lint强制执行的规则,只是噪音,而不是有效信息。 ## 遵守linter查不出的编译器版本和import规则 - 编译器pragma版本下限:不要手动挑选最低版本。运行项目的pragma最小化工具,它会遍历依赖图,针对每个候选编译器版本进行编译,并把每个文件可用的最低版本写回(接口使用`>=`前缀,实现和库使用`^`前缀)。随意提高版本下限可能会引入某些目标链不支持的操作码,因此该工具的输出才是安全的答案。 - 导入必须100%使用具名、花括号形式,并在源码树内使用相对路径。禁止使用通配符导入。 - 继承顺序必须在全局范围内保持一致。如果修改了`is A, B, C`这样的继承列表,在推送之前必须重新编译并运行继承顺序检查。 - 变更日志条目:每一处改变合约行为的改动都需要一条变更日志。只有纯文档修改、对用户不可见的内部重构,或纯粹的仓库基础设施调整,才可以省略。 ## 不改动现有函数和存储布局,尽量不增加依赖 - 已发布的合约会被下游继承,并且常常会被转译为单独的可升级版本。不要改变现有public或external函数的签名、现有事件或错误的结构,也不要改变现有合约的存储布局。改动应当是增量式的;应弃用而非删除。破坏性变更是维护者与主版本发布绑定的决策,绝不应在日常工作中随意引入。 - 保持依赖面尽可能小。在向外部寻求依赖之前,先复用库中已有的工具函数。未经维护者批准,不要添加第三方包或新的外部导入;真正需要较重第三方依赖的代码,应放在单独的社区仓库或扩展仓库中,而不是核心库中。 ## 亲自重读核实密码学和存储槽等AI容易出错的代码 - 在以下这些领域,AI给出的建议常常看似合理却是错误的。在接受任何改动之前,请阅读周边代码并重新推导相关结论: - 密码学:哈希、ECDSA、类型化数据(EIP-712)域分隔符、签名方案,以及配对或BLS数学运算。 - 存储槽推导,例如命名空间化(ERC-7201)的槽位:使用规范的推导辅助函数重新计算,并与已声明的常量进行比对。行内注释中的公式是强制性要求,而不是装饰性说明。 - 经过代理或转译器处理的合约的存储布局:新增、删除或重新排序字段都会破坏已部署的代理合约。即便CI也会运行存储布局差异检查,你仍应亲自阅读该差异。 - `delegatecall`、内联汇编与内存安全:核实任何memory-safe标注是否属实,并确认栈和临时空间的使用是有界的。 - `unchecked`代码块:针对每一条代码路径,重新推导"不可能溢出"这一论证。行内的说明注释就是你必须遵守的约定。 - 升级授权:base合约中的升级授权钩子按设计是空的,因此每一个重写都必须限制谁可以调用它。 - 代理实现合约的构造函数:确认在UUPS或透明代理的实现目标上,初始化函数已被禁用(例如调用了禁用初始化函数的方法)。 ## 公开API的改动和安全判断交给人来决定 - 新增或重命名公共API,或决定某个功能是否应该属于该库:先开issue,并获得维护者的决定。 - 安全评估与审计意见:应交由人类审计员判断,而不是自行断言某份合约是安全的。 - 在没有明确方向的情况下制定新的接口标准。 - 在没有相应合约改动的情况下重构测试。 - 绝不要编造安全奖励。不要声称、暗示或凭空捏造漏洞赏金计划、奖励金额或资格条件。只有在确实存在官方记录的计划时,才可以引用它。