技术决策记录

持续记录每次开发的技术决策、问题修复和架构变更。 与 session.md 互补:session.md 记录"做了什么",dev-log 记录"为什么这么做"。


2026-03-11 — Phase 6: Sepolia Testnet AWS 全球部署设计

背景

所有功能 Phase (0-5c, 7) 全部完成,项目进入部署阶段。目标:在 AWS 上部署生产级全球节点网络, 覆盖三大洲,支持公开 Testnet 测试。

架构决策

决策项
选择
理由

IaC 工具

Terraform

业界标准,多云支持,AWS provider 最成熟

容器编排

AWS EKS

有状态服务 (RocksDB/PostgreSQL) 支持好,GPU 节点池弹性伸缩

Prover

跳过 (TestnetVerifier)

GPU 月成本 $3000-8000+,testnet 无必要

Region

us-east-1 + eu-west-1 + ap-northeast-1

全球三大洲均衡覆盖

节点分布

单主多从

Sequencer us-east-1 (离 Sepolia L1 最近),其他 region External Node

数据库

Aurora (Sequencer) + CloudNativePG (External Node)

核心数据全托管,可重建数据自建省成本

网络入口

AWS Global Accelerator

TCP 层 Anycast,适合 JSON-RPC + WebSocket

CI/CD

GitHub Actions + ECR + Helm

现有仓库直接用,Helm 版本管理 + 回滚

监控

Prometheus + Grafana + Jaeger → Slack/Telegram

复用现有 era-observability 栈

Prover 跳过决策(重要)

Testnet 阶段使用 TestnetVerifier 跳过 ZK proof 验证。未来切换路径:

  1. Terraform 添加 module "prover" — EKS GPU 节点池 (p3/g5 Spot + On-Demand)

  2. Helm chart 添加 prover-gateway, witness-generator, prover 三个 deployment

  3. 替换 TestnetVerifier 为 Verifier.sol (完整 FFLONK 验证)

  4. 预估增加成本: $5,000-15,000/月

项目结构

成本估算

组件
预估月成本

EKS 节点 (3 region)

~$880

Aurora PostgreSQL (Multi-AZ)

~$500

监控栈

~$60

Global Accelerator + ECR

~$100

总计

~$1,500/月

下一步


2026-03-10 — Phase 7: 预测市场 + SDK

完成内容

  1. ConditionalTokens.sol — 简化版 Gnosis CTF ERC-1155(去掉 parentCollectionId 嵌套,用 keccak256 替代 EC 数学)

  2. CTFExchange.sol — 链上 CLOB 订单簿(EIP-712 签名,fillOrder/matchOrders/cancel)

  3. OracleResolver.sol — 混合结算器(OracleHub 自动价格结算 + admin 手动结算)

  4. @babydriver/sdk — isomorphic TypeScript SDK(viem, tsup ESM+CJS, vitest)

关键决策

决策
选择
理由

条件代币

Gnosis CTF 简化版

行业标准,Polymarket 使用

交易模式

链上 CLOB

L2 gas 低,比 AMM 资金效率高

结算

混合(OracleHub + manual)

价格类自动化,事件类灵活

SDK

viem isomorphic

一个包覆盖 browser + Node.js

positionId

keccak256(collateral, conditionId, indexSet)

简化,无 EC 数学

测试

  • ConditionalTokens: 20 tests(prepare, split, merge, redeem, reportPayouts)

  • CTFExchange: 15 tests(fill, partial, cancel, nonce, fees, pause, EIP-712)

  • OracleResolver: 13 tests(create, resolvePrice, resolveManual, staleness)

  • E2E: 2 tests(完整生命周期 price + manual)

  • SDK: 14 tests(helpers + client)

  • 总计: 64 tests

文件结构


2026-03-10 — Phase 3: Bridge-Enhancer Rust 自动结算模块

完成内容

  • baby-modules/bridge-enhancer/ — Rust LP 自动结算监控模块

    • config.rs — TOML 配置(L1/L2 RPC、合约地址、轮询间隔)

    • rpc.rs — JSON-RPC 调用 + ABI 编码/解码(FastWithdrawalPoolV2 函数)

    • monitor.rs — SettlementMonitor 核心循环(扫描未结算请求、超时检测)

    • wiring.rs — BridgeEnhancerWiringLayer + 后台 tokio 任务

  • 24 个 Rust 单元测试通过

技术决策

  • 选择纯 RPC + 手动 ABI 编码(方案 A),与 oracle-wiring 模式一致

  • 不引入 ethers-rs,保持轻量依赖

  • MVP 支持 read-only 模式(无私钥时仅日志)

  • settlement 交易签名留待下阶段实现(需要 secp256k1 签名库)

架构

  • 沿用 baby-modules 标准模式:config → service → wiring → tokio::spawn

  • SettlementMonitor 跟踪 last_scanned_id,增量扫描新请求

  • 请求分类:NotFound / AlreadySettled / TimedOut / PendingSettlement


2026-03-05 — Phase 5b: Genesis 重部署 + Groth16 Verifier 注册 + E2E 验证

IdentityVerifier 访问控制修复

问题: setCircuitVerifier() 使用 onlySystemCall 修饰符,EOA 无法直接调用。 解决: 参照 OracleHub 模式,添加 initialize() 一次性函数(无修饰符 + _initialized 状态守卫),允许 post-genesis 注册 circuit verifiers 和 trusted issuers。

Genesis 完整重部署

修改 IdentityVerifier 后需要完整重建 genesis(系统合约字节码变化导致 hash 级联更新):

  1. 编辑源文件 contracts/(非 contracts-preprocessed/,后者被预处理器覆盖)

  2. yarn preprocess:system-contractsnpx hardhat compileyarn compile-yul compile-bootloader

  3. 替换 era-core/contracts/ git 子模块为 era-contracts-l1/ 副本

  4. zkstack ecosystem createecosystem init --no-genesischain init --no-genesis → genesis

  5. 修复 3 个 hash 不匹配:default_aa_hashgenesis_rootgenesis_batch_commitment

关键教训: 任何系统合约修改都需要迭代修复 genesis.yaml 中的 hash 值。

E2E 验证结果

项目
状态
详情

Chain ID

271 (0x10f)

OracleHub 5 symbols

ETH/USD, BTC/USD, USDC/USD, SOL/USD, BNB/USD

OracleHub operator

Governor (0x25bb...8489)

OracleHub 价格更新

ETH/USD = $3500, freshness = true

IdentityVerifier 3 verifiers

KYC(0), Credit(1), Enterprise(2)

IdentityVerifier mode

ECDSA (0)

DID createDID

⚠️

onlySystemCall — 需通过系统合约或 bootloader 调用

Groth16 Verifier 地址(L2):

  • KYC (circuit 0): 0x6A47fA35A8Bfb021Cb9f5313d44B7838f8C2E944

  • Credit (circuit 1): 0x2D60d2a35Dc1dD64b2E0a8eCB06887728a869185

  • Enterprise (circuit 2): 0x58424DE0E3C21476934E8Cf165258a06372B1A41


2026-03-02 — Phase 2: Oracle 集成(5 层改动)

背景

Oracle 是 BabyDriver 最核心的差异化特性。我们需要在 L2 上提供原生价格源,让 DApps 可以零成本查询价格。 实现需要修改 5 层:Solidity 系统合约 → Yul Bootloader → Rust State Keeper → Rust VM 接口 → Rust 节点框架。

Phase 2.1: Oracle System Contract (0x8016)

技术决策:

  • 选择地址 0x8016(当前最高系统合约 0x8015 = EVM_HASHES_STORAGE)

  • 使用 bytes32 作为符号键(gas 效率优于 string,系统合约场景下更合适)

  • 存储布局:PriceData 使用 uint128 price + uint128 timestamp 打包存储节省 slot

  • 价格异常时 跳过更新而非 revert,避免阻塞 batch 处理

  • 使用 onlyCallFromBootloader 保护 batchUpdatePrices()

  • 使用 onlySystemCall 保护管理函数 (addSymbol, setConfig)

改动文件:

文件
改动

era-contracts-l1/system-contracts/contracts/Constants.sol

添加 ORACLE_HUB_SYSTEM_CONTRACT = 0x8016

era-contracts-l1/system-contracts/contracts/OracleHub.sol

系统合约版本 Oracle(继承 SystemContractBase)

era-contracts-l1/system-contracts/contracts/interfaces/IOracleHub.sol

系统合约接口

era-contracts-l1/system-contracts/scripts/constants.ts

注册 oracleHub 地址

era-core/core/lib/constants/src/contracts.rs

添加 ORACLE_HUB_ADDRESS Rust 常量

era-core/core/lib/types/src/system_contracts.rs

注册到 SYSTEM_CONTRACT_LIST (40→41)

编译验证: 98 Solidity files compiled successfully (zksolc 1.5.11)

Phase 2.2: Bootloader Hook

技术决策:

  • 在 bootloader 内存布局中分配 24 slots (768 bytes) 给 Oracle 数据

  • 格式:slot[8] = calldata_length, slot[9..] = ABI-encoded calldata

  • Bootloader 直接转发 pre-encoded calldata 给 OracleHub(不在 Yul 中做 ABI 编码)

  • Oracle 更新失败不阻塞 batch — 只记录 debugLog

  • SCRATCH_SPACE_BEGIN_SLOT 从 8 移到 32(所有下游位置自动重算)

改动文件:

文件
改动

bootloader.yul

添加 ORACLE_HUB_ADDR(), ORACLE_CALLDATA_BEGIN_SLOT()

bootloader.yul

添加 updateOraclePrices() 函数

bootloader.yul

setNewBatch() 之后调用 updateOraclePrices()

编译验证: 所有 7 个 bootloader 变体编译通过

Phase 2.3: State Keeper 数据注入

技术决策:

  • L1BatchEnv 添加 oracle_calldata: Option<Vec<u8>> 字段

  • L1BatchParams 添加对应字段

  • State Keeper 通过 l1_batch_params() 传递数据到 VM

  • BootloaderState::initial_memory() 将 calldata 写入 bootloader 堆内存

  • 大端序编码,32 字节对齐

改动文件(13 个):

文件
改动

vm_interface/.../l1_batch_env.rs

L1BatchEnv 添加 oracle_calldata

multivm/.../bootloader/init.rs

initial_memory() + append_oracle_calldata()

vm_executor/src/storage.rs

l1_batch_params() 默认 oracle_calldata: None

state_keeper/src/io/mod.rs

L1BatchParams 添加字段 + into_init_params() 传递

state_keeper/src/io/mempool.rs

两处构造添加 oracle_calldata: None

7 个测试/辅助文件

添加 oracle_calldata: None

编译验证: cargo check 200+ crates 全部通过 (2m52s)

Phase 2.4: EthWatch Oracle Event Processor

决策: 推迟到后续阶段。 当前 Oracle 价格由 Operator 直接提供(通过 WiringLayer),不需要 L1 事件监听。 L1 Oracle 事件监听用于跨链价格验证,将在 Phase 3 Bridge 增强时实现。

Phase 2.5: Oracle WiringLayer

技术决策:

  • 使用 Arc<Mutex<OracleService>> 作为共享资源

  • 后台 tokio task 定期获取价格(可配置间隔,默认 12s)

  • 当前使用 mock 价格(ETH $3000, BTC $60000, USDC $1.00)

  • encode_oracle_calldata() 生成 ABI 编码的 batchUpdatePrices() calldata

  • 提供 get_oracle_calldata() 辅助函数供 MempoolIO 调用

改动文件:

文件
改动

baby-modules/oracle-wiring/src/lib.rs

导出 WiringLayer

baby-modules/oracle-wiring/src/wiring.rs

OracleWiringLayer + 后台价格获取

baby-modules/oracle-wiring/src/service.rs

ABI calldata 编码 + 测试

架构总结

下一步


2026-03-01 — P0 合约安全加固

背景

Phase 1 (Day 1-3) 完成了基础设施骨架:智能合约、Sequencer、SDK、部署脚本。 深度代码审计发现 9 个必须修复的安全/逻辑问题,全部在合约层。 决定暂停应用层开发,优先完成 P0 安全加固。

审计发现的问题清单

#
严重性
模块
问题
状态

1

CRITICAL

L1Bridge

Merkle proof 第二原像攻击风险 — 自定义排序不标准

已修复

2

CRITICAL

L2Bridge

提款叶子未去重,相同 (recipient, token, amount) 生成相同叶子

已修复

3

CRITICAL

FastPool

LP 匹配硬编码 address(this),费用不归 LP

已修复

4

HIGH

L1Bridge

大额存款 timelock 只记录不执行

已修复

5

HIGH

L2Bridge

processed 字段永远不置 true

已修复

6

HIGH

L2Bridge

Merkle root 每次查询重算 O(n),无缓存

已修复

7

MEDIUM

PriceLib

偏差计算不对称 (除以 a 而非平均值)

已修复

8

MEDIUM

OracleHub

merkleRoot 参数存而不验,无 minSourceCount

已修复

9

MEDIUM

Deploy

缺少 RELAYER/SEQUENCER 角色配置

待修复

修复记录

P0-1: Merkle Proof 安全修复

问题分析:

L1Bridge _verifyProof 使用自定义叶子排序 (hash <= sibling)。这与 OpenZeppelin 的标准实现一致,但存在第二原像攻击风险:内部节点和叶子节点使用相同哈希方式, 攻击者可以构造内部节点作为叶子提交。

标准防护方式是给叶子加 0x00 前缀,内部节点加 0x01 前缀。

L2Bridge 的 _withdrawalLeaves 允许重复叶子(相同 recipient+token+amount), 这会导致 L1 上同一笔提款可被多次执行。

修复方案:

  • L1Bridge: 叶子哈希加入 withdrawalId 使其唯一,使用双重哈希 keccak256(abi.encode(...)) 防止长度扩展攻击

  • L2Bridge: 叶子中包含 requestId 保证唯一性,与 L1Bridge 叶子格式对齐

  • 所有测试更新为多叶 Merkle 树

P0-2: 大额存款 Timelock 执行检查

修复: 新增 isDepositUnlocked(uint256 depositId) view 函数。 Sequencer 在 L2 执行 finalizeDeposit 之前必须调用此函数检查时间锁。

P0-3: L2Bridge Withdrawal Processed 追踪

修复: 新增 markWithdrawalProcessed(uint256 requestId) 函数(SEQUENCER_ROLE only)。 Sequencer 在 L1 确认提款后调用此函数将 processed 设为 true。

P0-4: FastPool LP 费用归属

问题: 费用硬编码给 address(this),LP 无法获得手续费。Settlement 不需要实际转账。

修复:

  • 新增 _lpFees mapping 追踪每个 LP 的费用

  • settleWithdrawal 改为 payable,要求 settler 发送实际资金

  • Settlement 拆分:pool 获得 amount - fee,settler 的 _lpFees 累加 fee

  • 新增 claimFees(address token) 供 LP 提取手续费

  • 新增 getLpFees() view 函数

P0-5: PriceLib 偏差计算 + OracleHub minSourceCount

PriceLib 修复: deviationBps 使用 (a + b) / 2 作为分母,确保对称结果。

OracleHub 修复:

  • 新增 minSourceCount 状态变量(默认 1)

  • _updateSinglePrice 内部增加 require(sourceCount >= minSourceCount)

  • 新增 setMinSourceCount(uint8 count) admin 函数

测试结果

所有 P0 修复完成后(除 P0-6 Deploy 角色配置),全量测试通过:

新增测试覆盖:

  • test_finalizeWithdrawal_uniqueLeaves — 验证不同 withdrawalId 生成不同叶子

  • test_isDepositUnlocked_* — 3 个 timelock 状态测试

  • test_withdrawalLeaf_includesRequestId — 验证叶子包含 requestId

  • test_withdrawalLeaves_unique — 相同参数不同 requestId 的唯一性

  • test_markWithdrawalProcessed* — processed 字段追踪

  • test_refreshMerkleRoot — Merkle root 缓存

  • test_pauseBridge/unpauseBridge — L2Bridge 暂停

  • test_settleWithdrawal_revertIfInsufficientETH — settlement 需要实际 ETH

  • test_claimFees* — LP 费用领取

  • test_E2E_oracle_minSourceCount — 最低源数量验证

  • test_E2E_largeDepositTimelock — 含 isDepositUnlocked 验证


2026-03-01 — 架构评估 + 技术路线决策

背景

P0 安全修复完成后,审视现有代码发现 缺少 90% 的 L2 核心组件: 没有 zkEVM/VM、没有 State Keeper、没有 Prover、没有 Merkle Tree、没有 L1 Verifier。 当前实现只是"壳"(合约 + 骨架 Sequencer),不是真正的 ZK Rollup。

架构差距分析

对比 zksync-era(200+ Rust crate,212 个 Solidity 合约),发现:

模块
zksync-era
BabyDriver
差距

zkEVM / VM

6+ 版本 MultiVM

完全没有

CRITICAL

State Keeper

完整状态机

TxPool 骨架

CRITICAL

Prover

35 电路 + 5 层聚合 + GPU

完全没有

CRITICAL

Merkle Tree

稀疏 Merkle + RocksDB

完全没有

CRITICAL

L1 合约

Diamond Proxy + Verifier

简单 Bridge

HIGH

DA 层

Calldata/Blobs/Celestia

完全没有

HIGH

Oracle

无原生实现

OracleHub ✓

我们的优势

FastPool

FastWithdrawalPool ✓

我们的优势

完整分析报告:docs/architecture/ARCHITECTURE-ANALYSIS.md

技术路线决策

决策:Fork zksync-era 作为底层引擎

方案
工作量
时间
选择

Fork zksync-era

6-12 月

✅ 选定

Fork Optimism (OP Stack)

4-8 月

❌ 不是 ZK Rollup

自研 ZK Rollup

极高

3-5 年

❌ 不现实

基于 Polygon CDK

6-10 月

❌ 备选

理由:

  1. Apache 2.0 许可证,允许商业使用

  2. 与 PRD "Type 2.5 zkEVM + PLONK" 完全匹配

  3. 生产级代码,已处理数十亿美元资产

  4. 最完整的开源 ZK Rollup 实现

现有代码价值评估

模块
价值
去向

OracleHub.sol

★★★★ 核心差异化

移植为 System Contract (0x8016)

FastWithdrawalPool.sol

★★★ 有价值增强

集成到 era L1AssetRouter

PriceLib.sol

★★★ 可复用

保留

L1/L2 Bridge

★★ 概念验证

被 era-contracts 替代

Sequencer (Rust)

★ 学习价值

被 era core 替代

83 个测试

★★★ 验证逻辑

移植到新架构


2026-03-01 — Phase 0: Fork 环境搭建

实施计划

制定了 8 阶段实施计划(详见 .claude/plans/parsed-juggling-dahl.md):

Phase
内容
预计时间

0

环境搭建 + Fork 创建

2-3 天

1

Vanilla zksync-era 本地运行

3-5 天

2

Oracle 集成(系统合约 + Bootloader + State Keeper + EthWatch)

7-10 天

3

Bridge 增强(FastPool → IL1AssetHandler)

5-7 天

4

L1 合约定制(Oracle Facet + TestnetVerifier)

3-5 天

5

应用层(DID + 预测市场 + SDK)

10-14 天

6

Testnet 部署(Sepolia)

5-7 天

7

安全审计 + 主网准备

4-8 周

Phase 0 完成情况

0.1 开发环境依赖 ✅

依赖
版本
状态

Rust nightly-2025-03-19

rustc 1.87.0-nightly

✅ 新装

wasm32-unknown-unknown target

✅ 新装

cmake

4.2.3

✅ 新装

LLVM

22.1.0

✅ 新装

RocksDB

10.10.1

✅ 新装

jemalloc

5.3.0

✅ 新装

PostgreSQL

17.7

✅ 已有

Node.js

v20.20.0 (nvm) + v24.12.0

✅ 新装 v20

yarn

1.22.22

✅ 已有

Docker

29.1.3

✅ 已有

Foundry

1.5.1

✅ 已有

0.2 Fork 并克隆仓库 ✅

  • GitHub Fork:

    • leeleeEcho/baby-era ← matter-labs/zksync-era

    • leeleeEcho/baby-era-contracts ← matter-labs/era-contracts

  • 本地克隆:

    • Layer2/era-core/ (107MB, core v29.11.1)

    • Layer2/era-contracts-l1/ (92MB, v29.4)

  • 两个仓库已创建 baby/main 分支

  • git submodules 已初始化

  • .gitignore 已更新排除 fork 目录

0.3 项目结构重组 ✅

创建 baby-modules/ Rust workspace(3 个 crate,编译通过):

创建 config/baby-chain.toml — BabyDriver 链配置。

0.4 首次编译验证 ✅

额外工具安装:

  • cargo-nextest

  • sqlx-cli

  • Node.js v20.20.0 ✅(system-contracts 需要,v24 不兼容 hardhat-zksync-solc 插件)

编译结果:

组件
命令
结果

era-core Rust 核心

ZKSYNC_USE_CUDA_STUBS=true cargo build --release

✅ 5分42秒

era-contracts L1 合约

forge build

✅ 517 个合约目录

era-contracts system-contracts

npx hardhat compile (Node.js 20)

✅ typechain 生成

baby-modules

cargo build

✅ 3 个 crate

关键二进制文件确认:

  • era-core/core/target/release/zksync_server

  • era-core/core/target/release/zksync_external_node

  • era-core/core/target/release/block_reverter

踩坑记录:

  • Node.js v24 与 @matterlabs/hardhat-zksync-solc 不兼容(maxRedirections is not supported),需用 v20

  • era-core 编译需设置 ZKSYNC_USE_CUDA_STUBS=true(非 GPU 环境跳过 CUDA 依赖)

Phase 0 总结

Phase 0 全部完成。 环境搭建、Fork 创建、项目重组、首次编译验证均已通过。 下一步进入 Phase 1: Vanilla zksync-era 本地运行


2026-03-02 — Phase 1: Vanilla zksync-era 本地运行

Phase 1 完成情况

1.1 启动 Docker 容器 ✅

  • Docker reth v1.8.2 作为 L1 模拟节点(dev 模式,300ms 出块)

  • L1 chain_id = 9,RPC http://127.0.0.1:8545

  • 本地 PostgreSQL 17.7 复用(无需 Docker PG)

1.2 zkstack ecosystem init ✅

安装 foundry-zksync v0.1.9 + anvil-zksync 0.6.11(zkstack 需要 forge build --zksync)。

zkstack ecosystem init 完成:

  • 生态系统合约部署(Bridgehub, Diamond Proxy, Verifier, Governance 等)

  • ERC20 测试代币部署

  • Chain "era" 注册(chain_id: 271, NoProofs, EraVM, Rollup)

  • 数据库初始化 + Genesis 创世区块生成

踩坑记录:

  • 系统代理 http_proxy=127.0.0.1:7001 导致 zkstack 内部 ethers/reqwest 无法连接本地 reth,需关闭代理

  • DB URL 必须指定默认数据库(postgres://judybaby@localhost:5432/postgres),否则 sqlx 尝试连接不存在的 judybaby 数据库

  • foundry 标准版不支持 --zksync flag,必须安装 foundry-zksync

1.3 启动 zksync_server ✅

zkstack server --chain era 启动成功,所有核心服务运行:

  • State Keeper: 处理 L1 Batch

  • eth_tx_manager: 提交 CommitBlocks 到 L1

  • eth_tx_aggregator: 创建 proof + execute 交易

  • API Server: JSON-RPC on http://127.0.0.1:3050

API 验证:

方法
结果

eth_chainId

0x10f (271) ✅

eth_blockNumber

持续增长 ✅

zks_L1ChainId

0x9 ✅

1.4 发送测试交易 ✅

L1 → L2 Deposit:

L2 内部转账:

Batch → L1 提交:

  • CommitBlocks tx FastFinalized ✅

  • Proof + Execute 交易已发送

Phase 1 总结

Phase 1 全部完成。 Vanilla zksync-era 在本地完整运行:

  • L1 reth 出块 → L1 合约部署 → Genesis → zksync_server 启动

  • L1 Deposit → L2 余额 → L2 转账 → Batch 提交 L1

  • 完整 ZK Rollup 流程验证通过

下一步进入 Phase 2: Oracle 集成


2026-03-02 — Phase 3: Bridge 增强设计评估

背景

Phase 2(Oracle 集成)完成后,按计划进入 Phase 3: Bridge 增强。 原计划是将 FastWithdrawalPool 实现为 era 的 IL1AssetHandler,并迁移 L1/L2 Bridge 合约到 era 架构。

架构调研

深入分析了两套桥系统后,得出关键结论:

zksync-era 桥架构(已有能力)

组件
职责

Bridgehub

统一入口,路由 L1→L2 存款

L1AssetRouter

资产路由,分发到对应 AssetHandler

L1NativeTokenVault

原生代币处理(锁定/释放),实现 IAssetHandler

L1Nullifier

提款证明验证 + 防双花(isWithdrawalFinalized mapping)

Mailbox

L1↔L2 消息传递(Diamond Proxy facet)

L2AssetRouter + L2NTV

L2 侧资产路由 + 铸币/销毁

完整存款流程: User → Bridgehub → L1AssetRouter → NTV.bridgeBurn() → Mailbox L2 tx → L2AssetRouter → L2NTV.bridgeMint()

完整提款流程: User L2 withdraw → L2→L1 message → Merkle proof → L1Nullifier.finalizeDeposit() → L1AssetRouter → NTV.bridgeMint()

BabyDriver 桥合约(现有代码)

合约
功能
与 era 对比

L1BridgeContract

存款 + Merkle proof 提款

完全被 era 覆盖

L2BridgeContract

L2 铸币/销毁 + Merkle root 计算

完全被 era 覆盖

FastWithdrawalPool

LP 即时提款池

era 没有,独有价值

技术决策:方案变更

原计划: FastWithdrawalPool 实现 IL1AssetHandler 接口,深度集成到 L1AssetRouter

新方案:Sidecar 模式 — FastWithdrawalPool 作为独立 L1 合约,与 era 桥并行运行

变更理由:

  1. L1/L2 BridgeContract 废弃 — era 已提供完整的存款/提款/证明验证系统,重复实现没有意义

  2. 深度集成 (IAssetHandler) 风险过高 — era 的 1-资产-1-处理器 模型不适合叠加 FastPool 逻辑

  3. Sidecar 是行业标准 — Across Protocol、Hop Protocol 均采用此模式

  4. 零修改 era 核心桥 — 降低维护负担和升级冲突

三方案对比

方案
复杂度
安全性
与 era 耦合度

A: IAssetHandler 深度集成

极高

中(可能引入桥漏洞)

强耦合

B: Sidecar 独立合约

高(不碰 era 桥)

零耦合

C: NTV 包装器

中(依赖 NTV 内部实现)

中耦合

FastWithdrawalPool v2 设计要点

与 v1 的核心区别

特性
v1(现有)
v2(新设计)

结算方式

SETTLER_ROLE 信任结算

任何人可通过 era L2→L1 证明结算

费率

固定 0.5%

可选 Oracle 动态费率(基于需求)

提款绑定

无绑定

用户提交 L2 提款哈希,绑定快速提款请求

超时保护

LP 超时后可取回资金

与 era 桥关系

独立系统

使用 era 的 L1Nullifier 证明验证

用户快速提款流程

架构图

实现范围

任务
类型
预估工作量

FastWithdrawalPool v2 合约

Solidity 重构

~300 行

大额存款 Timelock Diamond Facet

Solidity 新增

~50 行

集成测试(与 era 桥 E2E)

Foundry 测试

~200 行

bridge-enhancer Rust 模块

LP 自动结算监控

~100 行

不做的事

  • ❌ 不修改 L1AssetRouter / L1Nullifier / L2AssetRouter

  • ❌ 不迁移 L1BridgeContract / L2BridgeContract(保留作参考和测试用例源)

  • ❌ 不实现 IL1AssetHandler 接口

保留价值

现有合约
处理方式

FastWithdrawalPool.sol

重构为 v2(保留 LP 池 + 费用逻辑,重写结算层)

L1BridgeContract.sol

废弃(大额 timelock 逻辑移植到 Diamond Facet)

L2BridgeContract.sol

废弃(Merkle root 逻辑由 era 原生处理)

PriceLib.sol

保留(v2 动态费率可用)

83 个测试

核心逻辑移植到 v2 测试,era 桥部分由 era 自有测试覆盖

下一步


2026-03-04 — Phase 5a: DID 系统核心层 (P0)

背景

DID 是 BabyDriver 的去中心化身份基础设施。基于 did:ethr 标准,部署为系统合约, 为后续 ZK 身份证明 (P1) 和企业 IAM (P2) 奠定基础。

三个系统合约

DIDRegistry (0x8017):

  • did:ethr:baby 标识符格式

  • DIDDocument 存储:verificationMethods + controller + serviceEndpointHash

  • 委托机制:addDelegate/revokeDelegate(时间有效性)

  • 访问控制:onlySystemCall (createDID), onlyController (update/deactivate)

CredentialRegistry (0x8018):

  • Verifiable Credential 发行 + 撤销

  • 双方 DID 活跃性验证(issuer + subject 必须有活跃 DID)

  • CredentialId = keccak256(issuer, subject, type, claimHash, issuedAt)

  • 有效性检查:未撤销 + 未过期 + issuer DID 仍活跃

IdentityVerifier (0x8019):

  • 双模式设计:ECDSA (P0) → ZK_PLONK (P1)

  • verifyIdentity(): 查找 trusted issuer 发行的有效凭证

  • checkCompliance(): 合规标记查询

  • Trusted Issuer 管理(bootloader 控制)

改动文件

文件
改动

Constants.sol

+3 地址常量 (0x8017-0x8019)

constants.ts

+3 系统合约注册

contracts.rs

+3 Rust 地址常量

system_contracts.rs

SYSTEM_CONTRACT_LIST 41→44

DIDRegistry.sol + IDIDRegistry.sol

新建系统合约

CredentialRegistry.sol + ICredentialRegistry.sol

新建系统合约

IdentityVerifier.sol + IIdentityVerifier.sol

新建系统合约

contracts/src/did/*.sol

本地测试版 (Foundry)

contracts/test/DIDRegistry.t.sol

24 测试

contracts/test/CredentialRegistry.t.sol

15 测试

contracts/test/IdentityVerifier.t.sol

19 测试 + E2E

编译验证

  • 系统合约:90 Solidity files compiled (zksolc 1.5.11) ✓

  • Rust:cargo check 200+ crates ✓

  • Foundry:191 测试全通过(含 58 新 DID 测试)✓

下一步


2026-03-04 — Phase 5b: ZK 身份证明 + Oracle 信用评分

Phase 5b 完成情况

Phase 5b: ZK 身份证明 + Oracle 信用评分 (2026-03-04)

交付物:

  • 3 个 circom 电路: KYCComplianceProof (~7.8k 约束), CreditScoreProof (~7.8k 约束), EnterpriseIdentityProof (~2.9k 约束)

  • EdDSA/Poseidon 签名验证 (Baby Jubjub curve)

  • Groth16 trusted setup (Powers of Tau 2^16) + 3 个 Solidity Verifier 合约

  • IdentityVerifier (0x8019) 升级: verifyZKProof() 分发 + 防重放 + compliance 自动更新

  • Oracle 信用评分: getPersonalCreditScore() / getOrgCreditScore() / getCompositeCreditScore()

  • IGroth16Verifier 通用接口 + MockGroth16Verifier 测试工具

  • 20 circom JS 测试 + 18 Foundry Solidity 测试

关键决策:

  • Groth16/circom 而非 boojum (Goldilocks field 不兼容 BN256, VM 专用电路)

  • EdDSA (Baby Jubjub) 而非 ECDSA (~5k vs ~1.5M constraints)

  • 信用评分复用 OracleHub 现有接口 (CREDIT:* symbols, 无需修改 Oracle 合约)

  • 企业维度: KYC 电路支持 orgType/orgComplianceLevel, 信用电路支持双分数

测试结果

全量 Foundry 测试通过:

系统合约编译: 104 Solidity files compiled (zksolc 1.5.11) ✓

下一步


2026-03-04 — Phase 5b 续: L1 DIDFacet + Mailbox 双向同步

背景

DID 系统合约 (0x8017-0x8019) 运行在 L2,但 L1 合约(如 Bridge 治理、跨链身份验证) 需要查询 DID 状态。需要双向同步机制:

  • L2→L1: L2 DID 状态变更通过 L1Messenger 发送消息,L1 DIDFacet 通过 Mailbox proof 缓存

  • L1→L2: 从 L1 发起 DID 操作(createDID, issueCredential 等),通过 Bridgehub 到 L2 执行

架构选择

采用 Event-Driven Sync 方案(与 L1OracleReader 模式一致):

  • 安全模型最强:每条消息都有 ZK batch proof 背书

  • 代码复用度高:复用 Mailbox proveL2MessageInclusion

  • L2 合约改动最小:仅添加 L1Messenger.sendToL1() 调用

实现内容

L1 DIDFacet(contracts/ 目录,Foundry 测试版):

文件
用途

DIDMessageLib.sol

8 种消息类型常量 + 6 个解码函数

IDIDFacet.sol

接口:DIDSnapshot/CredentialSnapshot + 5 事件 + 5 错误

IBridgehubLocal.sol

L2TransactionRequestDirect 结构 + Bridgehub 接口

MockBridgehub.sol

记录 L2 请求的测试 mock

DIDFacetLocal.sol

完整实现:L2→L1 sync + L1→L2 request + 查询 + 管理

DIDFacet.t.sol

32 个 Foundry 测试

DIDFacetLocal 三层 API:

  1. L2→L1 同步: syncDIDDocument / syncCredential / syncCompliance — Mailbox proof 验证 + 重放保护

  2. L1→L2 请求: requestCreateDID / requestIssueCredential / requestDeactivateDID / requestRevokeCredential / requestAddTrustedIssuer — Bridgehub 发送优先交易

  3. 只读查询: getDIDDocument / isIdentityActive / isCredentialValid / checkCompliance / isTrustedIssuer

L2 系统合约 L1Messenger 集成(era-contracts-l1):

合约
函数
消息类型

DIDRegistry

createDID()

DID_CREATED (0)

DIDRegistry

updateDocument()

DID_UPDATED (1)

DIDRegistry

deactivateDID()

DID_DEACTIVATED (2)

CredentialRegistry

issueCredential()

CREDENTIAL_ISSUED (3)

CredentialRegistry

revokeCredential()

CREDENTIAL_REVOKED (4)

IdentityVerifier

setCompliance()

COMPLIANCE_UPDATED (5)

IdentityVerifier

addTrustedIssuer()

TRUSTED_ISSUER_ADDED (6)

IdentityVerifier

removeTrustedIssuer()

TRUSTED_ISSUER_REMOVED (7)

关键决策

  • 独立 Diamond Storage slot — DIDFacet 使用 keccak256("babydriver.diamond.storage.did.facet") - 1 避免修改 ZKChainStorage(减少上游 merge conflict)

  • DIDFacetLocal vs DIDFacet — Local 版用 MockMailbox/MockBridgehub 测试,生产版继承 ZKChainBase 访问 Diamond Proxy 的 Mailbox 和 Bridgehub

  • Stack Too Deep 修复decodeCredentialIssued 返回 8 个值,提取为 _handleCredentialIssued 内部函数

测试结果

全量 Foundry 测试通过:

下一步


Phase 2.5b: Oracle 真实 API 集成 (2026-03-04)

变更: 将 Oracle 系统从 mock 硬编码价格替换为 CoinGecko + Binance 双源真实 API。

关键改动

  1. keccak256 修复service.rs 中的 keccak256() 之前使用 DefaultHasher(SipHash),不是真正的 Keccak-256。改为 sha3::Keccak256,确保 symbolHash 与链上 Solidity keccak256() 一致。

  2. PriceSource Trait — 可插拔数据源抽象:

    • CoinGeckoSource — 免费 API /simple/price,批量查询最多 250 个 coin

    • BinanceSource — 免费 API /ticker/price,无 rate limit

    • MockSource — 测试用,可配置固定价格

  3. PriceAggregator — 多源聚合:

    • futures::join_all 并行获取所有源

    • 中位数价格计算

    • 偏差检测(basis points)

    • 置信度评分:双源低偏差 95-100, 高偏差 30-60, 单源 50

    • 故障转移:一个源挂掉自动使用另一个

  4. 配置扩展symbols: Vec<String>symbols: Vec<SymbolConfig> + sources 字段

    • baby-chain.toml 改为 [[oracle.symbols]] 表格数组

    • 每个 symbol 包含 canonical, coingecko_id, binance_symbol 映射

    • 初始配置 30 个主流交易对

测试结果

  • oracle-wiring 单元测试: 38 个全部通过 (36 pass + 2 ignored integration)

  • Foundry 合约测试: 全部通过

后续

  • State Keeper 从 bootloader memory slot 注入改为 operator 优先交易注入(支持 100+ 对)

  • MempoolIO 接入 SharedOracleService(oracle_calldata: None → 真实 calldata)

  • OracleHub.sol 添加 onlyOperator 修饰符


2026-03-04 — Phase 2.6: Oracle Operator 交易注入

背景

Phase 2.5b 完成了 CoinGecko + Binance 双源 API 集成,但价格注入仍使用 bootloader 内存 slot 方式(slot 8-31, 共 24 slots = 768 bytes)。每个交易对需要 ~128 bytes 编码空间,24 slots 最多支持 ~6 对,无法满足 31+ 交易对需求。

技术决策

方案选择: Operator 合成 L2 交易注入(方案 B: 一步到位)

  • 仿照 ProtocolUpgradeTx 模式,在 batch 开头注入 operator → OracleHub 的合成 L2Tx

  • 数据量无上限(transaction calldata 不受 memory slot 限制)

  • Oracle tx 执行失败不阻塞 batch(与 protocol upgrade tx 不同,后者失败会 panic)

  • 完全移除 bootloader memory slot 旧代码

oracle_tx.rs — 合成交易构造

新建 era-core/core/node/state_keeper/src/oracle_tx.rs:

  • build_oracle_update_tx(): 构造 L2Tx (EIP-712)

    • from: operator (fee_account)

    • to: ORACLE_HUB_ADDRESS (0x8016)

    • calldata: 预编码的 batchUpdatePrices(bytes32[],uint128[],uint64[],uint8[])

    • gas_limit: 5M(operator 不实际扣费)

    • nonce: Nonce(0)(不走 mempool nonce 验证)

  • 6 单元测试

keeper.rs — Batch 开头注入

  • StateKeeperInner::process_oracle_tx(): 仿照 process_upgrade_tx() 模式

    • 通过 process_one_tx() 执行(与普通交易相同路径)

    • 成功: extend UpdatesManager

    • 失败/revert/ExcludeAndSeal/Unexecutable: warn 日志,return Ok(())

  • process_block() 注入点: is_batch_start 检查后,在 protocol_upgrade_tx 与用户交易循环之间

StateKeeperIO trait 扩展

  • get_oracle_tx_calldata(&self) -> Option<Vec<u8>>: 默认返回 None

  • MempoolIO 实现: 从 SharedOracleService.encode_oracle_calldata() 获取

旧代码移除(19 个 Rust 文件)

移除内容
影响文件数

L1BatchEnv.oracle_calldata 字段

1

L1BatchParams.oracle_calldata 字段 + 赋值

1

init.rs ORACLE_CALLDATA_BEGIN_SLOT/MAX_SLOTS + append_oracle_calldata()

1

oracle_calldata: None 构造字段

16

bootloader.yul 清理

  • 移除 ORACLE_CALLDATA_BEGIN_SLOT(), ORACLE_CALLDATA_BEGIN_BYTE(), ORACLE_CALLDATA_MAX_SLOTS()

  • 移除 ORACLE_HUB_ADDR() 函数

  • 移除 updateOraclePrices() 函数 + 2 处调用(proved + playground batch flow)

  • SCRATCH_SPACE_BEGIN_SLOT 从 32 恢复为 8

OracleHub.sol 权限变更

  • batchUpdatePrices(): onlyCallFromBootloaderonlyOperator

  • 新增 address public operator + modifier onlyOperator()

  • 新增 setOperator(address) (onlySystemCall)

  • initialize() 自动设置 operator = tx.origin

  • 19 Foundry 测试(含 operator rotation E2E)

验证结果

  • era-core cargo check: 200+ crates 全部通过

  • oracle_tx 单元测试: 6/6 pass

  • oracle-wiring 测试: 36/36 pass (2 ignored)

  • Foundry 合约测试: 260/260 pass(含 19 新 operator 测试)

  • bootloader 预处理: 通过

  • oracle_calldata 旧引用: 0(19 文件全部清理)

后续

  • L1 DIDFacet + Mailbox 双向同步实现

  • 重新部署 genesis 含 OracleHub operator 初始化

  • E2E 测试: operator tx → OracleHub.getLatestPrice() 验证


2026-03-05 — Genesis 完整重部署 + E2E 验证

背景

Phase 2.5b 的 Oracle 架构重构(移除 bootloader 注入,改为 operator tx 模式)需要完整重部署 genesis, 验证所有系统合约(OracleHub 0x8016、DIDRegistry 0x8017、CredentialRegistry 0x8018、IdentityVerifier 0x8019) 在新链上正确工作。

关键修复:protective_reads_persistence_enabled

问题: 重部署后 state_keeper 在 batch 1 sealed 后卡死,无法创建 batch 2。

根因分析:

  • State keeper 创建 batch 2 时需要 batch 1 的 hash

  • Hash 由 Merkle tree (metadata_calculator) 计算

  • Merkle tree 判断哪些 batch 可处理的逻辑分两条路径:

    • sealed_batches_have_protective_reads = true → 检查 is_sealed = true(简单)

    • sealed_batches_have_protective_reads = false → 检查 vm_runner_protective_reads 表(复杂)

  • 我们的配置 protective_reads_persistence_enabled: false 触发了后者

  • vm_runner_protective_reads 表为空(ProtectiveReadsWriter 未运行)→ 返回 batch 0 → 死锁

修复: general.yamlprotective_reads_persistence_enabled: false → true

代码路径:

  • metadata_calculator/src/lib.rs:123-124: config 映射

  • metadata_calculator/src/updater.rs:201-221: 条件分支

  • vm_runner_dal.rs: get_protective_reads_latest_processed_batch() SQL

教训: 当不运行 ProtectiveReadsWriter 组件时,必须设置 protective_reads_persistence_enabled: true, 否则 Merkle tree 会检查一个永远为空的表。

OracleHub 初始化

验证结果:

  • stalenessThreshold = 3600 ✓

  • deviationThreshold = 500 ✓

  • minSourceCount = 3 ✓

  • operator = governor 地址 ✓

  • getLatestPrice(ETH/USD) = 200000000000 ($2000.00) ✓

  • isPriceFresh(ETH/USD) = true ✓

E2E 验证结果

验证项
结果

OracleHub initialize + update + query

DID 合约部署 (0x8017-0x8019 有 bytecode)

Chain ID = 271

Block 持续推进 (block 10+)

L1 Batch 持续 seal (batch 5+)

L1 deposit 处理 (governor ~2 ETH)

Batch hash 计算 (tree 正常工作)

配置变更

文件
变更

era_core/chains/era/configs/general.yaml:72

protective_reads_persistence_enabled: false → true

era_core/chains/era/configs/general.yaml:206

添加 zksync_state_keeper=trace 到 log_directives

下一步

  • Phase 5b: ZK 身份证明 (PLONK 电路 + IdentityVerifier 升级)

  • Oracle operator 自动化服务(Rust WiringLayer 发送 batchUpdatePrices)

  • Testnet 部署 (Sepolia)


2026-03-05 — Oracle 自动化 E2E 调试 (7 个 Bug 修复)

背景

实现 Oracle 价格自动化注入:每个 L1 batch 开始时,State Keeper 自动构建签名交易调用 OracleHub.batchUpdatePrices()。从 mock/CoinGecko/Binance 获取价格,编码 ABI calldata, EIP-712 签名后注入 batch 首位。

修复的 7 个 Bug

#
Bug
根因
修复

1

set_input panic

L2Tx::new_signed 后未设置 tx.set_input(...) 导致 hash() panic

在 oracle_tx.rs 调用 set_input(rlp_bytes, hash)

2

VM 签名验证失败

使用普通 ECDSA 签名,VM 期望 EIP-712

改用 K256PrivateKey::sign_typed_tx EIP-712 签名

3

basefee reject

max_fee_per_gas = 0,低于 block basefee

设置 max_fee_per_gas = 250_000_000

4

NonceAlreadyUsed (缓存)

首次启动时缓存 nonce 到 AtomicU32,后续 batch 使用过期 nonce

改为每 batch 从 DB 异步查询 (storage_web3_dal().get_nonces_for_addresses())

5

"insufficient sources" revert

链上 minSourceCount=3,calldata 仅报 source_count=1 (只有 mock)

encode_oracle_calldata() 使用 max(actual, config.min_source_count)

6

"unsupported symbol" revert

config 有 31 符号但链上只注册了 ETH/USD

暂时减少 config 到 ETH/USD;后续需 addSymbol 系统调用

7

Batch 不开启

空 mempool 导致 wait_for_new_batch_params 无限等待

非 bug — zksync-era 设计:需要 mempool 有 tx 才开 batch

关键代码改动

era-core/core/node/state_keeper/src/io/mod.rs:

  • get_oracle_tx(): fnasync fn (支持 DB 查询)

era-core/core/node/state_keeper/src/io/mempool.rs:

  • 移除 AtomicU32 nonce 缓存

  • get_oracle_tx() 改为 async,每 batch 从 DB 查 nonce

era-core/core/node/state_keeper/src/oracle_tx.rs:

  • max_fee_per_gas: 0 → 250_000_000

  • 新增 nonce: Nonce 参数

baby-modules/oracle-wiring/src/service.rs:

  • encode_oracle_calldata() source count floor: max(pd.source_count, config.min_source_count)

config/baby-chain.toml:

  • 从 31 符号减少到 1 个 (ETH/USD)

E2E 验证结果

已知限制

  1. 首 batch 竞态:服务器启动后第一个 batch 总是错过 Oracle 注入(价格获取 ~12s,batch 开启 ~100ms)

  2. Binance 400 / CoinGecko 403:外部 API 不可用,仅 mock 源工作(本地开发环境限制)

  3. 单符号:链上仅注册 ETH/USD,多符号需 addSymbol() 系统调用

  4. Operator 地址冲突:Oracle tx 和用户 tx 共享同一地址会导致 nonce 冲突(生产环境需独立 operator)


Oracle 多符号注册 (方案 A+B)

日期: 2026-03-05

问题: addSymbol(bytes32) 使用 onlySystemCall 修饰符,普通 EOA 无法调用,导致链上只有 genesis 时注册的 ETH/USD 一个符号。batchUpdatePrices 传入未注册符号会 revert(Bug #7)。

方案 A(Genesis): 扩展 initialize() 调用,一次性传入 5 个符号 hash(ETH/BTC/USDC/SOL/BNB)。

方案 B(Runtime): addSymbol 权限从 onlySystemCall 放宽为 onlySystemCall OR onlyOperator,新增 batchAddSymbols(bytes32[]) 批量注册接口。

变更文件:

  • OracleHub.sol_isSystemCallOrOperator() 内部函数 + addSymbol 双权限 + batchAddSymbols

  • IOracleHub.sol — 接口同步

  • OracleHubLocal.sol — Foundry 可测试镜像同步(_isAdminOrOperator

  • baby-chain.toml — 启用 BTC/USD, USDC/USD, SOL/USD, BNB/USD 配置

  • 6 个新 Foundry 测试(全套 50 个通过)

安全决策: removeSymbol 保持 onlySystemCall(高危操作 — 删除符号可能影响依赖该价格的 DApp)。addSymbol 是低风险操作(只添加,不影响现有价格数据),故允许 operator 调用。


Phase 5b 完成 (2026-03-05)

IdentityVerifier 修复

  • setCircuitVerifier 访问控制修复:onlyCallFromBootloaderonlySystemCall

  • 允许 genesis 后通过系统调用交易注册 Groth16 Verifier

CreditScoreAggregator (baby-modules/credit-score/)

  • 新 Rust 模块:加权信用评分服务

  • config.rs: 评分权重配置 — tx_activity(25%) + account_age(20%) + kyc_level(20%) + holding_duration(20%) + did_activity(15%)

  • on_chain.rs: L2 RPC 查询(DIDRegistry + CredentialRegistry + IdentityVerifier)

  • aggregator.rs: 饱和归一化评分算法(递减回报),评分范围 0-1000

  • wiring.rs: SharedCreditScoreService + CreditScoreWiringLayer 后台 tokio 任务

  • 符号格式:CREDIT:PERSONAL:0x{address},通过 OracleHub.batchUpdatePrices 提交

  • Phase 1 简化:仅链上因子,account_age/holding_duration 使用代理值

  • 25 个测试(21 单元 + 4 集成)全部通过

L1 DIDFacet 验证

  • DIDFacetLocal.sol(390 行)测试验证:32 个 Foundry 测试全部通过

  • L2→L1 消息格式验证:8 种消息类型 (0-7) 确认正确

    • 0: DID_CREATED, 1: DID_UPDATED, 2: DID_DEACTIVATED

    • 3: CREDENTIAL_ISSUED, 4: CREDENTIAL_REVOKED

    • 5: COMPLIANCE_UPDATED, 6: TRUSTED_ISSUER_ADDED, 7: TRUSTED_ISSUER_REMOVED

  • 注意:verifyZKProof 尚未发送 L1 消息(ZK_PROOF_VERIFIED type 8 延至 Phase 6)

全量测试验证

技术决策

  • CreditScore 评分使用饱和归一化(value * MAX / (value + ref))而非线性归一化,避免极端值主导评分

  • 参考值设定:TX_COUNT_REF=200, ACCOUNT_AGE_REF=180 days, HOLDING_DURATION_REF=90 days, CREDENTIAL_COUNT_REF=10

  • 信用评分作为 OracleHub 特殊符号存储,复用现有 Oracle 基础设施


(后续开发记录在此追加)

Phase 5c: 社会恢复 + 企业 IAM + 选择性披露 (2026-03-06)

完成内容

Part 1: 社会恢复 (DIDRegistry 0x8017)

  • N-of-M guardian 恢复 + 时间锁(最少 1 小时,默认 24h)

  • 最多 7 个 guardian,不可重复,不能是自己

  • 流程:setRecovery → initiateRecovery → approveRecovery → executeRecovery(或 cancelRecovery)

  • Guardian 变更自动清除待处理恢复请求

  • L1 sync: Type 8 (RecoveryInitiated), Type 9 (RecoveryExecuted)

  • 30 Foundry 测试

Part 2: 企业 IAM (EnterpriseIAM 0x801A)

  • 新系统合约:组织管理 + 自定义角色 + uint256 权限位图

  • 8 权限常量: ISSUE_CREDENTIAL, REVOKE_CREDENTIAL, MANAGE_MEMBERS, MANAGE_ROLES, VIEW_REPORTS, MANAGE_COMPLIANCE, ADMIN, SIGN_TRANSACTIONS

  • ADMIN 权限隐含所有权限,Owner 自动拥有所有权限

  • DIDRegistry 集成:创建组织需 DID 活跃 + 调用者为 controller 或 delegate

  • L1 sync: Type 10 (OrgCreated), Type 11 (RoleAssigned), Type 12 (RoleRevoked)

  • 24 Foundry 测试

Part 3: 选择性披露 (IdentityVerifier 0x8019)

  • ZK 属性级证明(证明年龄 >= 18 而不暴露出生日期)

  • DisclosurePolicy: credentialType + requiredAttributes + circuitType

  • 新 circuitType: 3 (age proof), 4 (income proof), 5 (region proof)

  • 复用 Groth16 基础设施 (_circuitVerifiers, _usedProofs 防重放)

  • 验证成功自动设置 compliance key: SD_<policyId>

  • 12 Foundry 测试

E2E 测试: 4 个跨合约集成测试 (recovery+IAM, IAM+credential, disclosure+compliance, full lifecycle)

测试总计

测试文件
测试数

DIDRegistryRecovery.t.sol

30

EnterpriseIAM.t.sol

24

IdentityVerifierDisclosure.t.sol

12

Phase5cE2E.t.sol

4

Phase 5c 新增

70

项目总计

336

系统合约地址总表

地址
合约
Phase

0x8016

OracleHub

P2

0x8017

DIDRegistry

P5a + P5c (社会恢复)

0x8018

CredentialRegistry

P5a

0x8019

IdentityVerifier

P5a/b + P5c (选择性披露)

0x801A

EnterpriseIAM

P5c (新增)

技术决策

  • 社会恢复采用混合模式(N-of-M + 时间锁)而非纯多签,给原始控制者反应时间

  • 企业 IAM 独立为新系统合约(0x801A),避免 DIDRegistry 过于膨胀

  • 选择性披露复用现有 Groth16 基础设施,通过 DisclosurePolicy 映射策略到电路

  • 权限位图使用 uint256(256 位),当前定义 8 个权限,预留扩展空间

Last updated