解析代理合约的存储状态

用真实 Proxy、Implementation、区块和 Slot 区分状态地址与代码布局来源。

案例目标

确认代理模式下状态存在哪里、应使用哪个合约的 Storage Layout,以及如何在指定区块读取和验证原始 Slot。

示例交易与背景

本例继续使用区块 17806056 中的交易:

0xa84aa065ce61dbb1eb50ab6ae67fc31a9da50dd2c74eefd561661bfce2f1620c

在 Skylens 中打开交易

分析对象是 Curve pETH-ETH-f 池。用户交互地址是 minimal proxy 0x9848482da3Ee3076165ce6497eDA906E66bB85C5,执行逻辑来自 implementation 0x6326DEbBAa15bCFE603d831e7D75f4fc10d9B43E

预期回答的问题

  1. 状态应从 Proxy 还是 Implementation 读取?
  2. Storage Layout 应从哪个地址加载?
  3. 指定区块中的 slot 8 如何与交易内 SSTORE 对应?

分析步骤

  1. 打开 Proxy 地址,在 Proxy Storage 中确认并加载 implementation。
  2. 保持状态地址为 Proxy,只把 implementation 作为源码和 Storage Layout 来源。
  3. Storage Layout 中定位 slot 8;未能可靠解码变量名时,保留原始 Slot 作为查询键。
  4. 在区块 17806056 查询该 Slot,并与交易的 State Changes 对照。
  5. 从 State Changes 跳转 Execution Trace,验证 implementation 代码中的 SSTORE 实际写入 Proxy 上下文。

关键证据

证据类型
State addressProxy 0x9848482da3Ee3076165ce6497eDA906E66bB85C5
Layout / code sourceImplementation 0x6326DEbBAa15bCFE603d831e7D75f4fc10d9B43E
Query block17806056
Storage keyslot 80x...0008
Before0x00000000000000000000000000000000000000000000014f4ef71451a6d37997
After0x00000000000000000000000000000000000000000000003f3278e0363aaefcf
SSTORE traces6987105144194

这组证据同时保留了三个不同身份:

  • 状态身份:Proxy 地址;
  • 代码与布局身份:Implementation 地址;
  • 历史上下文:交易和区块 17806056

如果直接查询 implementation 的 slot 8,得到的是 implementation 自身的 Storage,不能代表池的业务状态。

案例结论

pETH-ETH-f 池的代码由 implementation 提供,但 slot 8 的实际状态保存在 Proxy。交易中的五次 SSTORE 由 implementation 代码执行,State Changes 却正确归属于 Proxy 地址。读取代理状态时必须使用“implementation 的布局 + proxy 的 Storage + 目标区块”这一组合。

注意事项

  • 历史区块必须匹配当时生效的 implementation;当前实现未必能解释旧状态。
  • Implementation 自身也可能是 Proxy,需要继续加载嵌套实现。
  • @custom:storage-location 命名空间应使用 EIP-7201 Decoder,不能按普通 slot 0 布局推断。
  • 未验证布局时,先报告地址、Slot 和原始值,不要把推测的变量名写成事实。

相关文档