SafeProxyFactory 创建 SafeProxy 并且 SafeProxy 继承 Safe
SafeProxyFactory 创建 SafeProxy 并且 SafeProxy 继承 Safe 所有方法的关键在于 代理合约(Proxy Pattern),特别是 SafeProxy 充当代理,并将调用委托给 Safe。让我们解析一下核心机制:
1. SafeProxy 是如何继承 Safe 方法的?
SafeProxy 其实并没有直接继承 Safe,而是通过 代理(Proxy)模式,利用 delegatecall 让 SafeProxy 具备 Safe 的所有方法。
SafeProxy 的核心逻辑通常在其 fallback 函数内,通过 delegatecall 把调用转发给 _singleton(也就是 Safe),让 SafeProxy 看起来像是 Safe,但实际上只是一个空壳:
2. deployProxy 是如何让 SafeProxy 具备 Safe 方法的?
在 deployProxy 方法中,我们关注以下关键点:
(1) 通过 CREATE2 创建 SafeProxy
bytes memory deploymentData = abi.encodePacked(type(SafeProxy).creationCode, uint256(uint160(_singleton)));
assembly {
proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
}
type(SafeProxy).creationCode:获取SafeProxy的合约代码。abi.encodePacked(..., uint256(uint160(_singleton))):将SafeProxy代码和_singleton地址编码到一起。create2(...):使用CREATE2部署SafeProxy,确保地址可预测。
关键点:这里
_singleton传入的是Safe的地址,意味着SafeProxy内部的singleton变量会被初始化为Safe的地址。
(2) SafeProxy 代理 Safe
当 SafeProxy 被创建后,它的 fallback 会将所有调用 delegatecall 到 _singleton,即 Safe。因此:
- 从外部调用
SafeProxy时,会通过fallback进入delegatecall,相当于直接调用Safe本体。 delegatecall让SafeProxy继承Safe的所有逻辑,但存储变量仍然在SafeProxy内部。
3. initializer 作用
initializer允许在部署后立即执行初始化,通常用于Safe的setup方法,以设置 owners、threshold、fallback handler 等信息。- 这避免了代理合约刚部署时处于未初始化状态,防止攻击者利用
delegatecall进行恶意初始化(类似EIP-1967的安全风险)。- 使用
call执行initializer:initializer是一个bytes类型的 calldata,它通常是Safe的setup方法的 ABI 编码参数。call发送交易到proxy(SafeProxy),执行initializer指定的初始化逻辑。
- 如果
call失败,则回滚整个交易。
各参数解析
这是一个
call低级操作,Soliditycall语法如下:参数解析:
参数 作用 gas()传递当前剩余 Gas 让 proxy运行initializerproxy目标合约地址,即 SafeProxy实例0发送的 ETH数量,这里是 0add(initializer, 0x20)initializer的数据指针,跳过前 32 字节长度信息mload(initializer)initializer的数据长度0返回数据存储的内存位置(这里忽略) 0返回数据的最大长度(这里忽略)
总结
SafeProxy只是一个壳,所有方法都通过delegatecall代理到Safe。deployProxy通过CREATE2创建SafeProxy,并设置Safe作为singleton。SafeProxy的fallback函数拦截所有调用,并delegatecall给Safe,让它表现得像Safe。initializer允许部署时执行Safe的setup,确保合约立即可用。
最终结果: 通过 SafeProxy 交互,相当于直接调用 Safe,但存储数据仍然保留在 SafeProxy 自己的存储空间内,这就是 代理模式(Proxy Pattern) 的强大之处。 🚀

浙公网安备 33010602011771号