﻿---
title: "Delegatecall 存储风险"
description: "Delegatecall 会在调用者合约的存储上运行另一个合约的代码。了解存储冲突、升级权限和不受信任的目标如何危及代理合约或智能钱包。"
image: "https://wiki.fcontext.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://wiki.fcontext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Delegatecall 存储风险

> 仅供教育参考，不构成投资建议；投资可能产生损失。

<a id="answer"></a>

## 直接答案

`delegatecall` 在调用者合约的上下文中执行目标合约的代码。调用者保留自己的存储、余额和 `address(this)`，而 `msg.sender` 和 `msg.value` 则保留原始调用中的值。

这种行为让代理合约、库和智能钱包模块成为可能，但也会把调用者的实际权限交给被委托执行的代码。存储写入、资产转移、授权或外部调用均以调用者而非提供代码的目标合约身份执行。

应将每个可触达的 `delegatecall` 目标都视为特权代码。安全性取决于目标选择规则、存储布局是否兼容、初始化状态、升级控制，以及该笔交易实际使用的确切实现。

<a id="mechanism"></a>

## 工作原理

普通外部调用会读写被调用者自己的存储。使用 `delegatecall` 时，目标字节码则在调用者的存储上运行：一条 `SSTORE` 指令会更改属于调用者的存储槽。目标代码中的变量名在运行时并不重要，只有计算得到的存储槽位置才重要。

因此需要审计以下四个边界：

- **目标控制：** 确定目标地址是固定的、由用户选择的、通过注册表解析的，还是可由管理员更改的。
- **存储兼容性：** 对比每个实现版本的变量顺序、类型、继承关系、存储间隙，以及命名空间槽或标准化槽。
- **初始化与授权：** 确认初始化器无法重复执行，并确认升级或模块管理函数会强制校验预期的调用者和治理延迟。
- **返回值处理：** 验证失败会向上传播，且返回数据按预期类型解码；低级调用不会提供 Solidity 通常具备的合约类型检查。

ERC-1967 将实现、信标和管理员地址放在正常编译器分配范围之外的标准化存储槽中，从而减少代理合约的存储冲突。但它并不能证明某个实现是安全的，也不能证明经授权的升级是善意的。

<a id="example"></a>

## 示例

假设某个钱包将 `owner` 存储在 `slot 0`。一个插件在编译时把 `counter` 放在 `slot 0`，钱包通过 `delegatecall` 调用该插件时，插件递增这个计数器。

由于存储属于钱包，这次写入会改变钱包的 `owner` 值。如果写入后的字编码了攻击者控制的地址，后续授权检查就可能把攻击者识别为所有者，尽管插件本身从未持有钱包资产。

成功的交易回执无法区分预期状态变更和有害状态变更。因此，交易模拟应针对确切的代理地址和实现地址，检查存储差异、资产和授权变化、发出的事件以及下游调用。

<a id="risks"></a>

## 风险

- **任意目标执行：** 用户控制或验证薄弱的目标可以利用调用者的权限运行恶意代码。
- **存储冲突：** 实现合约可以覆盖所有权、余额、暂停状态，甚至覆盖用于选择下一个实现的存储槽。
- **不安全升级：** 管理员或治理流程遭到入侵后，可以在用户存入资产或授予授权之后替换此前已经审查的代码。
- **初始化失败：** 未初始化的代理或实现合约可能允许其他账户取得特权角色，或配置危险的依赖项。
- **误导性检查：** 只验证代理源码、当前实现或接口，可能会遗漏信标、待执行升级、模块注册表或其他执行路径。

签名前，应在近期区块上解析实现地址，核实谁能在何种延迟下更改它，检查目标的已验证字节码和存储布局，模拟完整调用数据，并比较执行前后的敏感存储与代币授权。对于智能钱包，还应审查模块如何启用、禁用，以及它们如何获准选择目标。

<a id="misconceptions"></a>

## 常见误区

- **“目标无法动用调用者的资产。”** 被委托执行的代码以调用者身份运行；只要调用者具备相应能力，它就能调用外部合约、转移资产或创建授权。
- **“变量名相同就能避免冲突。”** EVM 使用存储槽，而不是源代码中的名称。布局顺序、继承关系和类型必须保持兼容。
- **“代理代码经过验证，就代表整个系统已经过验证。”** 当前实现、信标、升级管理员、初始化状态和模块权限都是信任边界中彼此独立的部分。

<a id="related"></a>

## 相关主题

- [加密经济安全](/zh-cn/crypto/crypto-economic-security/)
- [私有交易 RPC](/zh-cn/crypto/private-transaction-rpc/)
- [代理合约](/zh-cn/crypto/proxy-contract/)
- [智能合约](/zh-cn/crypto/smart-contract/)
- [交易模拟](/zh-cn/crypto/transaction-simulation/)

<a id="sources"></a>

## 来源

- [Introduction to Smart Contracts](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html) - Solidity Documentation (查阅日期: 2026-08-20)
- [Units and Globally Available Variables](https://docs.soliditylang.org/en/latest/units-and-global-variables.html) - Solidity Documentation (查阅日期: 2026-08-20)
- [ERC-1967: Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967) - Ethereum Improvement Proposals (查阅日期: 2026-08-20)

Source: https://wiki.fcontext.com/zh-cn/crypto/delegatecall-storage-risk/index.mdx
