读完 5 分钟,你将一次性搞懂 以太坊交易、ETH/ERC20 转账、合约交互和部署 的全部细节。
把重点放进收藏夹,开发时再照着敲,就能少踩 90% 的坑。
基本概念:以太坊交易是什么?
以太坊可被视为 交易驱动的状态机。任意时刻,链上所有余额、合约、NFT 的状态,都由“刚才已被确认的交易”决定;任何新的 交易 transaction 一旦被矿工打包,就会推动状态再次变化。
一次交易长什么样子?
一条标准交易包含 9 个字段,核心关键词涵盖:recipient、signature、value、data、gasLimit、maxFeePerGas、maxPriorityFeePerGas、nonce。
| 字段 | 作用&注意点 |
|---|---|
| recipient | 收款地址,外部账户或智能合约皆可。 |
| signature | 你钱包私钥的签名,防伪造。 |
| value | 随交易附赠的 ETH 数量(单位 Wei)。 |
| data | 与合约交互时必填,调什么函数靠它下指令。 |
| gasLimit / maxFeePerGas / maxPriorityFeePerGas | 成本防护罩,防止耗费过多手续费。 |
| nonce | 递增序号,保证先后顺序、抗重放攻击。 |
小技巧:想替换或“取消”已在交易池的交易?发一笔同等 nonce、更高 priorityFee 的新交易即可 —— 通常是给自己转 0 ETH。
交易分为 3 类
- 常规转账:EOA → EOA(外部地址转账)。
- 合约执行:EOA → 合约地址,如 mint NFT。
- 合约部署:recipient 为空,附带基建代码 → 生成全新合约。
转账 Transfer:ETH vs ERC20
不少人误以为“转账”是同一件事,实际上 ETH 转账与 ERC20 代币转账 底层行为完全不同。
ETH 转账
- 无需 data,仅填写收款地址 + 转账金额。
成功/失败逻辑极简:
- 收款地址是 EOA → 总是成功,哪怕该地址从未上链。
- 收款地址是合约 → 自动触发合约
receive()或fallback(),两函数至少一个需payable,否则交易 revert。
示例代码:
// 这个合约想接受纯 ETH 转账,必须补上 receive 或 fallback
receive() external payable {}
// 如果还想处理附带 data 的转账:
fallback() external payable {
emit FallbackCalled(msg.data);
}ERC20 代币转账
- 本质是“调用合约函数”。
- 交易 recipient 填写 代币合约地址。
- data 里编码
transfer(address,uint256)并附带接收方地址 + 转账数量。 - value 字段通常填 0(你不是给合约转 ETH)。
标准写法:
// 标准 ERC20 函数原型
function transfer(address _to, uint256 _value) public returns (bool);合约底层用 mapping(address => uint256) 保存余额,自由度很高 —— 例如你可以在 transfer 中额外燃烧 10% 实现通缩设计。
合约交互:data 字段拆解
向合约发送交易时,data 负责说明具体调用哪个函数、传递什么参数。
结构速读
前 4 Byte:函数选择器 = keccak256("函数签名")[:4]
后续字节:ABI 编码后的参数举个 mint 例子:
Function = mint(uint256 _amount) → keccak256 后得 0xa0712d68。 data 字段即 0xa0712d68... + ABI 编码的 _amount 值。
👉 想在浏览器实时体验逆向合约 input data?在 Etherscan 一键解析更直观!
合约如何匹配函数?
链上字节码里存在一个自动生成的 dispatcher(语义相当于 C 语言入口 main)。
流程:
- 取 input 前 4 字节 → 与函数哈希对比。
- 命中 → 跳转至对应函数;未命中 → revert。
部署新合约:部署交易剖析
部署同样是一笔 recipient = 0x0 的特殊交易,data 并非最终运行代码,而是 构造函数输出的字节码生成器。
步骤流程
本地/Remix 编译 Solidity,得到两部分:
creationCode= 构造函数 + 逻辑代码。runtimeCode= 去掉构造函数后的真正 ELF,tag0x60806040...第二次出现即为 runtime 起点。
- 交易广播 → EVM 执行构造函数 → 返回 runtimeCode → 存入区块链,并以
keccak256(sender, nonce)算法计算新合约地址。
👉 想验证一下?对照刚部署的合约 hash,确认 runtimeCode 是否恰好从第二个 0x60806040 开始!
FAQ:关于交易与合约的 5 个高频疑问
Q1:MetaMask 能发“批量交易”吗?
A:MetaMask 单次请求只能打包 1 条链上交易;如需批量,可手动构造多笔并同 nonce 或者写合约合约包装器一次性完成。
Q2:为什么我把 nonce 设错,交易一直挂起?
A:以太坊严格按照 nonce 顺序执行,若中间某个 nonce 丢失,后续全部 pending。补发缺失 nonce 的交易即可疏通。
Q3:没有 receive/fallback,ETH 就不能打进合约?
A:尝试直接转账会 revert;开发者可设计 deposit() 函数通过调用方式入账并保存余额。
Q4:ERC20 的 transfer 会不会消耗我钱包里的 ETH?
A:会,因为仍是链上交易,需付 gas。代币合约不会从你的 ETH 余额扣钱,但矿工费一样跑不掉。
Q5:为何部署后合约地址和我的测试地址差很远?
A:地址由当时的发起者地址与部署交易对应的 nonce 共同计算,任何细微变量都会改变结果。
小结 & 下一步
把今天梳理的关键词 交易字段、ETH 转账、ERC20 transfer、合约交互、部署生成器 记录到速查表:
- 开发时先自问“我要改状态吗?”,若“是” => 需发交易;若“否” => 只读 call。
- 所有改变状态的步骤,都先估算 gas,再补强 priorityFee。
下篇我们将借助 Remix & Hardhat 亲手写一条带 receive/fallback 的合约,把它发上测试网并让前端用 ethers.js 跟合约对话。保持关注,下集不迷路!