news 2026/9/15 18:51:52

Foundry cast safe 命令完全指南:用 CLI 全流程部署与运营 Safe 多签账户

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Foundry cast safe 命令完全指南:用 CLI 全流程部署与运营 Safe 多签账户

Foundry cast safe 命令完全指南:用 CLI 全流程部署与运营 Safe 多签账户

【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry

cast safe是 Foundry 的 cast 命令套件中面向 Safe(原 Gnosis Safe)多签账户的完整操作子命令,覆盖 Safe 账户部署、交易服务委托管理、多签提案、签名、签名无关的模拟(signature-independent simulation)与链上执行全流程。本文以仓库 .changelog/cast-safe-transactions.md 记录的变更内容为骨架,结合 crates/cast/src/cmd/safe 下的全部源码实现,系统讲解每个子命令的用法、参数含义与底层原理,读完即可用 cast 命令行独立完成一个 Safe 多签账户从创建到执行交易的全生命周期管理。

一、cast safe 子命令全景

cast safe是 cast 下的一级命令组,在 crates/cast/src/cmd/safe/mod.rs 中定义为SafeSubcommand枚举,共包含 8 个子命令:

子命令作用实现文件
cast safe create部署一个 Safe 账户(多签钱包)deploy.rs
cast safe add-delegate为 Safe 所有者注册交易服务委托delegates.rs
cast safe list-delegates列出 Safe 已注册的委托delegates.rs
cast safe remove-delegate移除 Safe 所有者的委托delegates.rs
cast safe propose创建、签名并提交 Safe 交易提案proposal.rs
cast safe sign为已提案的 Safe 交易签名并提交确认proposal.rs
cast safe simulate无需所有者签名即可模拟 Safe 交易simulate.rs
cast safe execute链上执行已确认的 Safe 交易execute.rs

此外 mod.rs 还定义了SafeOperation枚举(Call = 0/DelegateCall = 1),以及构建 RPC provider 的公共辅助函数rpc_provider

二、cast safe create:部署 Safe 账户

cast safe create用于部署一个 Safe 多签账户,支持指定多个所有者与签名阈值。官方示例(见 mod.rs 中的文档注释):

# 单所有者、阈值 1,使用 ledger 签名 cast safe create $OWNER --threshold 1 --rpc-url $RPC --ledger # 三个所有者、阈值 2,使用 named account 签名 cast safe create $OWNER_1 $OWNER_2 $OWNER_3 --threshold 2 --rpc-url $RPC --account deployer

2.1 核心参数说明

根据 deploy.rs 中CreateArgs的定义,完整参数如下:

参数必填默认值说明
owners是(1 个以上)拥有 Safe 的地址列表,位置参数
--threshold全部所有者数量所需签名数;必须大于 0 且不超过所有者数量
--salt-nonce链特定的默认 nonceCREATE2 盐值 nonce,默认与 Safe Protocol Kit 的链特定 nonce 一致
--singleton规范的 v1.4.1 部署地址Safe singleton 合约地址,与--l1互斥
--l1false使用 L1 Safe singleton 而非 SafeL2
--factorySAFE_PROXY_FACTORY_V1_4_1SafeProxyFactory 地址
--fallback-handlerCOMPATIBILITY_FALLBACK_HANDLER_V1_4_1CompatibilityFallbackHandler 地址;传零地址可禁用它
--confirmations1等待的确认数
--timeout配置值部署确认超时(秒),可通过环境变量ETH_TIMEOUT设置
--poll-interval配置值轮询部署回执的间隔(秒),可通过环境变量ETH_POLL_INTERVAL设置

2.2 底层部署流程

从源码看,部署流程分为四个步骤(deploy.rs):

  1. 校验所有者配置:调用validate_owners,依次检查所有者列表非空、阈值大于 0 且不超过所有者数量、所有者不能为零地址或哨兵地址(SENTINEL_OWNER)、不能有重复所有者。
  2. 选择 singleton 并校验合约存在:若未显式指定--singleton,则在主网(chain_id == 1)或指定--l1时使用 L1 Safe singleton,否则使用 SafeL2。随后通过ensure_contract检查 singleton、factory、fallback handler 地址上确实存在代码,否则报错提示通过对应 flag 指定该网络的部署地址。
  3. 编码并发送部署交易:构造ISafe::setup的 initializer calldata(owners、threshold、fallbackHandler 等),再通过ISafeProxyFactory::createProxyWithNonce编码部署调用并发送。
  4. 解析 ProxyCreation 事件输出地址:从回执日志中过滤出 factory 发出的ProxyCreation事件,打印新 Safe 地址。若回执未发出该事件则报错。

一个值得注意的细节是默认 salt nonce 的计算:default_salt_nonce(chain_id)使用keccak256("{PREDETERMINED_SALT_NONCE}{chain_id}")计算。该逻辑有专门的单元测试matches_protocol_kit_default_salt_nonce验证其与 Safe Protocol Kit 的一致性(测试断言 chain_id 1 的默认 nonce 为0x69b3...a1f6)。

2.3 交易发送与 Tempo 网络支持

部署交易的发送统一由 transaction.rs 中的SafeSendOpts完成。该结构体打包了 RPC、钱包与交易参数,其send方法会根据是否 Tempo 网络选择TempoNetworkEthereum网络发送。cast safe createcast safe execute共用这套发送逻辑,并做了以下限制(当前版本):

  • 外层交易 value 必须为零;
  • 不支持 blob 交易与 EIP-7702 授权;
  • Tempo sponsorship(赞助)、Tempo Accounts 会话尚不支持(会明确报错提示)。

这正对应变更日志中提到的"Tempo fee-token transaction options":在 Tempo 网络上发送时支持其特有的费用代币交易选项。

三、委托管理:add-delegate / list-delegates / remove-delegate

Safe Transaction Service 支持"委托(delegate)"机制:所有者可以委托其他地址代为提交交易提案,而无需转移所有权。三个子命令分别对应注册、查询、移除委托。

3.1 添加委托

cast safe add-delegate $SAFE $DELEGATE --label "my-bot" --rpc-url $RPC --account signer

参数包括safe(Safe 地址)、delegate(允许提案的地址)和必填的--label(人类可读标签,源码中校验其非空)。实现上(delegates.rs)通过sign_delegate对 EIP-712 类型化数据签名后,向 Transaction Service 的v2/delegates/端点发送 POST 请求,请求体包含 delegate、label、safe、delegator 与签名。

3.2 列出委托

cast safe list-delegates $SAFE --rpc-url $RPC

实现上通过v2/delegates/?safe=...端点 GET 查询,并自动处理分页:循环跟随next字段,且会校验下一页 URL 必须仍指向同一 Transaction Service 端点(防止分页跳转到外部地址),最终以 JSON 数组打印全部委托。

3.3 移除委托

cast safe remove-delegate $SAFE $DELEGATE --rpc-url $RPC --account signer

对应v2/delegates/{delegate}/的 DELETE 请求,同样需要签名授权。

3.4 委托签名原理

委托相关的签名逻辑在 signing.rs 中:签名内容为 EIP-712 类型化数据,primaryTypeDelegate,字段为delegateAddresstotp,域名为Safe Transaction Service(version 1.0,chainId 为当前链)。totp是时间窗口 TOTP(now / 3600,即按小时取整),起到防重放的时间约束作用。Trezor 钱包走safe_eth_sign路径(对 EIP-712 哈希做 eth_sign),其他钱包直接sign_dynamic_typed_data

四、提案与签名:propose / sign

4.1 创建并提交提案

cast safe propose会在签名后向 Transaction Service 提交一条待确认的多签交易:

cast safe propose $SAFE $TO "transfer(address,uint256)" $RECIPIENT $AMOUNT --rpc-url $RPC --account owner1

参数说明(proposal.rs 中ProposeArgs):

参数说明
safe/toSafe 地址与交易目标地址(位置参数)
sig/args函数签名与参数;不提供时 calldata 为空
--data原始 calldata,与sig/args互斥(clap 强制冲突)
--valueSafe 转出的原生代币数量,默认 0,支持以太单位解析
--operationcall(默认)或delegatecall
--safe-tx-gas/--base-gas/--gas-priceSafe 交易 gas 相关字段,默认 0
--gas-token/--refund-receivergas 偿还代币与收款地址,默认零地址
--nonce交易 nonce,默认取 Transaction Service 下一个排队 nonce
--originSafe 客户端展示的可选来源信息

nonce 的默认获取逻辑值得说明:先从链上读取 Safe 的当前 nonce,再调用next_nonce查询 Transaction Service 的v1/safes/{safe}/multisig-transactions/?executed=false&ordering=-nonce&limit=1,取两者较大者(服务端 nonce 加一)。这保证了排队中的交易不会与链上 nonce 冲突。

4.2 为提案签名确认

cast safe sign $SAFE $SAFE_TX_HASH --rpc-url $RPC --account owner2

cast safe sign先从 Transaction Service(v1/multisig-transactions/{safe_tx_hash}/)拉取交易详情,然后做哈希校验verify_hash会确认服务端返回的 Safe 地址与命令行一致、operation 合法,并通过链上getTransactionHash重算交易哈希,确保与服务端返回的safeTxHash一致,防止服务端数据被篡改。校验通过后打印交易摘要(Safe、To、Value、Operation、Nonce、Data 等字段),对哈希签名,再 POST 到v1/multisig-transactions/{hash}/confirmations/提交确认。

五、签名无关的模拟:cast safe simulate

cast safe simulate是变更日志中强调的"signature-independent simulation"——不需要任何所有者签名即可验证一条 Safe 交易能否成功执行:

cast safe simulate $SAFE $SAFE_TX_HASH --from $EXECUTOR --rpc-url $RPC

5.1 原理与限制

模拟基于 Safe 的simulateAndRevertSimulateTxAccessor合约实现(simulate.rs):

  1. 从 Transaction Service 拉取交易并校验哈希;
  2. 拒绝报销型交易:若gasPrice > 0则报错,因为SimulateTxAccessor不强制执行safeTxGas(源码注释明确说明该限制);
  3. 检查 SimulateTxAccessor 合约存在(默认SIMULATE_TX_ACCESSOR_V1_4_1,可用--accessor覆盖);
  4. 构造simulateAndRevert(targetContract, calldataPayload)调用,其中 calldata 是 accessor 的simulate(to, value, data, operation)
  5. 期望该调用必然 revert,从 revert data 中解码(gasUsed, success, returnData)三元组;
  6. 若内部模拟失败(success == false),报错并输出消耗的 gas 与返回数据;成功则以 JSON 输出safeTxHashsuccessgasUsedreturnData

--from参数指定模拟的tx.origin(可通过环境变量ETH_FROM设置)。该模拟不校验Safe nonce、所有者签名、阈值或 guard 钩子,只关心内部 CALL/DELEGATECALL 在 Safe 上下文中能否成功,适合提案执行前的快速预检。

六、链上执行:cast safe execute

cast safe execute $SAFE $SAFE_TX_HASH --rpc-url $RPC --account executor

cast safe execute将已收集足够确认的交易真正上链(execute.rs),执行前做如下检查:

  • 交易未被执行过(服务端标记is_executed为 false 且无transaction_hash);
  • 重算哈希与服务端一致;
  • 交易 nonce 必须等于链上当前 nonce,否则拒绝执行(防止跳过排队交易)。

随后从服务端拉取全部确认签名,调用packed_signatures组装成 Safe 要求的签名打包格式,构造execTransaction调用并发送。签名打包逻辑在 service.rs 中,支持三类签名:

  • EOA 签名(v >= 27):固定 65 字节,按所有者地址升序排列静态段;
  • 合约签名(v = 0):携带动态数据,需校验长度字段与偏移量(偏移必须等于 65);
  • P-256 签名(v = 2):固定 65 + 128 字节,同样校验偏移;
  • 明确拒绝approved-hash(v = 1)签名类型。

执行后从回执日志中查找 Safe 发出的ExecutionSuccess/ExecutionFailure事件(取最后一个匹配safeTxHash的事件),若内部交易失败则报错。该逻辑同样有单元测试uses_last_matching_safe_execution_event覆盖。

七、Safe Transaction Service 自动发现

所有需要与 Safe Transaction Service 交互的子命令都依赖 service.rs 中的SafeServiceOpts

参数环境变量说明
--service-urlSAFE_TRANSACTION_SERVICE_URLTransaction Service URL;省略时根据 RPC 链 ID 推断;/api后缀可写可不写(源码会自动补齐)
--api-keySAFE_API_KEYTransaction Service API key,通过 Bearer 认证发送

当省略--service-url时,default_service_url会基于 chain_id 映射出官方服务地址(https://api.safe.global/tx-service/{short_name}),内置映射覆盖了以太坊(eth)、Arbitrum(arb1)、Base(base)、Optimism(oeth)、Polygon(pol)、BNB(bnb)、Gnosis(gno)、zkSync(zksync)、Linea(linea)、Scroll(scr)、Mantle(mantle)、Avalanche(avax)、Celo(celo)、Sepolia(sep)、**Tempo(chain 4217,short name "tempo")与 Tempo-Moderato(chain 42431)**等 30 余条链。未内置的链 ID 会提示"no known Safe Transaction Service for chain ID X; pass --service-url"。

值得注意的是list-delegates在显式提供--service-url时无需 RPC 连接(chain_id 传 0),因为服务端点已确定;其余命令仍需 RPC。该模块对 URL 规范化、非空/数字字符串反序列化、分页防循环等均有单元测试覆盖(见 service.rs)。

八、从一个提案到执行的完整工作流

综合以上各节,一个典型的多签交易生命周期如下:

# 1. 部署 Safe(多所有者、阈值 2) cast safe create $OWNER_1 $OWNER_2 $OWNER_3 --threshold 2 --rpc-url $RPC --account deployer # 2. 可选:注册委托,便于自动化工具代为提案 cast safe add-delegate $SAFE $BOT_ADDR --label "ops-bot" --rpc-url $RPC --account $OWNER_1 # 3. 所有者 1 创建并签名提案 cast safe propose $SAFE $TO "transfer(address,uint256)" $RECIPIENT $AMOUNT --rpc-url $RPC --account $OWNER_1 # 4. 执行前无签名模拟预检(任意执行者视角) cast safe simulate $SAFE $SAFE_TX_HASH --from $EXECUTOR --rpc-url $RPC # 5. 所有者 2 确认签名 cast safe sign $SAFE $SAFE_TX_HASH --rpc-url $RPC --account $OWNER_2 # 6. 达到阈值后链上执行 cast safe execute $SAFE $SAFE_TX_HASH --rpc-url $RPC --account $OWNER_1

整个流程在 crates/cast/src/cmd/safe 目录下闭环实现:部署与执行走 transaction.rs 的统一发送通道,提案/签名/模拟/执行共享 service.rs 的 Transaction Service 客户端与哈希校验逻辑,所有链上接口定义集中在 contracts.rs。如果需要在自动化脚本中集成 Safe 多签管理,cast safe是除 Safe CLI / Web 界面之外的轻量命令行替代方案,且与 Foundry 现有的--account--ledger等钱包体系无缝衔接。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:48:12

H5微场景源码包拆解:从解压到上线的完整工程实践

简介:这是一份面向Web前端学习者与开发者的H5微场景源码合集,13套项目涉及产品发布、品牌宣传、婚礼邀请、节日贺卡、教育培训等常见类型。初学者可通过完整工程理解从零搭建交互页面的流程,有经验的开发者则能直接从中提取动画交互方案或改造…

作者头像 李华
网站建设 2026/9/15 18:47:46

gs-quant Portfolio 指南:用 Python 构建、定价与风险管理投资组合

gs-quant Portfolio 指南:用 Python 构建、定价与风险管理投资组合 【免费下载链接】gs-quant Python toolkit for quantitative finance 项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant gs-quant 的 Portfolio 类是量化交易中处理一篮子工具的…

作者头像 李华
网站建设 2026/9/15 18:46:39

分布式系统服务根目录安全防护体系设计与实践

1. 服务根目录的安全防护体系设计在分布式系统架构中,服务根目录作为核心入口节点,其安全性直接关系到整个系统的稳定运行。我曾在某大型电商平台的微服务架构改造项目中,亲历过因根目录配置不当导致的全局性服务雪崩。那次事故让我们团队深刻…

作者头像 李华