0%

利用合约批量发送ETH

原因:

我昨天看到Blast×Element有一个特殊的免费NFT——机甲兔。

他每个用户都只能领取一个,限量30万个。

我的做法是,大号里面先用跨链桥将sepolia的测试币转换成blast的测试币。

然后从大号里面发送到小号,再由小号领取NFT。

写成程序就是两个操作:

1:大号批量发送ETH余额到小号

2:小号批量合约交互(MintNFT)

他的领取并不复杂,而且没有啥变动的量,直接写死就好。

但是发送我是直接复制以前的代码,然后改动了RPC和链ID就可以运行了。

但是官方的节点实在是太慢了,而且还容易发送失败,经常漏掉一些账号。

我原本的想法是缝缝补补,在发送前加一个查询操作,如果小号钱包没有余额就发送,否则就跳过。

这样一来增加了节点的压力,而且同样不能保证一次成功。

最后,看着NFT的进度条快没有了,忍不住直接问GPT,我要写合约批量发送ETH。

代码:

这是GPT给出的代码,问了两次,效果还不错,带中文注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract BatchTransferETH {
address public owner;

receive() external payable {
// 这是 fallback 函数,用于接收以太币
}

modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}

constructor() {
owner = msg.sender;
}

// 批量转账函数
function batchTransfer(address[] calldata recipients, uint256[] calldata amounts) external onlyOwner {
require(recipients.length == amounts.length, "Arrays length mismatch");

for (uint256 i = 0; i < recipients.length; i++) {
address recipient = recipients[i];
uint256 amount = amounts[i];

// 调用转账函数
require(payable(recipient).send(amount), "Transfer failed");
}
}

// 合约所有者可以将合约余额提取到自己的地址
function withdraw() external onlyOwner {
payable(owner).transfer(address(this).balance);
}
}

运行:

先在remix编译,部署,然后调用部署的合约。

编辑网站:

https://remix.ethereum.org/

image-20240207235009849

编译代码:

image-20240207235320390

部署代码:

image-20240208000153628

调用代码:

在调用之前,我们需要先向合约里面打入ETH作为转账的金额。

其次,这里有两个参数,分别对应的是账号数组和金额数组,格式如下:

[“0xaaa”,”0xbbb”]

[“1”,”2”]

注意,金额的单位是wei,1ETH=10^18wei。

请注意最大GasLimit的限制,如果发送的账号过多导致失败,请减少账号。

image-20240208000656942

由于时间关系,我已经提前给合约打入了一个代币。

并且给100个账号,每个账号都发送0.01个测试币。

我们运行测试,测试成功!

image-20240208001047489

既然在mumbai测试网上可以运行,那么在其他的EVM测试网上也可以运行。

所以,我把他部署到了blast测试网上面,他一样可以运行。

优化代码:

次日,也是我写文章这天,我想优化下代码。

因为我觉得,如果给所有的账号发送相同数量的代币,就没有必要使用数组来浪费资源。

我向GPT询问,结果和我想的一样,所以我在新代码中去掉了数组,直接使用一个数组就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 批量转账函数
function batchTransfer(address[] calldata recipients, uint256 amount) external onlyOwner {
require(amount > 0, "Amount must be greater than zero");
require(recipients.length > 0, "Recipient list is empty");

for (uint256 i = 0; i < recipients.length; i++) {
address recipient = recipients[i];

// 使用 transfer 来进行转账,并处理失败情况
if (!payable(recipient).send(amount)) {
// 处理转账失败的情况,可以选择抛出异常或者记录日志
// 注意:在处理失败时,确保逻辑不会导致整个循环中止
}
}
}

效果是明显的,我还是向上面的100个地址发送交易。

交易的手续费从0.006降到了0.002,这是一个正确的改良。