Foundry Cast ERC-4626 兼容性检查与原生资产金额格式化的修复解析
【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry
本文基于 Foundry 仓库的变更记录(.changelog/fix-erc4626-inspection.md)展开,解析cast erc4626子命令在"ERC-4626 兼容性检查"与"原生资产(native asset)金额格式化"两处修复背后的源码实现与测试依据。读者将理解cast erc4626 check的 21 项探测逻辑、PASS/WARN/FAIL 三态判定、ERC-7535 原生资产哨兵与 ERC-7540 异步金库的识别方式,以及--human格式化输出的完整数据流。
变更背景:一次针对cast erc4626的 patch 级修复
变更记录原文如下:
--- cast: patch --- Fixed ERC-4626 compatibility checks and native-asset amount formatting.这是一条标准 Foundry changelog 片段:frontmatter 声明cast: patch级别(不破坏兼容性的缺陷修复),正文说明修复目标为两点:
- ERC-4626 兼容性检查(即
cast erc4626 check子命令); - 原生资产金额格式化(即对
asset()返回 ERC-7535 原生资产哨兵地址时的金额展示逻辑)。
与之配套的迭代记录可见 .changelog/cast-erc4626-commands.md(新增完整同步 ERC-4626 接口命令)与 .changelog/cast-erc4626-inspection.md(新增金库摘要、账户持仓与兼容性探测)。三者共同构成了cast erc4626从"命令落地"到"检查与格式化被修复完善"的演进脉络。
修复核心一:ERC-4626 兼容性检查的判定逻辑
cast erc4626 check <vault>用于对目标金库做只读的接口兼容性探测,其实现位于 crates/cast/src/cmd/erc4626.rs。修复涉及的核心是check_compatibility函数(约 L1125-L1322)。
21 项探测条目
探测通过 alloy 生成的IERC4626、IERC20Metadata、IERC165三个 Solidity 接口(见 L30-L74)发起eth_call,覆盖以下检查项:
- 合约存在性:
get_code_at验证金库地址存在字节码(无字节码判定 FAIL); - 资产解析:
asset()返回值校验——零地址判 FAIL、ERC-7535 原生哨兵判 WARN、普通代币则继续检查底层资产字节码与balanceOf调用; - 核心读数:
totalAssets()、totalSupply()、balanceOf(address)、allowance(address,address); - 零输入换算:
convertToShares(0)、convertToAssets(0),正常应返回 0,非零返回 WARN(record_zero_conversion,见 L1466-L1485); - 限额与预览:
maxDeposit、previewDeposit(0)、maxMint、previewMint(0)、maxWithdraw、previewWithdraw(0)、maxRedeem、previewRedeem(0); - 元数据:
name()、symbol()、decimals()。
测试文件 crates/cast/tests/cli/erc4626.rs 中以str!宏断言了完整输出,例如 L418-L445 展示的 21 项全部 PASS 场景,末行输出Summary: 21 passed, 0 warnings, 0 failed。
ERC-7540 异步金库的特殊处理
修复引入了一个重要的"放过"逻辑:部分金库是ERC-7540 异步金库,其规范要求previewDeposit/previewMint/previewWithdraw/previewRedeem有意 revert。代码通过IERC165::supportsInterface探测两个固定选择子(L27-L28):
const ERC7540_ASYNC_DEPOSIT_INTERFACE: FixedBytes<4> = FixedBytes::new([0xce, 0x3b, 0xbe, 0x50]); const ERC7540_ASYNC_REDEEM_INTERFACE: FixedBytes<4> = FixedBytes::new([0x62, 0x0e, 0xe8, 0xe4]);record_preview(L1487-L1528)据此区分四种情形:
| 探测结果 | 金库声明异步支持 | 判定 |
|---|---|---|
| 调用成功 | 是 | WARN(规范要求 revert) |
| 调用成功返回 0 | 否 | PASS |
| 调用成功返回非 0 | 否 | WARN(零输入预览通常应为 0) |
| 调用 revert | 是 | WARN(符合异步规范) |
| 调用 revert | 否 | FAIL |
同样,preview_error(L959-L966)在preview*单独调用失败时,给出"异步 ERC-7540 金库有意 revert 该预览"的明确错误提示,避免用户误判为金库损坏。
检查报告与退出语义
- 任一检查 FAIL 时,文本模式先打印完整报告再
bail!报错(L1309-L1320); - JSON 模式(
--json)下则抛出结构化错误,错误码为erc4626.compatibility_failed,并携带read_compatible: false与完整 checks 数组,测试断言见 L572-L574; - 报告顶部始终附带免责声明:该探测仅验证只读调用行为,不能证明状态变更函数的选择器覆盖或语义级 ERC-4626 合规(
CHECK_DISCLAIMER,L836-L837)。
修复核心二:原生资产金额的格式化
ERC-7535 原生资产哨兵
以太坊生态约定使用哨兵地址0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE表示"原生资产"(ETH 及其衍生链币)。代码中定义为:
const NATIVE_ASSET: Address = address!("EeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"); /// ERC-7535 asset quantities are denominated in wei. const NATIVE_ASSET_DECIMALS: u8 = 18;(见 L24-L26)
当asset()返回该哨兵时,info与position两条命令不再尝试调用IERC20Metadata(原生资产无合约、没有name()/symbol()/decimals()),而是:
- 将
Asset name、Asset symbol显示为<unavailable>; - 将
Asset decimals固定为 18(wei 精度); - 同时输出一条
erc4626_native_asset警告,提示基础 ERC-4626 写入命令不会自动附带原生价值,如需存入 ETH 应改用cast send --value(native_asset_warning,L1566-L1573)。
测试 L459-L473 验证了该路径:原生资产金库的info --human输出中,资产名称为<unavailable>、资产小数位为 18、总资产等以 wei 精度格式化。
--human格式化与 TokenAmount
金额展示由TokenAmount结构(L755-L770)承担:保留raw(wei 原值)与可选formatted(按小数位换算后的十进制字符串)。display_amount(L1431-L1437)仅在同时满足--human且存在格式化结果时输出带符号(如95183395.377893 USDC)的文本,否则回退到原始 wei 值,保证脚本解析始终稳定。
info命令还通过decimal_unit(10^decimals,溢出时返回 None,见 L1439-L1442)计算"每股资产"与"每资产股份"两个衍生指标(assets_per_share、shares_per_asset),它们同样走TokenAmount格式化管线。
入金/出金上限的警告策略
修复同时完善了零上限的语义提示:
maxDeposit/maxMint返回 0 时,提示"部分金库有意返回保守上限或对入金设门控,不必然代表无法入金"(warn_if_zero_entry_max,L1530-L1538);maxWithdraw/maxRedeem返回 0 但balanceOf(owner)非零时,输出erc4626_zero_max_withdraw/erc4626_zero_max_redeem警告,解释流动性、门控、提款队列等可能阻止标准出金(zero_exit_warning,L1551-L1564)。position命令中该逻辑由 L1097-L1104 触发,JSON 模式下的警告结构在测试 L400-L409 有完整断言。
源码级实现细节:并行探测与错误包装
info、position、check三个命令均使用tokio::join!并行发起全部eth_call,显著降低多 RPC 往返延迟(如 L984-L991 一次性并行拉取 6 项读数)。每个调用分别以.ok()或wrap_err处理,元数据类失败降级为<unavailable>,而asset()、totalAssets()等关键读数失败则直接报错,避免输出不完整结论。
check命令的账户参数为可选:未指定时回退到Address::ZERO(L1133-L1136),测试 L419-L420 展示了默认零地址账户的输出。
命令全景与实战用法
cast erc4626(别名cast vault,注册见 crates/cast/src/opts.rs)共 19 个子命令,单元测试 L1608-L1633 强制每个子命令都带有可运行的示例与示例输出。除检查/格式化修复点外,完整命令族如下:
| 类别 | 子命令 |
|---|---|
| 检查与摘要 | info、position、check |
| 只读查询 | asset、total-assets、convert-to-shares、convert-to-assets、max-deposit、preview-deposit、max-mint、preview-mint、max-withdraw、preview-withdraw、max-redeem、preview-redeem |
| 状态变更 | deposit、mint、withdraw、redeem(复用cast send的交易参数与私钥管理) |
典型用法示例(以 Morpho MetaMorpho 金库为例,地址取自 crates/cast/tests/cli/erc4626.rs 的生产金库清单):
# 查看金库摘要(人类可读金额) cast erc4626 info 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB --human \ --block 25519075 --rpc-url https://ethereum.reth.rs/rpc # 查看指定账户的持仓、资产等价与提现上限 cast erc4626 position 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB \ 0x255c7705E8bb334dfCaE438197f7c4297988085A --human # 只读兼容性探测(21 项检查) cast erc4626 check 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB \ --account 0x255c7705E8bb334dfCaE438197f7c4297988085A --rpc-url $ETH_RPC_URL # 机器可读的 JSON 输出 cast erc4626 check 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB --json各只读命令均支持--block/-B指定查询区块高度,交易类命令支持--async、--private-key等标准cast send参数;对需要存入原生资产的 ERC-7535 金库,按源码提示改用cast send --value附加上链值。
测试保障与验证范围
修复由 crates/cast/tests/cli/erc4626.rs 的端到端测试兜底,覆盖三类场景:
- 本地 Anvil 部署的测试金库(
TestVault.sol与异步变体TestAsyncVault):验证 21 项 PASS 输出、ERC-7540 异步扩展的 WARN 行为、原生资产哨兵路径及 JSON 错误结构; - 以太坊生产金库(
PRODUCTION_VAULTS:Morpho MetaMorpho、Yearn V3、Maple syrupUSDC)在固定分叉高度25_519_075下执行全部只读命令面与info/position/check检查面,断言输出非空; - Tempo 网络的 Morpho 金库(
TEMPO_VAULT)在分叉高度37_847_799下验证多网络兼容性。
这套测试矩阵保证了兼容性检查的判定逻辑与原生资产格式化在真实生产合约上持续有效,也是本次 patch 修复的核心回归防线。
【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考