权限、托管
与韧性方案
zkVerify Launchpad · 从"单人全权"到"多人可接管"
摘要
问题。平台全部特权集中在一个人身上。这不是"权限配置不当",而是架构层面的单人依赖。
方案。叠加六层相互独立的控制:
① 资金层
多签(Horizen 官方 Safe 部署 Den)替代单钥 EOA。
② 合约层
角色分离 + 时间锁,合约 owner 不是 EOA。
③ 应急层
独立、只能暂停、且会过期的守护者权限。
④ 托管层
用户资金不进平台钱包,平台无任意提取函数。
⑤ 链下层
仓库、CI/CD、服务器、域名、凭证的责任分离。
⑥ 流程层
演练、轮换、离职、预先公布的升级触发点。
Stage 0(测试网)可在 5 个工作日内落地全部高优先级控制;Stage 1(主网上线)与外部审计绑定。方案刻意不过度设计:分三阶段递进,每阶段是上一阶段的超集,触发条件事先写死。
目的与范围
1.1 背景(2026-10-14 一对一会议)
| 编号 | 要求 / 约束 | 原文要点 |
|---|---|---|
| R1 | 金库与钱包托管方案 | "put together an outline of what you have in mind for that setup";"safe, durable infrastructure and capabilities management" |
| R2 | 引入其他责任人 | "bringing in one or two other responsible parties on key management, repo, access, all sorts of stewardship" |
| R3 | 合约可被内部审计 | "well-formed and safe — that the Horizen Labs team can run internal security audits" |
| R4 | 韧性方案 | "resiliency plan around the contract, the code base, and the treasury" |
| C1 | 不过度设计 | "while not over-engineering it in the beginning" |
| C2 | 消灭单点故障 | "make sure that Jet is not a single point of failure";"key-man risk" |
| C3 | 给保守组织依据 | "a very well-informed plan that will give us enough cover" |
1.2 范围与边界
在范围内
全部链上合约权限;平台资金与托管中的用户资金;团队代币归属;证明签名密钥;代码仓库、CI/CD、部署、服务器、域名、第三方账号;事故响应与连续性。
不在范围内
前端与网站代码安全(另立文档);Horizen L3 与 zkVerify 链本身的安全性(作为外部依赖纳入威胁模型);法务实体与合规。
现状与风险
2.1 十一个权限面
| # | 资产 / 权限 | 载体 | 风险性质 | 当前持有 |
|---|---|---|---|---|
| 1 | 平台费率收入 | FeeRouter → 收款地址 | 运营收入与 VFY 回购销毁 | Jet |
| 2 | 托管中的募集资金 | escrow 合约 | 第三方用户资金 | Jet |
| 3 | 拍卖 / 结算权 | CCA 与发售流程 | 可操纵价格或阻止募资 | Jet |
| 4 | 发售参数 | LaunchpadHook + 配置 | 参数变动直接影响各方利益 | Jet |
| 5 | 验证 → 解锁门控 | ReportingSchedule | 可静默释放或冻结团队代币 | Jet |
| 6 | zkTLS 证明签名 / 提交密钥 | 后端 → zkVerify → Horizen | 产品信任根,可伪造"已验证" | Jet |
| 7 | 开发者只读凭证 | GA4 / PostHog / Stripe / App Store Connect | 第三方机密在我们手上 | Jet |
| 8 | 代码仓库与 CI | GitHub 组织、Actions secrets | 可把任意代码推上主网 | Jet |
| 9 | 部署与服务器 | VPS、Docker、部署密钥 | 可替换运行中的二进制/前端 | Jet |
| 10 | 域名 / 注册商 / Cloudflare | 注册商 + Cloudflare | 前端劫持、钓鱼后继 | Jet |
| 11 | 第三方服务账号 | 例:Web3 auth 账号挂在前员工个人邮箱 | 已实际发生过的失效模式 | Jet / 前员工 |
以上 11 项均可由单人的一台笔记本触达。按影响排序,最严重的三项是:
① 证明签名密钥——危害不是"丢钱",而是产品承诺被伪造。一旦泄漏或单人滥用,历史上全部"已验证"报告的可信度同时归零,且无法通过换密钥修复已发布的历史。
② 托管中的用户资金——涉及第三方资金,事故性质从"团队损失"升级为"用户损失"。
③ 仓库与部署权——可在无人察觉的情况下改变链上行为,且是审计覆盖不到的链路:审计只看代码,不看谁有权部署什么。
设计原则
| # | 原则 | 可检验的表述 |
|---|---|---|
| P1 | 单人不能动钱、不能改合约行为 | 任一资金/升级动作需 ≥2 个独立主体,任一主体无法单独完成 |
| P2 | 时间即控制 | 不可逆操作一律排队,延迟 ≥24h,给他人取消窗口 |
| P3 | 权限分离 | 升级 ≠ 暂停 ≠ 提议 ≠ 执行 ≠ 提取,不同持有人、不同密钥 |
| P4 | 最小权限 | 按函数授权,不存在"要么全权要么无权" |
| P5 | 证据优于声称 | 每个权限进矩阵,每个控制可测试,每个时间表可公开核验 |
| P6 | 当前适度、未来可升 | 分阶段,触发条件写死,避免开局过度设计、上线后欠设计 |
目标架构
4.1 链与环境事实(已核实)
| 项 | 值 |
|---|---|
| 执行环境 | Horizen 是 Base 之上的 EVM L3,标准 Solidity / EVM |
| 主网 | Chain ID 26514;RPC https://horizen.calderachain.xyz/http;浏览器 explorer.horizen.io(Blockscout) |
| 测试网 | Chain ID 2651420;RPC https://horizen-testnet.rpc.caldera.xyz/http |
| 工具链 | Foundry / Hardhat / viem / wagmi / ethers 全部原生支持 |
| 官方多签 | Den,基于 Safe 合约,safe.horizen.io |
| zkVerify | 证明验证链,非 EVM 执行环境——属于外部依赖,必须写入威胁模型与审计范围 |
5 个合约采用标准 Solidity 技术栈,OpenZeppelin + Foundry + Slither 全部适用;源码验证走 Horizen 浏览器与 Sourcify。用链官方背书的 Den 去跟 Horizen Labs 谈,成本最低。
4.2 钱包与密钥拓扑
| 用途 | 结构 | 签名人 | 说明 |
|---|---|---|---|
| 协议金库 / 管理员 | Safe(Den)3-of-5,≥2 名非创始团队;TGE 升 4-of-7 | Jet、Michael、Horizen Labs 提名 1、外部 2 | 硬件钱包;只拥有时间锁,不直接持有用户资金 |
| 费率收款 | 专用收款合约(或专用 2-of-3 Safe) | 与运营钱包完全分离 | 收款人与分账比例部署时固定,pull 式领取 |
| 团队 / dev 分配 | 链上归属合约,不是钱包 | 受益人为 2-of-3 Safe(另两人非开发者本人) | 12 个月 cliff + 36 个月线性,不可取消、不可回收 |
| 运营热钱包 | 1-of-1 EOA,维持低余额 | Jet | 仅 gas 与日常操作,余额定期归集 |
| 暂停守护者 | Safe 2-of-3 | 非开发者 + Horizen Labs 提名 | 只能暂停,无升级/铸造/转账权,合约内带到期 |
为什么团队分配用归属合约而不是钱包:未到期代币任何私钥都无法动用;释放时间表公开可核验;受益人自助领取;"开发者持有 X% 在热钱包里"这一威胁项从根上消失。Sablier 未部署在 Horizen,故采用自部署的 OpenZeppelin VestingWallet(上游已审计、代码量小)。
4.3 合约权限设计
所有权与角色
| 层级 | 实现 | 说明 |
|---|---|---|
| 单所有者合约 | Ownable2Step | 转移需两步接受,避免误转到不可用地址 |
| 多角色合约 | AccessControl | 按函数授予权限;DEFAULT_ADMIN_ROLE 归时间锁 |
| 合约 owner | TimelockController(合约地址) | 合约可以成为另一个合约的 owner,官方推荐模式 |
角色定义
| 角色 | 持有人 | 权限 | 延迟 |
|---|---|---|---|
DEFAULT_ADMIN_ROLE | 时间锁合约 | 授予/撤销其他角色 | 时间锁延迟 |
UPGRADER_ROLE | 时间锁合约 | 升级实现合约 | 时间锁延迟 |
CONFIG_ROLE | 时间锁合约 | 修改费率、上限、押金、白名单 | 时间锁延迟 |
SETTLER_ROLE | 独立运营密钥 + 上限与频率限制 | 结算、铸造、标记完成 | 无延迟,但额度受限 |
PAUSER_ROLE | 暂停守护者 Safe | 仅暂停 / 解暂停 | 即时 |
GUARDIAN_ROLE | 暂停守护者 Safe | 仅限紧急路径 | 即时,带到期 |
结算/铸造权限与金库管理权限必须由不同密钥持有。这样即使运营密钥被攻破,损失的边界是"单次数额上限",而不是全部资金。
时间锁参数
测试网阶段先建立流程,容忍度较高。
主网 / TGE,与行业成熟项目对齐,给外部签名人充分反应时间。
延迟只作用于"变更",不作用于"暂停",避免拖慢事故响应。
时间锁三角色分离:提议者(协议 Safe)负责排期与取消;执行者(独立运维地址或开放)负责到期执行;管理员在初始化后 renounce 给时间锁自身,确保此后所有维护都必须走时间锁流程。
紧急权限的边界
参照两个最强行业先例:Lido CircuitBreaker(3/6,pause-only,每个合约单次使用,用后需 DAO 重新授权,并要求心跳)与 ENS Security Council(4/8,只能取消,权限自动到期)。
本方案采用:2-of-3 守护者,只能暂停,无升级/铸造/转账权,合约内强制到期。给"第二个人"的权力必须有界且会自动消失,否则只是换了个中心。
WazirX(2.35 亿美元):4-of-6 Safe 被 2 把密钥 + 2 个钓鱼签名攻破后升级为恶意实现,硬件钱包与地址白名单因"代码变了"而全部失效。
因此:签名人必须查看解码后的 calldata,不得仅凭交易哈希签名;所有实现变更必须走时间锁。
4.4 不托管原则(最高优先级建议)
escrow 合约中不存在 "withdraw to arbitrary address" 类函数;资金只能由用户自己 claim,或按预先定义的里程碑规则放款;平台只能在规则内推动状态流转,不能改变受益地址。
费率收款合约参照 Uniswap FeeSplitter / TokenJar 模式:收款人部署时固定,只能 collect 或加仓,不能转出到任意地址。
理由:平台拿不到,就不存在"被平台拿走"的风险。这一条比任何多签都更彻底地消除第 2 项风险,且实施成本最低。
4.5 权限矩阵规范
产出 ACCESS-CONTROL-MATRIX.md,每一条特权函数一行:
角色 · 合约.函数(选择器) · 持有人地址 · 密钥类型 · 时间锁延迟 · 是否可单人完成 · 缓解措施
- 原始行由
slither function-summary与slither vars-and-auth自动导出,不手工编写 - 必须包含 proxy 管理、pause、mint、upgrade、withdraw、setFee、setRecipient 等高危函数
- 每行"是否可单人完成"必须为否;若为是,必须在缓解措施列写明理由与限额
此文档是回应"单人全权"质疑的唯一定量证据。Trail of Bits Rekt Test 第 1 题要求角色权限成文,第 8 题明确要求"任何单个人都不能使系统失效"。
4.6 链下控制
| 对象 | 控制 |
|---|---|
| 组织所有者 | 至少两名真人;不留共享"机器人 owner"(审计事件按账号归属,共享账号破坏归因) |
| 双因素认证 | 组织级强制,仅允许安全方式(passkey / 安全密钥 / 验证器),禁用短信 |
| 分支保护 | main / release/* 启用 Ruleset:必须 PR、2 个批准、新提交使旧批准失效、必过状态检查、签名提交、禁止强推、禁止删除、bypass 名单为空 |
| Deploy Key | 全部删除。有写权限的 deploy key 等价于仓库管理员、无到期时间、不绑定用户、创建人离职后依然有效。改用受限 GitHub App |
| PAT | 组织级限制 classic PAT;fine-grained PAT 需审批并设 90 天到期 |
| 密钥扫描 | 开启 push protection 与泄露报告 |
| Cloudflare | 强制 2FA;Super Admin ≤2 人;开启注册商锁;导出审计日志 |
| SSH | 一人一钥一设备一用途;人类密钥带口令;生产使用 ed25519-sk;关闭 ForwardAgent;经堡垒机;删除共享 root、关闭密码登录 |
| 应急预案 | 密封凭据包存于共享保险库,需两名指定人员共同开启,使用后告警并 5 个工作日内复盘,用后轮换 |
GitHub Environments 的 "required reviewers" 与"等待计时器"在 Free / Pro / Team 套餐下仅对 public 仓库有效;私有仓库需 Enterprise Cloud。分支限制在私有仓库 + Pro/Team 可用。
因此当前可执行的双人控制是以下组合,缺一不可:① Ruleset 层面 PR + 2 个批准;② 只能从 CI 部署,禁止从个人设备部署;③ 生产 environment 限制到 main;④ 凭据通过 OIDC,绑定 environment:prod / ref:refs/heads/main。
待决策:是否需要真正的"点击批准"式部署门。若需要,则为 Enterprise Cloud 成本项,提请 Michael 决策。
4.7 信任根:证明签名
| 控制 | 措施 |
|---|---|
| 分离 | 证明签名密钥与部署权限分离,使用专用密钥 |
| 轮换 | 制定书面轮换流程与周期 |
| 门限 | Stage 2 起评估门限签名,降低单钥风险 |
| 历史完整性 | 每条证明记录链上锚定,便于事后核验不可篡改 |
| 访问 | 仅后端服务可访问,禁止出现在开发者本机 |
若验证层为单人持有,"单点故障"是低估——它是单点伪造,且损害不可通过技术手段回溯修复。
4.8 客户凭证管理
开发者授予的只读凭证(GA4 / PostHog / Stripe restricted key / App Store Connect key)属客户机密:仅授予完成验证所需的最小 scope;静态加密存储,访问留痕;明确可撤销路径;项目结束或用户请求时删除,并在隐私条款中写明保留期限。
分阶段实施计划
5.1 Stage 0 — 测试网(本周内,5 个工作日)
- 1在 Den 创建协议金库 2-of-3 Safe
任一交易需 2 人签名。产出:链上地址 + 签名人名单。
- 2创建费率收款合约
平台无任意转出函数。产出:部署地址 + 收款人配置。
- 3部署时间锁(24h)并移交合约所有权
owner 已变更为时间锁地址。产出:链上地址 + 所有权转移交易哈希。
- 4部署团队归属合约(12+36)
受益人可自助领取,无法提前提取。产出:部署地址 + 释放曲线。
- 5生成权限矩阵
每行"可单人完成"均为否。产出:
ACCESS-CONTROL-MATRIX.md。 - 6GitHub 第二 owner + ruleset + 删除 deploy key
deploy key 数量为 0。产出:配置截图。
- 7建立凭证台账,轮换前员工遗留凭证
无凭证挂靠个人邮箱。产出:台账 + 轮换记录。
- 8铁人三项演练:部署 / 升级 / 恢复
第二人能独立完成部署。产出:演练记录。
5.2 Stage 1 — 主网 / TGE
| 序 | 任务 | 验收标准 |
|---|---|---|
| 1 | 通过外部审计(既有红线) | 审计报告 + 高危项清零 |
| 2 | 金库升级为 4-of-7,含 Horizen Labs 提名人与 ≥2 名外部签名人 | 链上阈值已更新 |
| 3 | 时间锁延长至 7 天 | 链上延迟已更新 |
| 4 | 暂停守护者独立部署(2-of-3,带到期) | 守护者无法升级或转账 |
| 5 | 证明签名密钥与部署权限分离 | 两个独立密钥,台账可查 |
| 6 | 部署所有权交接留链上证明 | 所有权转移交易哈希归档 |
| 7 | 完成季度演练第 1 次 | 演练报告 |
| 8 | 对外公布资金地址、归属合约、管理员地址 | 文档页面已上线 |
5.3 Stage 2 — 规模阶段(触发式)
治理加固
时间锁延长至 7 天以上;引入外部签名人或机构托管;公开金库与分配的可验证页面。
技术加固
证明签名升级为门限签名;启动漏洞赏金,引入外部白帽。
5.4 阶段触发条件(预先写死)
| 触发事件 | 动作 |
|---|---|
| TGE / 主网上线 | 升至 4-of-7 + 7 天时间锁 |
| TVL 或平台托管资金达到约定阈值 | 升至 5-of-9,引入机构签名人 |
| 平台市值达到约定阈值 | 启动门限签名 + 漏洞赏金 |
| 团队人员变动(含离职) | 即刻触发密钥轮换与所有权复核 |
| 发生 P1/P2 级安全事件 | 立即复核全部权限面,48 小时内出报告 |
审计就绪包
6.1 交付物清单(16 项)
| 文件 | 内容 |
|---|---|
AUDIT-SCOPE.md | 冻结的 commit/tag、文件清单、范围内外、联系人、审计窗口 |
ARCHITECTURE.md | 组件关系、时序图(发售 / 领取 / 费率归集 / 升级) |
DATA-FLOW.md | 资产流向与信任边界,含 zkVerify / Vela 依赖 |
THREAT-MODEL.md | 资产、角色、攻击树、风险登记册 |
ACCESS-CONTROL-MATRIX.md | 角色 × 函数 × 持有人 × 是否可单人完成 × 缓解 |
PRIVILEGED-ROLES.md | 密钥台账:地址、类型/阈值、权限、轮换、恢复 |
RUNBOOK-DEPLOY / UPGRADE / INCIDENT.md | 三份运行手册 |
INVARIANTS.md | 每条不变量及其对应测试 |
UPGRADE-SAFETY.md | 存储布局 diff、validateUpgrade、slither-check-upgradeability 输出 |
BUILD.md | 固定工具链与 solc、可复现构建、浏览器与 Sourcify 链接 |
DEPENDENCIES.md | 固定依赖、上游审计链接、许可证 |
KNOWN-ISSUES.md | 已接受风险、理由、责任人 |
FINDINGS-TRIAGE.md | 严重度分级、修复 SLA、复测记录 |
STAGING.md | 已部署地址、种子数据、测试账号 |
TEST-EVIDENCE/ | 覆盖率 LCOV、fuzz/invariant 配置与运行记录、静态分析报告与分诊表 |
6.2 必须成文的不变量
| 不变量 | 检验方式 |
|---|---|
| 代币总量守恒 | Foundry invariant test |
Σ可领取 == escrow 余额 | 不变量测试 |
| 费率余额单调不减(无异常转出) | 不变量测试 |
| 不存在重复领取 | 单元 + 模糊测试 |
| 配置仅可由对应角色修改 | 权限测试 |
| 升级仅可经时间锁 | 集成测试 |
| 同一证明不可重放 | 单元测试 |
6.3 审计流程要求
- 冻结 commit/tag,clean clone 可复现构建
- 提供 staging 环境或 anvil fork 以便复现问题
- 指定一名有权回答设计问题的对接人
- 严重度分级 + 修复 SLA + 复测窗口
- 明确列出不在范围的内容(前端、密钥托管、链本身、zkVerify)
Horizen Labs 的内部审计验证的是"符合规格 + 符合 OWASP SCSVS 相关控制项",不替代对抗性的外部审计。外部审计仍是主网上线的既有红线。
运维、应急与连续性
7.1 运行手册要求
| 手册 | 必须包含 |
|---|---|
RUNBOOK-DEPLOY | 前置检查、签名人名单与阈值、精确命令、部署后冒烟、回滚路径 |
RUNBOOK-UPGRADE | 存储布局 diff、fork 模拟、时间锁排期、解码 calldata 复核、升级后不变量检查 |
RUNBOOK-INCIDENT | 分级、谁宣布、沟通渠道、暂停操作、密钥轮换、对外披露、事后复盘 |
7.2 演练
- 季度演练,至少覆盖:密钥轮换、时间锁升级路径(fork 上)、仓库与基础设施恢复
- 铁人三项:至少两人能独立完成部署、升级、恢复
- 团队已有先例:Acta 部署演练。本方案将其固化为制度
7.3 事故响应角色
| 角色 | 职责 |
|---|---|
| 检测者 Detector | 发现并上报 |
| 事件负责人 Incident Leader | 决策与统筹 |
| 记录员 Scribe | 全程留痕 |
| 沟通负责人 Comms | 对内对外统一口径 |
| 领域专家 SMEs | 合约 / 后端 / 基础设施 |
| 决策者 Decision Makers | 资金与对外承诺 |
严重度 P1–P5,原则是"存疑时取更高一级"。加密项目建议同时接入 SEAL 911 战时机制。
7.4 离职与交接
清单:GitHub(PAT / SSH / 组织成员 / deploy key / App 安装)、Cloudflare(API Token / 成员)、云平台 IAM、服务器 authorized_keys 与 sudoers、注册商联系人、1Password 保险库、第三方服务所有权、部署所有权(留链上转移证明)。
事故依据:Munchables(6250 万美元)——离职开发保留 proxy 升级权,改存储后提走资金。
责任分工与验收
8.1 RACI
| 事项 | Jet | Michael | Horizen Labs 安全 | 第二运维 |
|---|---|---|---|---|
| 合约开发与修复 | R | A | C | I |
| 权限矩阵与审计包 | R | A | C | I |
| 多签签名人 | R | R | R | — |
| 暂停守护者 | C | A | R | R |
| 内部审计 | C | A | R | I |
| 生产部署 | R | I | I | R(第二人批准) |
| 事故响应 | R | A | C | R |
| 季度演练 | R | I | I | R |
R = 负责执行,A = 最终批准,C = 需咨询,I = 知会。
8.2 验收标准
| 要求 | 验收标准(可客观核验) |
|---|---|
| R1 金库托管 | 权限矩阵全部行"可单人完成"为否;金库为 ≥3-of-5;团队分配在归属合约内且不可提前提取;费率收款与运营钱包分离 |
| R2 引入责任人 | 至少 2 名非创始团队签名人已加入金库;GitHub 有 2 名以上 owner;凭证台账 100% 覆盖且无个人邮箱归属 |
| R3 合约可审计 | 16 项交付物齐备;外部审计通过;源码在浏览器与 Sourcify 验证;不变量测试全绿 |
| R4 韧性 | 三份运行手册存在且被第二人独立执行过;季度演练完成 1 次;备份恢复测试通过并留记录;离职清单被实际执行过一次 |
| C1 不过度设计 | Stage 0 全部控制在 5 个工作日内完成,无额外基础设施采购 |
| C2 无单点 | 任一资金动作需 ≥2 方;任一升级需时间锁;暂停权与升级权分离;证明签名与部署分离 |
| C3 给保守组织依据 | 每条控制可映射到公开标准(OWASP SCSVS / Rekt Test / NIST),附录有据可查 |
风险登记册
| # | 风险 | 影响 | 可能性 | 缓解 | 状态 |
|---|---|---|---|---|---|
| 1 | 证明签名密钥泄漏或滥用 | 极高 | 中 | 分离、轮换、Stage 2 门限签名 | 未闭环 |
| 2 | 托管资金被平台方转移 | 极高 | 低 | 不托管架构,合约无任意提取函数 | 设计中 |
| 3 | 外部签名人响应慢导致无法操作 | 中 | 中 | 4-of-7 容忍 3 人缺席;Stage 0 用 2-of-3 | 待定 |
| 4 | 时间锁拖慢事故响应 | 中 | 中 | 暂停即时生效,延迟只作用于变更 | 已缓解 |
| 5 | 私有仓库部署门控不足 | 中 | 中 | PR 双批准 + CI-only + OIDC 绑定 | 设计中 |
| 6 | 前员工遗留凭证 | 高 | 已发生 | 转组织别名后轮换 | 未闭环 |
| 7 | 归属参数未定(D1/D2/D3) | 中 | 高 | 代币部署前必须拍板 | 待定 |
| 8 | Den 上 Safe 模块可用性未验证 | 中 | 中 | 测试网上先验证再依赖 | 待验证 |
| 9 | org-level ruleset 是否在当前套餐内 | 低 | 中 | 查看组织设置确认 | 待验证 |
附录
行业基准、事故教训、标准参考、上线检查清单。
行业基准
| 项目 | 主控结构 | 延迟 | 应急权限边界 |
|---|---|---|---|
| Arbitrum | 安全委员会 12 人 9-of-12 | 紧急亦需 9/12;常规 3+8+3 天;DAO 全程约 42 天 | 6 人一届、12 个月任期、每实体最多 3 名候选 |
| Balancer | DAO Safe 6/11,金库 5/7 | 未公开 | 应急子 DAO 3-of-7,仅可 kill gauge / pause;核心合约不可升级 |
| Lido | 委员会 4/7、4/8、5/7、5/9 | 双速 | CircuitBreaker 3/6,pause-only,单次使用;Emergency Brakes 3/5 |
| EigenLayer | Protocol Council 3-of-5(2 基金会 + 3 外部) | 10 / 10 / 24 天 | 6 个月任期;基金会可撤换(公开的中心化兜底) |
| ENS | 根密钥 4-of-7,18 个月交错任期 | — | Security Council 4-of-8,仅可取消,权限自动失效 |
| CoW DAO | 按用途分离多个 Safe | 未公开 | 角色分离而非守护者模型 |
| 同类 launchpad | 自托管发售合约,创始人自行结算 | — | 未公开任何签名人/时间锁模型(我们公开即差异化) |
事故教训
| 案例 | 损失 | 失效点 | 对本项目的直接含义 |
|---|---|---|---|
| Ronin 2022-03 | 6.24 亿美元 | 5-of-9 但 4 人同属一家公司;临时白名单未撤销;6 天才发现 | 门槛必须超过任何单一组织可控制的席位;临时授权必须有到期与撤销证明 |
| Harmony 2022-06 | 1 亿美元 | 2-of-5,两钥被攻破 | 2-of-5 在九位数规模即单点故障 |
| Wormhole 2022-02 | 3.26 亿美元 | 验证代码缺陷,密钥未丢 | 门限签名只在验证器正确时成立;须把"检查本身出错"写进威胁模型 |
| Nomad 2022-08 | 1.9 亿美元 | 例行升级把可信根初始化为 0x00,人人可抢 | 升级权限即密钥;升级须独立复核 + 升级后不变量检查 + 一个人能拉的 kill switch |
| WazirX 2024-07 | 2.35 亿美元 | 4-of-6 Safe,2 钥 + 2 个钓鱼签名升级为恶意实现 | 签名人必须看解码 calldata;实现变更必须走时间锁 |
| Munchables 2024-03 | 6250 万美元(追回) | 离职开发保留 proxy 升级权 | 交接必须有链上所有权转移证明;离职是安全控制 |
说明:Curve 2023-07 为 Vyper 编译器重入缺陷,不是密钥/权限失效,故未列入。
六起事故中没有一起是"没配多签",全部是门槛设置、延迟、升级权、交接出了问题。因此"我们有多个签名人"不构成安全论证。
标准与参考
标准与框架
- OWASP SCSVS — 访问控制与认证(S4.1 RBAC / 多签 / 最小权限)· scs.owasp.org
- OWASP Smart Contract Top 10 — SC01 访问控制、SC10 代理与可升级性 · scs.owasp.org
- Trail of Bits — The Rekt Test(第 1 题角色成文,第 8 题无单人可使系统失效)· secure-contracts.com
- Trail of Bits — 安全审计准备清单 · secure-contracts.com
- NIST SP 800-61r3 事件响应建议 · csrc.nist.gov
- SEAL — 事件响应政策模板 / GitHub 加固指南 · securityalliance.org
技术文档
- Horizen 文档(EVM L3 on Base、链 ID、Foundry)· docs.horizen.io
- Horizen 多签 Den(基于 Safe)· docs.horizen.io
- zkVerify 文档(证明验证链)· docs.zkverify.io
- OpenZeppelin 访问控制 / 治理 / 升级插件 / VestingWallet · docs.openzeppelin.com
- Sablier Lockup 概念与链支持 · docs.sablier.com
- Uniswap 协议费托管(TokenJar / FeeSplitter)· developers.uniswap.org
上线前检查清单
链上
- 5 个合约全部使用 OpenZeppelin 组件
- 所有 owner 已转移至时间锁,部署 EOA 已 renounce
- 时间锁延迟 = 7 天,三角色已分离
- 暂停守护者独立、
2-of-3、带到期 - escrow 合约无任意地址提取函数
- 费率收款合约收款人部署时固定
- 团队分配在归属合约,不可取消
- 权限矩阵"可单人完成"全部为否
- 不变量测试全绿,覆盖率报告归档
- 源码在浏览器与 Sourcify 验证通过
- 存储布局 diff 与升级安全检查通过
组织与密钥
- 金库
4-of-7,含 ≥2 名外部签名人 - 全部签名人使用硬件钱包
- GitHub 至少 2 名 owner,2FA 强制
- ruleset 生效,bypass 名单为空
- deploy key 数量为 0
- 生产部署仅从 CI,OIDC 已配置
- Cloudflare 2FA、Super Admin ≤2、注册商锁
- SSH 一人一钥,无共享 root
- 凭证台账完整,无个人邮箱归属
- 应急预案密封包就位,两名指定人员
流程
- 三份运行手册完成,第二人独立执行过
- 季度演练第 1 次完成并留记录
- 备份恢复测试完成并留记录
- 离职清单 dry-run 过一次
- 事件响应一页纸已批准
- 资金地址、归属合约、管理员地址已公布
开发总盘
与文档索引
所有已有文档、看板、设计稿、调研的入口
这是文档中心的线上副本。下面标注为 .md / 本地目录的链接,只在本地 vault 里能打开;已上线的页面(如 About Face 4)可以直接点。
进度与看板
产品与机制
技术架构与合约
设计、线稿与设计系统
调研与参考
如何往这里
加一份文档
新增 = 复制一段 <section>,其余自动
三步加一篇
- 1复制一段骨架
在文件里任意两段
<section class="doc">之间,粘一段新的骨架(见 02)。 - 2填四个属性
data-cat决定它在左侧归到哪一组,data-title是显示名,data-num是编号,data-badge是标签。 - 3粘正文
正文用
div.chapter包小节,h2.ch-title是小节标题——脚本会据此生成右侧目录。
每一篇文档最外层必须是 <section class="doc">,并且有一个唯一 id。脚本靠它自动建导航,不需要你手动改侧栏或顶部菜单。
骨架模板
<section class="doc" id="doc-xxx" data-cat="分类名" data-title="文档标题" data-num="04" data-badge="v1.0"> <div class="hero"> <div class="hero-kicker">编号 · 状态</div> <h1>主标题<span>副标题</span></h1> <div class="abstract">一段话摘要</div> </div> <div class="chapter" id="x1"> <div class="ch-head"> <div class="ch-num">01<small>小节英文名</small></div> <h2 class="ch-title">小节标题</h2> </div> <p>正文……</p> </div> </section>
可用的组件
| 想要的样式 | 写法 |
|---|---|
| 章节标题(带大编号) | div.chapter > div.ch-head > div.ch-num + h2.ch-title |
| 小节标题 | h3.sub |
| 提示框(金/红/绿) | div.callout.callout--key / --warn / --project,内部第一行 <b>标签</b> |
| 指标卡 | div.kpi-row > div.kpi > b + span |
| 卡片网格 | div.grid.grid-2 / grid-3 + div.card |
| 编号步骤 | ol.steps > li.step > span.step-num + b + p |
| 时间线 | div.timeline > div.tl-item |
| 勾选清单 | ul.checklist > li |
| 表格(移动端可横向滚) | div.table-scroll > table |
| 附录分隔段 | div.part-divider |
| 索引卡片(带链接) | a.navcard |
三条约定
这样做
- 一篇文档一个
section.doc,id唯一 - 小节用
div.chapter包,目录才会出现 - 表格一律包
div.table-scroll - 新文档放最前面(顺序即侧栏顺序)
别这样做
- 别用外部 CSS / 字体 / CDN(断网会挂)
- 别手动改侧栏和顶部菜单(脚本自动生成)
- 别把样式写成行内(除了极少数一两个词)
- 别删掉
<script>段
现有 Markdown 文档不用重写——告诉我「把某某 .md 放到文档中心」,我就按上面模板转成一篇带章节编号的页面,并把源文件链接放进文档 02 的索引里。