Skip to content

Commit 2d42f8c

Browse files
build: add donate many multiple tokens function
1 parent ff42422 commit 2d42f8c

File tree

1 file changed

+62
-22
lines changed

1 file changed

+62
-22
lines changed

src/contracts/DonationHandler.sol

+62-22
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
pragma solidity ^0.8.0;
33

44
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
5-
65
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
76
import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
87
import '@openzeppelin/contracts/interfaces/IERC20.sol';
@@ -67,13 +66,12 @@ contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable {
6766
/// @param tokenAddress The address of the token being donated
6867
/// @param requiredAmount The required amount of the allowance
6968
/// @param owner The owner of the token
70-
modifier checkERC20Allowance(address tokenAddress, uint256 requiredAmount, address owner) {
69+
function _checkERC20Allowance(address tokenAddress, uint256 requiredAmount, address owner) internal view {
7170
require(tokenAddress != ETH_TOKEN_ADDRESS, 'Invalid token address');
7271
uint256 allowance = IERC20(tokenAddress).allowance(owner, address(this));
7372
if (allowance < requiredAmount) {
7473
revert InsufficientAllowance();
7574
}
76-
_;
7775
}
7876
// ETH Donations
7977
// Donate multiple ETH donations at once
@@ -112,6 +110,22 @@ contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable {
112110
_handleETH(amount, recipientAddress, data);
113111
}
114112

113+
// Donate a single ERC20 donation
114+
/// @notice Donate a single ERC20 donation
115+
/// @param tokenAddress The address of the token being donated
116+
/// @param recipientAddress The address of the recipient of the donation
117+
/// @param amount The amount of the donation
118+
/// @param data The data of the donation
119+
function donateERC20(
120+
address tokenAddress,
121+
address recipientAddress,
122+
uint256 amount,
123+
bytes calldata data
124+
) external nonReentrant {
125+
_checkERC20Allowance(tokenAddress, amount, msg.sender);
126+
_handleERC20(tokenAddress, amount, recipientAddress, data);
127+
}
128+
115129
// ERC20 Donations
116130
// Donate multiple ERC20 donations at once
117131
/// @notice Donate multiple ERC20 donations at once
@@ -126,12 +140,8 @@ contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable {
126140
address[] calldata recipientAddresses,
127141
uint256[] calldata amounts,
128142
bytes[] calldata data
129-
)
130-
external
131-
nonReentrant
132-
validateInputLengths(recipientAddresses, amounts, data)
133-
checkERC20Allowance(tokenAddress, totalAmount, msg.sender)
134-
{
143+
) external nonReentrant validateInputLengths(recipientAddresses, amounts, data) {
144+
_checkERC20Allowance(tokenAddress, totalAmount, msg.sender);
135145
Allocations memory allocations = Allocations(tokenAddress, totalAmount, recipientAddresses, amounts, data);
136146
require(allocations.tokenAddress != ETH_TOKEN_ADDRESS, 'Invalid token address');
137147

@@ -145,20 +155,50 @@ contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable {
145155
}
146156
}
147157
}
158+
// Donate multiple ERC20 & ETH donations at once
159+
/// @notice Donate multiple ERC20 & ETH donations at once
160+
/// @param tokenAddresses The addresses of the tokens being donated
161+
/// @param amounts The amounts of the donation to each recipient
162+
/// @param recipientAddresses The addresses of the recipients of the donation
163+
/// @param data The data of the donation to each recipient
148164

149-
// Donate a single ERC20 donation
150-
/// @notice Donate a single ERC20 donation
151-
/// @param tokenAddress The address of the token being donated
152-
/// @param recipientAddress The address of the recipient of the donation
153-
/// @param amount The amount of the donation
154-
/// @param data The data of the donation
155-
function donateERC20(
156-
address tokenAddress,
157-
address recipientAddress,
158-
uint256 amount,
159-
bytes calldata data
160-
) external nonReentrant checkERC20Allowance(tokenAddress, amount, msg.sender) {
161-
_handleERC20(tokenAddress, amount, recipientAddress, data);
165+
function donateManyMultipleTokens(
166+
address[] calldata tokenAddresses,
167+
uint256[] calldata amounts,
168+
address[] calldata recipientAddresses,
169+
bytes[] calldata data
170+
) external payable nonReentrant validateInputLengths(recipientAddresses, amounts, data) {
171+
uint256 len = recipientAddresses.length;
172+
if (len != tokenAddresses.length) revert InvalidInput();
173+
uint256 totalETHNeeded = 0;
174+
175+
for (uint256 i = 0; i < len;) {
176+
if (tokenAddresses[i] == ETH_TOKEN_ADDRESS) {
177+
totalETHNeeded += amounts[i];
178+
}
179+
unchecked {
180+
++i;
181+
}
182+
}
183+
184+
require(msg.value == totalETHNeeded, 'Incorrect ETH amount sent');
185+
186+
for (uint256 i = 0; i < len;) {
187+
address token = tokenAddresses[i];
188+
uint256 amount = amounts[i];
189+
address recipient = recipientAddresses[i];
190+
bytes memory donationData = data[i];
191+
192+
if (token == ETH_TOKEN_ADDRESS) {
193+
_handleETH(amount, recipient, donationData);
194+
} else {
195+
_checkERC20Allowance(token, amount, msg.sender);
196+
_handleERC20(token, amount, recipient, donationData);
197+
}
198+
unchecked {
199+
++i;
200+
}
201+
}
162202
}
163203

164204
// Internal functions

0 commit comments

Comments
 (0)