forked from AmazingAng/WTF-Solidity
-
Notifications
You must be signed in to change notification settings - Fork 124
/
Airdrop.sol
145 lines (127 loc) · 4.9 KB
/
Airdrop.sol
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 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];
}
}
// ERC20代币合约
contract ERC20 is IERC20 {
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
uint256 public override totalSupply; // 代币总供给
string public name; // 名称
string public symbol; // 符号
uint8 public decimals = 18; // 小数位数
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
}
// @dev 实现`transfer`函数,代币转账逻辑
function transfer(
address recipient,
uint amount
) public override returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}
// @dev 实现 `approve` 函数, 代币授权逻辑
function approve(
address spender,
uint amount
) public override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
// @dev 实现`transferFrom`函数,代币授权转账逻辑
function transferFrom(
address sender,
address recipient,
uint amount
) public override returns (bool) {
allowance[sender][msg.sender] -= amount;
balanceOf[sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}
// @dev 铸造代币,从 `0` 地址转账给 调用者地址
function mint(uint amount) external {
balanceOf[msg.sender] += amount;
totalSupply += amount;
emit Transfer(address(0), msg.sender, amount);
}
// @dev 销毁代币,从 调用者地址 转账给 `0` 地址
function burn(uint amount) external {
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
emit Transfer(msg.sender, address(0), amount);
}
}