EVM交易构造和解析

2026/03/08 Web3 共 3597 字,约 11 分钟

EVM交易构造和解析

一、EVM 交易基础结构

EVM 交易本质是 对账户或合约的一次调用。

标准交易字段:

Transaction
├─ nonce
├─ gasPrice / maxFeePerGas
├─ gasLimit
├─ to
├─ value
├─ data
├─ chainId
└─ signature (v,r,s)

关键字段说明:

字段作用
nonce防止重放,账户交易序号
to目标地址(EOA 或合约)
value转账 ETH 数量
data调用合约函数数据
gasLimit最大 gas
gasPrice每单位 gas 价格

如果:

data = 0x

则是普通转账。


二、EVM 交易类型

常见交易类型:

1 Legacy Transaction

旧交易结构:

nonce
gasPrice
gasLimit
to
value
data
v,r,s

2 EIP-1559 Transaction

增加了动态费率:

maxPriorityFeePerGas
maxFeePerGas

交易类型:

type = 2

3 EIP-2930 Transaction

支持 access list:

type = 1

4 Account Abstraction / 特殊结构

例如:

  • EIP-4337
  • EIP-7702

会出现:

call struct
batch calls

三、EVM calldata 编码

EVM 合约调用通过:

data (calldata)

编码规则来自 ABI encoding。

基本结构:

4 bytes   function selector
N bytes   parameters

四、Function Selector

selector 计算方法:

keccak256("functionSignature")[0:4]

例如:

transfer(address,uint256)

计算:

keccak256("transfer(address,uint256)")

取前 4 bytes:

a9059cbb

所以:

0xa9059cbb

表示 ERC20 transfer。

常见 selector:

selector函数
a9059cbbtransfer
095ea7b3approve
23b872ddtransferFrom
70a08231balanceOf
dd62ed3eallowance

五、ABI 参数编码规则

ABI 使用:

32 bytes slot

参数对齐方式:

uint256 → 32 bytes
address → 32 bytes (左填充)
bool → 32 bytes

示例:

transfer(address,uint256)

calldata:

a9059cbb
0000000000000000000000008c99bc6137cfe81a295fff86de795e0557b60f46
00000000000000000000000000000000000000000000000000000000000f4240

解释:

selector
address
amount

六、动态参数编码

如果函数包含:

string
bytes
array
struct

使用 offset 编码。

结构:

selector
offset
...
dynamic data

示例:

function foo(string)

编码:

selector
offset (0x20)
length
data

七、EVM 地址编码

EVM 地址:

20 bytes

calldata 中表示为:

32 bytes

示例:

0000000000000000000000008c99bc6137cfe81a295fff86de795e0557b60f46

规则:

前 12 bytes 填充 0
后 20 bytes 地址

八、数字编码

EVM 所有整数:

uint256

编码:

32 bytes big-endian

示例:

0x0f4240

转十进制:

1000000

九、交易构造流程

构造交易通常步骤:

1 定义函数
2 ABI encode 参数
3 构造 calldata
4 填充交易字段
5 签名
6 广播

示例(ethers.js):

const iface = new ethers.Interface(abi)

const data = iface.encodeFunctionData(
  "transfer",
  [to, amount]
)

const tx = {
  to: token,
  data: data,
  value: 0
}

十、交易签名

EVM 使用:

ECDSA secp256k1

签名字段:

r
s
v

交易 hash:

keccak256(rlp(tx))

签名后:

rawTransaction

十一、交易解析流程

解析一笔交易通常:

1 获取 transaction
2 读取 data
3 解析 selector
4 查 ABI
5 decode 参数

流程图:

transaction
   ↓
data
   ↓
function selector
   ↓
ABI
   ↓
decode parameters

十二、Batch / Multicall 交易

DeFi 常见:

multicall

结构:

call[]
 ├─ target
 ├─ calldata
 └─ value

例如:

swap
transfer
transfer

十三、EVM 常见编码格式

类型编码
calldatahex
address20 bytes
hash32 bytes
signature65 bytes

EVM 基本全部使用:

hex (0x)

十四、Calldata 解析工具

常见工具:

  • Foundry
  • Tenderly
  • ethers.js

常用命令:

cast 4byte
cast decode-calldata

十五、交易 trace

复杂交易需要:

trace

trace 可以看到:

internal calls
delegatecall
staticcall
transfer

常见工具:

  • Tenderly
  • Hardhat

十六、链上解析常见数据

解析交易通常关注:

token transfers
swap events
logs
internal transactions

日志结构:

event signature
topics
data

event signature:

keccak256("Transfer(address,address,uint256)")

十七、事件日志解析

日志结构:

log
├─ address
├─ topics[]
└─ data

topics:

topic0 = event signature
topic1 = indexed param
topic2 = indexed param

示例:

Transfer(address,address,uint256)

topics:

topic0 event hash
topic1 from
topic2 to

data:

amount

十九、EIP-7702 Gas 代付流程

EIP-7702 实现了 账户抽象,允许合约代替用户支付 Gas。

流程

用户签名
   ↓
Relayer 收到签名
   ↓
Relayer 发链上交易
   ↓
7702 delegate contract 执行逻辑
   ↓
Sponsor/Paymaster 出 gas

各方职责

角色职责
用户签名授权,不需要主币
Relayer最终广播者,收取用户签名后构造并广播交易
Delegate Contract决定执行规则,验证签名,执行逻辑
Sponsor/Paymaster实际支付 Gas 费用

关键特点

  • 用户不需要主币:Gas 由 Sponsor 代付
  • Relayer 广播:承担链上交易的实际发送
  • Delegate Contract:可编程的执行规则,决定谁可以代理、收取多少手续费等

与传统交易的区别

传统交易:
  用户 → 链上(用户签名 + 广播,自身付 gas)

7702 代付:
  用户签名 → Relayer → 链上(Relayer 广播,Sponsor 付 gas)

二十、EVM 解析核心知识

1. 基本概念

  • calldata:以太坊 EVM 中交易调用合约的输入数据。
    • msg.data 在 Solidity 中对应 calldata
    • 包含函数选择器 + 函数参数编码
  • 函数选择器(function selector):
    • 前 4 字节(8 个 hex 字符)
    • 由函数签名(functionName(type1,type2,...))经过 Keccak256 哈希取前 4 字节生成
  • 参数编码:
    • 使用 ABI 编码,固定长度类型按 32 字节对齐,动态类型附带偏移和长度信息

2. 解析步骤

  1. 拆分选择器与参数
    • calldata: 0xa9059cbb000000000000000000000000e84e684c...
    • 前 4 字节 a9059cbb → 查函数对应的 selector → transfer(address,uint256)
  2. 解析参数
    • 固定长度类型(uint256、address、bool…):
      • 直接按 32 字节切片
      • 地址 address 在低 20 字节
    • 动态类型(string、bytes、数组):
      • 前面存偏移量(从 calldata 开始的字节位置)
      • 偏移位置存长度,再后面是实际数据
  3. 多函数调用(multicall / 7702 struct)
    • calldata 可能包含多个子调用
    • 每个子调用有:
      • target 地址
      • 子调用 callData(单独解析)
      • value(支付的 ETH 数量)

3. 常用工具

Search

    Table of Contents