EVM交易构造和解析

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 函数
a9059cbb transfer
095ea7b3 approve
23b872dd transferFrom
70a08231 balanceOf
dd62ed3e allowance

五、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 常见编码格式#

类型 编码
calldata hex
address 20 bytes
hash 32 bytes
signature 65 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

十八、EVM 解析核心知识#

EVM Calldata 解析笔记#

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. 常用工具#