高效、省 gas 的「一对多」解决方案,一次交易发送 ETH 或 ERC20 代币。
核心关键词:以太坊批量转账、gas 优化、多地址发送、智能合约教程、ERC20、批量空投、省钱技巧
为什么需要「一对多」转账?
对空投社群、结算工资、归还质押奖励等场景来说,一笔一笔人工转账既费时也费钱。以太坊原本只支持「一对一」交易,当你循环调用 transfer() 时,gas 费用迅速飙升,还可能触碰单区块 gasLimit。
解决思路:写一个「多地址并发」的智能合约,把所有收款地址和金额作为参数一次性发送,合约内部帮你逐一转账,外部只消耗一次交易费。
技术原理
- 用户把资金 + 数据发送到批量转账合约的某个函数。
- 合约在内部循环执行
transfer()或token.transferFrom()。 - 链上依旧生成多条内部交易,但只需消耗一次外层 gas。gas 便宜时,百元级空投能一次省下可观的 ETH。
可视化流程:
DApp ───────────────────→ BulkTransfer ───┬──→ 地址1
(一次交易) ├──→ 地址2
└──→ ……NETH 批量转账合约(示例代码)
核心逻辑:循环调用 Solidity 原生 transfer(),剩余 ETH自动退回发送方。
pragma solidity ^0.8.0;
contract ETHBulkSender {
event MultiTransfer(
address indexed from,
address indexed to,
uint amount
);
function multiSend(
address[] calldata recipients,
uint[] calldata amounts
) external payable {
require(recipients.length == amounts.length, "Length mismatch");
uint total;
for (uint i = 0; i < recipients.length; i++) {
total += amounts[i];
require(payable(recipients[i]).send(amounts[i]), "Send failed");
emit MultiTransfer(msg.sender, recipients[i], amounts[i]);
}
require(msg.value >= total, "Insufficient ETH");
// 退回多余 ETH
if (msg.value > total) {
payable(msg.sender).transfer(msg.value - total);
}
}
}⚠️ 实验性质,请先部署到测试网检验 gas 与回退逻辑。
ERC20 批量转账合约(示例代码)
当空投的是 USDT、DAI 等 ERC20 时,需先 approve 合约额度,再调用 transferFrom 多次。
pragma solidity ^0.8.0;
interface IERC20 {
function transferFrom(address,address,uint) external returns (bool);
}
contract ERC20BulkSender {
event MultiERC20Transfer(
address indexed token,
address indexed from,
address indexed to,
uint amount
);
function multiSendERC20(
IERC20 token,
address[] calldata recipients,
uint[] calldata amounts
) external {
require(recipients.length == amounts.length, "Length mismatch");
for (uint i = 0; i < recipients.length; i++) {
require(
token.transferFrom(msg.sender, recipients[i], amounts[i]),
"Transfer failed"
);
emit MultiERC20Transfer(
address(token),
msg.sender,
recipients[i],
amounts[i]
);
}
}
}别忘了先执行 approve(contractAddress, totalAmount)!
节省 gas 的 4 个实战技巧
- 合并数组长度检查:一次
require省一次跳转。 - 使用 calldata:大数组走
calldata可省复制 gas。 - 事件压缩:只留
to和amount,减少日志大小。 - 批量检查 approve:链下脚本预先算好
totalAmountIRY。
示例场景:向 1,000 名社群成员各发 10 USDC。
传统方式需 1000 笔交易,gas ~ 10×1000×21000 = 210,000,000。
采用合约批量操作,单次 gas ~ 1,300,000,节省 90%+。
构建属于你的批量转账 DApp
步骤 1:编写并测试合约
- Hardhat:
npx hardhat test - Foundry:
forge test - Remix:直接跑 Goerli,无须本地安装
步骤 2:前端集成
- React + ethers.js:调用函数
multiSend或multiSendERC20 - 前端自动计算总费用,弹窗确认 MetaMask 签名
- 做好「待执行列表」缓存,防止浏览器刷新数据丢失
步骤 3:异常处理
require失败会带着地址序号回退,链下脚本需记录成功位点- 监听
MultiTransfer事件,实时刷新 UI 进度条
常见问题 FAQ
|Q: 直接循环 transferFrom 会不会超限?
A: 是,数组过长会过区块 gasLimit(当前约 30M)。实测 400 笔左右较稳妥,再长可切分批次。
|Q: 退回多的 ETH 不是又烧一次 gas 吗?
A: 最后 transfer 回退金额在合约内部完成,属于子调用,不会触发新的外部交易费。
|Q: 能否同时发送 ETH 与 ERC20?
A: 可以把两部分逻辑写在单个函数,或让用户分两次调用,后者更灵活可并行。
|Q: 是否支持 EIP-1155 NFT 批量空投?
A: ERC1155 自带 safeBatchTransferFrom,同样可封装到统一入口,思路相同。
|Q: 如何防止同一地址重复领代币?
A: 可在 MerkleTree 白名单或链下签名参数上做校验,合约内解析后再转账。
|Q: 有哪些开源库可直接复用?
A: 可参考 OpenZeppelin Multicall 或一些空投脚本,但务必切换最新编译器,避免 pragma 0.4.x 老旧安全问题。
部署前的两大必做检查
- 安全审计:切勿把 PoC 代码直接用于生产,检查重放、整数溢出(Solidity 0.8+ 已内置 SafeMath)。
- 真实成本测算:用 Hardhat gasReporter 跑 50/200/1000 笔数据,估算主网费用后再决定是否上线。
做好以上步骤,就能在下一个空投活动里“一次打包,千笔到账”!