原因: 我昨天看到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/
编译代码:
部署代码:
调用代码: 在调用之前,我们需要先向合约里面打入ETH作为转账的金额。
其次,这里有两个参数,分别对应的是账号数组和金额数组,格式如下:
[“0xaaa”,”0xbbb”]
[“1”,”2”]
注意,金额的单位是wei,1ETH=10^18wei。
请注意最大GasLimit的限制,如果发送的账号过多导致失败,请减少账号。
由于时间关系,我已经提前给合约打入了一个代币。
并且给100个账号,每个账号都发送0.01个测试币。
我们运行测试,测试成功!
既然在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,这是一个正确的改良。