如果說能夠拿免費的你一定會拿對吧?敝圈有一個有趣的營銷模式就是,空投 所謂空投就是一個網站或者應用程式,可以免費獲得代幣,然後因為項目或應用程式做得好這代幣有價值,而你就可以免費賣錢了(沒成本對吧~)
大家有剛剛的概念 (水龍頭,ERC20) 那空投的概念就會很好懂通常是這樣
- 會有空投的白名單
- 會有空投的數量
這樣就可以預想這個 function 了
/// 向多个地址转账ETH
function multiTransferETH(
address payable[] calldata _addresses,
uint256[] calldata _amounts
) public payable {
// 检查:_addresses和_amounts数组的长度相等
require(_addresses.length == _amounts.length, "Lengths of Addresses and Amounts NOT EQUAL");
uint _amountSum = getSum(_amounts); // 计算空投ETH总量
// 检查转入ETH等于空投总量
require(msg.value == _amountSum, "Transfer amount error");
// for循环,利用transfer函数发送ETH
for (uint256 i = 0; i < _addresses.length; i++) {
// 注释代码有Dos攻击风险, 并且transfer 也是不推荐写法
// Dos攻击 具体参考 https://github.com/AmazingAng/WTF-Solidity/blob/main/S09_DoS/readme.md
// _addresses[i].transfer(_amounts[i]);
(bool success, ) = _addresses[i].call{value: _amounts[i]}("");
if (!success) {
failTransferList[_addresses[i]] = _amounts[i];
}
}
}
但實際上如果要做空投也不可能是在 ERC20 這個合約裡面直接執行(也行拉,但是不推薦)我們會有一個空投的合約然後,將 mint
的代幣轉到這個合約裡面再做空投的動作。所以我們必須要有控制權限,看一下完整的程式
// SPDX-License-Identifier: MIT
// By 0xAA
pragma solidity ^0.8.21;
import "./IERC20.sol"; //import IERC20
/// @notice 向多个地址转账ERC20代币
contract Airdrop {
mapping(address => uint) failTransferList;
/// @notice 向多个地址转账ERC20代币,使用前需要先授权
///
/// @param _token 转账的ERC20代币地址
/// @param _addresses 空投地址数组
/// @param _amounts 代币数量数组(每个地址的空投数量)
function multiTransferToken(
address _token,
address[] calldata _addresses,
uint256[] calldata _amounts
) external {
// 检查:_addresses和_amounts数组的长度相等
require(
_addresses.length == _amounts.length,
"Lengths of Addresses and Amounts NOT EQUAL"
);
IERC20 token = IERC20(_token); // 声明IERC合约变量
uint _amountSum = getSum(_amounts); // 计算空投代币总量
// 检查:授权代币数量 > 空投代币总量
require(
token.allowance(msg.sender, address(this)) > _amountSum,
"Need Approve ERC20 token"
);
// for循环,利用transferFrom函数发送空投
for (uint256 i; i < _addresses.length; i++) {
token.transferFrom(msg.sender, _addresses[i], _amounts[i]);
}
}
/// 向多个地址转账ETH
function multiTransferETH(
address payable[] calldata _addresses,
uint256[] calldata _amounts
) public payable {
// 检查:_addresses和_amounts数组的长度相等
require(
_addresses.length == _amounts.length,
"Lengths of Addresses and Amounts NOT EQUAL"
);
uint _amountSum = getSum(_amounts); // 计算空投ETH总量
// 检查转入ETH等于空投总量
require(msg.value == _amountSum, "Transfer amount error");
// for循环,利用transfer函数发送ETH
for (uint256 i = 0; i < _addresses.length; i++) {
// 注释代码有Dos攻击风险, 并且transfer 也是不推荐写法
// Dos攻击 具体参考 https://github.com/AmazingAng/WTF-Solidity/blob/main/S09_DoS/readme.md
// _addresses[i].transfer(_amounts[i]);
(bool success, ) = _addresses[i].call{value: _amounts[i]}("");
if (!success) {
failTransferList[_addresses[i]] = _amounts[i];
}
}
}
// 给空投失败提供主动操作机会
function withdrawFromFailList(address _to) public {
uint failAmount = failTransferList[msg.sender];
require(failAmount > 0, "You are not in failed list");
failTransferList[msg.sender] = 0;
(bool success, ) = _to.call{value: failAmount}("");
require(success, "Fail withdraw");
}
// 数组求和函数
function getSum(uint256[] calldata _arr) public pure returns (uint sum) {
for (uint i = 0; i < _arr.length; i++) sum = sum + _arr[i];
}
}
總之我們如果丟參數的話就要變成
// _addresses填写
["0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"]
// _amounts填写
[100, 200]
但切記一件事情這樣看起來合理但是每個動作都有改到鏈上的訊息,所以這樣的空投是有成本的,所以要謹慎使用。(項目方)