﻿---
title: "钱包中的 Calldata 解码"
description: "以核验为先，系统说明交易调用数据、ABI 字与偏移量、选择器碰撞、代理、批量调用、授权、类型化数据许可、模拟与交易后对账。"
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.

# 钱包中的 Calldata 解码

> 仅供教育参考，不构成投资、法律或安全建议。解码和模拟可以减少歧义，但不能保证授权、执行、资产安全或最终性。

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

## 直接答案

Calldata 是作为输入传给以太坊顶层交易或内部消息调用的不可变字节串。常规 Solidity 函数调用以一个 `4-byte` 选择器开头，后接 ABI 编码参数，但 calldata 并非自描述格式：对于不同的运行时代码、代理实现或模式，同一组字节可能具有不同含义。回退函数、原始汇编以及非 Solidity 协议也完全不必遵循常规函数 ABI。

因此，钱包展示的内容不应止于候选函数名称。稳妥的复核应把这些字节与 `chainId`、具体区块、`from`、`to`、原生资产 `value`、运行时 `codeHash`、当前实现合约和可信 ABI 绑定；严格解码每一层嵌套调用；区分链上 calldata 与 EIP-712 签名；在明确的状态下模拟；并在交易入块后对实际回执和状态变化进行核对。

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

## 运作机制

1. 固定签名信封和观察时点：`chainId`、区块号与区块哈希、`from`、`to`、原生资产 `value`、输入字节、nonce 和费用字段。保留钱包或 RPC 数据来源；来自另一条链或另一时点的解码结果并非同一项判断。
2. 解码前先判定对象类型。交易、EIP-712 类型化数据请求、ERC-2612 许可、ERC-4337 UserOperation 和原始 personal-sign 消息使用不同的域与模式；不能全部强行套用交易 ABI。
3. 在固定区块解析目标。读取运行时字节码和 `codeHash`；识别适用的代理、信标或实现合约；记录实现与管理员存储槽；并取得与该确切代码版本匹配的 ABI。选择器登记库只能提供候选项，不能作为权威依据。
4. 严格解码。选择器是规范函数签名经 Keccak-256 哈希后的前 `4 bytes`，不含返回类型。静态值占用 `32-byte` 字；动态参数头保存相对于选择器之后参数区起点的偏移量。遇到截断数据、越界偏移量、不可能的长度、无效填充或无法解释的尾随字节，应拒绝签名。
5. 递归展开 multicall、嵌套 calldata 和委托执行。逐项列明子调用的目标、原生资产价值、选择器、参数、调用类型及任何 `allowFailure` 标志。使用 `delegatecall` 时，实现合约代码在调用方的地址、余额与存储上下文中运行，同时保留 `msg.sender` 和 `msg.value`。
6. 分别建立权限账本和价值账本，再进行模拟。记录收款方、spender、NFT 操作员、代币原始单位、decimals、截止时间、滑点边界与原生资产价值。用确切区块、发送方和价值进行模拟，但应把结果视为条件性快照，因为状态、价格、时间、代码和交易排序都可能改变。
7. 签名前确认每一个重要字段。入块后检查回执状态、日志、可用的调用轨迹，以及余额、授权额度和操作员状态变化；区分被捕获的子调用失败与顶层调用成功；即使交易回滚也要计入 gas；等待所需最终性；若失败原因无法解释，应停止操作而不是盲目重新签名。

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

## 计算示例

- **静态 ERC-20 转账。** `transfer(address,uint256)` 通常使用选择器 `0xa9059cbb`。一个选择器加两个 ABI 字共 `4 + 2 * 32 = 68 bytes`。原始数量 `1,500,000` 对于已独立核实采用 `6 decimals` 的代币显示为 `1.5 tokens`。decimals 属于外部合约元数据，并未编码在这些参数中；选择器本身也无法唯一识别合约或函数。
- **动态字节偏移量。** 对于 `f(address,bytes)`，若载荷为 `3-byte`，两个字组成的参数头占 `64 bytes`。动态偏移量为 `0x40`，从参数区起点计量，不包括选择器。参数尾包含一个 `32-byte` 长度字和一个 `32-byte` 填充数据字，因此 calldata 总长为 `4 + 64 + 32 + 32 = 132 bytes`。若把偏移量误当成从第零字节起算，位置会向后错四个字节。
- **批量调用中的价值处理取决于实现。** 外层调用携带 `1.00 ETH`；三个已解码子调用明确请求 `0.20 ETH`、`0.30 ETH` 和 `0.10 ETH`，合计 `0.60 ETH`。剩余 `0.40 ETH` 可能被退回、留存、继续转发，或导致回滚，具体取决于批量调用代码。如果第三个子调用失败且设置了 `allowFailure=true`，此前子调用可能仍然生效；原子式实现则可能回滚全部操作。
- **许可签名并不是签名时中继者的 calldata。** 一名持有 `1,000 USDC` 的所有者签署额度为 `300 USDC`、nonce 为 `41` 的 ERC-2612 许可。签名本身既不改变余额，也不改变授权额度。中继者成功提交后，nonce 变为 `42`，授权额度变为 `300`；spender 随后使用 `180`，余额为 `820`，剩余授权额度为 `120`。断开网站连接并不会撤销这项权限。

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

## 风险

- 按错误的链、分叉、区块标签或交易信封解码。
- 为伪造域名、目标地址或收款地址签名。
- 尽管可能发生碰撞，仍把 `4-byte` 选择器视为唯一标识。
- 使用猜测、过时或未经正确验证的 ABI。
- 只相信源码已验证标签，却没有匹配当前运行时 `codeHash`。
- 漏掉复核与执行之间发生的实现、信标或管理员升级。
- 忽略代理合约自身函数与实现合约发生的选择器冲突。
- 忘记 `delegatecall` 会在调用方的存储上下文中写入状态。
- 接受畸形的动态偏移量、长度、填充或尾随字节。
- 未展开隐藏目标、价值或权限的嵌套批量调用。
- 在实现会捕获或容许子调用失败时仍假定调用具备原子性。
- 因代币参数看似无害而忽略顶层原生资产 `value`。
- 使用错误的 decimals，或假定转账收费和变基代币遵循标准 ERC-20 行为。
- 授予无限 ERC-20 授权额度，或错误处理授权额度更新竞态。
- 忽略 NFT `setApprovalForAll` 覆盖整个系列的权限范围。
- 把 EIP-712 类型化数据或 ERC-2612 许可误当作交易 calldata。
- 漏查 nonce、截止时间、验证合约、链域或重放边界。
- 在预言机、时间戳、待处理状态、MEV 或代码变化下仍把模拟视为稳定结果。
- 把回执状态、日志或服务商调用轨迹当成完整的经济状态证明。
- 通过已被攻陷的界面盲目重新签名，或忽略入块、重组和最终性风险。

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

## 常见误区

- 函数选择器可以唯一标识合约将执行的操作。
- 已验证的前端摘要与正在签署的字节及当前实现完全相同。
- `value=0` 的交易无法转移代币、NFT 或已委托资产。
- 模拟成功或回执成功可以证明安全性和预期经济结果。
- 断开 dapp 连接会撤销授权、许可和 NFT 操作员权限。

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

## 相关主题

- [交易模拟](/zh-cn/crypto/transaction-simulation/)
- [钱包授权](/zh-cn/crypto/wallet-approval/)
- [钱包签名](/zh-cn/crypto/wallet-signature/)

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

## 来源

- [Contract ABI Specification](https://docs.soliditylang.org/en/latest/abi-spec.html) - Solidity Documentation（查阅日期：2026-08-12）
- [Introduction to Smart Contracts](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#delegatecall-and-libraries) - Solidity Documentation（查阅日期：2026-08-12）
- [Transactions](https://ethereum.org/developers/docs/transactions/) - Ethereum.org（查阅日期：2026-08-12）
- [ERC-20: Token Standard](https://eips.ethereum.org/EIPS/eip-20) - Ethereum Improvement Proposals（查阅日期：2026-08-12）
- [EIP-712: Typed structured data hashing and signing](https://eips.ethereum.org/EIPS/eip-712) - Ethereum Improvement Proposals（查阅日期：2026-08-12）
- [ERC-2612: Permit Extension for EIP-20 Signed Approvals](https://eips.ethereum.org/EIPS/eip-2612) - Ethereum Improvement Proposals（查阅日期：2026-08-12）
- [ERC-721: Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) - Ethereum Improvement Proposals（查阅日期：2026-08-12）
- [ERC-1967: Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967) - Ethereum Improvement Proposals（查阅日期：2026-08-12）

Source: https://wiki.fcontext.com/zh-cn/crypto/calldata-decoding-wallet/index.mdx
