@@ -13,15 +13,30 @@ import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol";
13
13
14
14
// ========== Features ==========
15
15
import "../extension/Ownable.sol " ;
16
-
17
- contract AirdropERC20 is Initializable , Ownable , ReentrancyGuardUpgradeable , MulticallUpgradeable , IAirdropERC20 {
16
+ import "../extension/PermissionsEnumerable.sol " ;
17
+
18
+ contract AirdropERC20 is
19
+ Initializable ,
20
+ Ownable ,
21
+ PermissionsEnumerable ,
22
+ ReentrancyGuardUpgradeable ,
23
+ MulticallUpgradeable ,
24
+ IAirdropERC20
25
+ {
18
26
/*///////////////////////////////////////////////////////////////
19
27
State variables
20
28
//////////////////////////////////////////////////////////////*/
21
29
22
30
bytes32 private constant MODULE_TYPE = bytes32 ("AirdropERC20 " );
23
31
uint256 private constant VERSION = 1 ;
24
32
33
+ uint256 public payeeCount;
34
+ uint256 public processedCount;
35
+
36
+ uint256 [] private indicesOfFailed;
37
+
38
+ mapping (uint256 => AirdropContent) private airdropContent;
39
+
25
40
/*///////////////////////////////////////////////////////////////
26
41
Constructor + initializer logic
27
42
//////////////////////////////////////////////////////////////*/
@@ -30,6 +45,7 @@ contract AirdropERC20 is Initializable, Ownable, ReentrancyGuardUpgradeable, Mul
30
45
31
46
/// @dev Initiliazes the contract, like a constructor.
32
47
function initialize (address _defaultAdmin ) external initializer {
48
+ _setupRole (DEFAULT_ADMIN_ROLE, _defaultAdmin);
33
49
_setupOwner (_defaultAdmin);
34
50
__ReentrancyGuard_init ();
35
51
}
@@ -52,35 +68,96 @@ contract AirdropERC20 is Initializable, Ownable, ReentrancyGuardUpgradeable, Mul
52
68
Airdrop logic
53
69
//////////////////////////////////////////////////////////////*/
54
70
55
- /**
56
- * @notice Lets contract-owner send ERC20 tokens to a list of addresses.
57
- * @dev The token-owner should approve target tokens to Airdrop contract,
58
- * which acts as operator for the tokens.
59
- *
60
- * @param _tokenAddress Contract address of ERC20 tokens to air-drop.
61
- * @param _tokenOwner Address from which to transfer tokens.
62
- * @param _recipients List of recipient addresses for the air-drop.
63
- * @param _amounts Quantity of tokens to air-drop, per recipient.
64
- */
65
- function airdrop (
66
- address _tokenAddress ,
67
- address _tokenOwner ,
68
- address [] memory _recipients ,
69
- uint256 [] memory _amounts
70
- ) external payable nonReentrant onlyOwner {
71
- uint256 len = _amounts.length ;
72
- require (len == _recipients.length , "length mismatch " );
73
-
74
- if (_tokenAddress == CurrencyTransferLib.NATIVE_TOKEN) {
75
- uint256 totalAmount;
76
- for (uint256 i = 0 ; i < len; i++ ) {
77
- totalAmount += _amounts[i];
71
+ ///@notice Lets contract-owner set up an airdrop of ERC20 or native tokens to a list of addresses.
72
+ function addAirdropRecipients (AirdropContent[] calldata _contents ) external payable onlyRole (DEFAULT_ADMIN_ROLE) {
73
+ uint256 len = _contents.length ;
74
+ require (len > 0 , "No payees provided. " );
75
+
76
+ uint256 currentCount = payeeCount;
77
+ payeeCount += len;
78
+
79
+ uint256 nativeTokenAmount;
80
+
81
+ for (uint256 i = currentCount; i < len; i += 1 ) {
82
+ airdropContent[i] = _contents[i];
83
+
84
+ if (_contents[i].tokenAddress == CurrencyTransferLib.NATIVE_TOKEN) {
85
+ nativeTokenAmount += _contents[i].amount;
78
86
}
79
- require (totalAmount == msg .value , "Incorrect native token amount " );
80
87
}
81
88
82
- for (uint256 i = 0 ; i < len; i++ ) {
83
- CurrencyTransferLib.transferCurrency (_tokenAddress, _tokenOwner, _recipients[i], _amounts[i]);
89
+ require (nativeTokenAmount == msg .value , "Incorrect native token amount " );
90
+
91
+ emit RecipientsAdded (_contents);
92
+ }
93
+
94
+ /// @notice Lets contract-owner send ERC20 or native tokens to a list of addresses.
95
+ function airdrop (uint256 paymentsToProcess ) external nonReentrant {
96
+ uint256 totalPayees = payeeCount;
97
+ uint256 countOfProcessed = processedCount;
98
+
99
+ require (countOfProcessed + paymentsToProcess <= totalPayees, "invalid no. of payments " );
100
+
101
+ processedCount += paymentsToProcess;
102
+
103
+ for (uint256 i = countOfProcessed; i < (countOfProcessed + paymentsToProcess); i += 1 ) {
104
+ AirdropContent memory content = airdropContent[i];
105
+
106
+ CurrencyTransferLib.transferCurrency (
107
+ content.tokenAddress,
108
+ content.tokenOwner,
109
+ content.recipient,
110
+ content.amount
111
+ );
112
+
113
+ emit AirdropPayment (content.recipient, content);
114
+ }
115
+ }
116
+
117
+ /*///////////////////////////////////////////////////////////////
118
+ Airdrop view logic
119
+ //////////////////////////////////////////////////////////////*/
120
+
121
+ /// @notice Returns all airdrop payments set up -- pending, processed or failed.
122
+ function getAllAirdropPayments () external view returns (AirdropContent[] memory contents ) {
123
+ uint256 count = payeeCount;
124
+ contents = new AirdropContent [](count);
125
+
126
+ for (uint256 i = 0 ; i < count; i += 1 ) {
127
+ contents[i] = airdropContent[i];
128
+ }
129
+ }
130
+
131
+ /// @notice Returns all pending airdrop payments.
132
+ function getAllAirdropPaymentsPending () external view returns (AirdropContent[] memory contents ) {
133
+ uint256 endCount = payeeCount;
134
+ uint256 startCount = processedCount;
135
+ contents = new AirdropContent [](endCount - startCount);
136
+
137
+ uint256 idx;
138
+ for (uint256 i = startCount; i < endCount; i += 1 ) {
139
+ contents[idx] = airdropContent[i];
140
+ idx += 1 ;
141
+ }
142
+ }
143
+
144
+ /// @notice Returns all pending airdrop processed.
145
+ function getAllAirdropPaymentsProcessed () external view returns (AirdropContent[] memory contents ) {
146
+ uint256 count = processedCount;
147
+ contents = new AirdropContent [](count);
148
+
149
+ for (uint256 i = 0 ; i < count; i += 1 ) {
150
+ contents[i] = airdropContent[i];
151
+ }
152
+ }
153
+
154
+ /// @notice Returns all pending airdrop failed.
155
+ function getAllAirdropPaymentsFailed () external view returns (AirdropContent[] memory contents ) {
156
+ uint256 count = indicesOfFailed.length ;
157
+ contents = new AirdropContent [](count);
158
+
159
+ for (uint256 i = 0 ; i < count; i += 1 ) {
160
+ contents[i] = airdropContent[indicesOfFailed[i]];
84
161
}
85
162
}
86
163
0 commit comments