@@ -3,6 +3,7 @@ pragma solidity ^0.8.4;
3
3
4
4
import './interfaces/IERC20ConversionProxy.sol ' ;
5
5
import './interfaces/IEthConversionProxy.sol ' ;
6
+ import './ChainlinkConversionPath.sol ' ;
6
7
import './BatchNoConversionPayments.sol ' ;
7
8
8
9
/**
@@ -24,9 +25,13 @@ contract BatchConversionPayments is BatchNoConversionPayments {
24
25
25
26
IERC20ConversionProxy public paymentErc20ConversionProxy;
26
27
IEthConversionProxy public paymentEthConversionProxy;
28
+ ChainlinkConversionPath public chainlinkConversionPath;
27
29
28
30
uint256 public batchConversionFee;
29
31
32
+ uint256 public batchFeeAmountUSDLimit; // maybe not necessary
33
+ address public USDAddress;
34
+
30
35
/**
31
36
* @dev All the information of a request, except the feeAddress
32
37
* _recipient Recipient address of the payment
@@ -57,6 +62,7 @@ contract BatchConversionPayments is BatchNoConversionPayments {
57
62
uint256 [] amounts;
58
63
bytes [] paymentReferences;
59
64
uint256 [] feeAmounts;
65
+ //address[][] pathsToUSD; // TODO is there another solution ?
60
66
}
61
67
62
68
/**
@@ -76,17 +82,20 @@ contract BatchConversionPayments is BatchNoConversionPayments {
76
82
* @param _paymentEthProxy The ETH payment proxy address to use.
77
83
* @param _paymentErc20ConversionProxy The ERC20 Conversion payment proxy address to use.
78
84
* @param _paymentEthConversionFeeProxy The ETH Conversion payment proxy address to use.
85
+ * @param _chainlinkConversionPathAddress The address of the conversion path contract
79
86
* @param _owner Owner of the contract.
80
87
*/
81
88
constructor (
82
89
address _paymentErc20Proxy ,
83
90
address _paymentEthProxy ,
84
91
address _paymentErc20ConversionProxy ,
85
92
address _paymentEthConversionFeeProxy ,
93
+ address _chainlinkConversionPathAddress ,
86
94
address _owner
87
95
) BatchNoConversionPayments (_paymentErc20Proxy, _paymentEthProxy, _owner) {
88
96
paymentErc20ConversionProxy = IERC20ConversionProxy (_paymentErc20ConversionProxy);
89
97
paymentEthConversionProxy = IEthConversionProxy (_paymentEthConversionFeeProxy);
98
+ chainlinkConversionPath = ChainlinkConversionPath (_chainlinkConversionPathAddress);
90
99
batchConversionFee = 0 ;
91
100
}
92
101
@@ -99,16 +108,29 @@ contract BatchConversionPayments is BatchNoConversionPayments {
99
108
* - batchEthPayments, paymentNetworkId=3
100
109
* - batchEthConversionPayments, paymentNetworkId=4
101
110
* If metaDetails use paymentNetworkId = 4, it must be at the end of the list, or the transaction can be reverted
111
+ * @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees, caution,
112
+ Caution, the calculation of batchFeeAmountUSD which allows to limit the batch fees takes only
113
+ into consideration these paths. Without paths, there is not limitation.
102
114
* @param _feeAddress The address where fees should be paid
103
115
* @dev batchRouter only reduces gas consumption when using more than a single payment network.
104
116
* For single payment network payments, it is more efficient to use the suited batch function.
105
117
*/
106
- function batchRouter (MetaDetail[] calldata metaDetails , address _feeAddress ) external payable {
118
+ function batchRouter (
119
+ MetaDetail[] calldata metaDetails ,
120
+ address [][] calldata pathsToUSD ,
121
+ address _feeAddress
122
+ ) external payable {
107
123
require (metaDetails.length < 6 , 'more than 5 metaDetails ' );
124
+ uint256 batchFeeAmountUSD = 0 ;
108
125
for (uint256 i = 0 ; i < metaDetails.length ; i++ ) {
109
126
MetaDetail calldata metaConversionDetail = metaDetails[i];
110
127
if (metaConversionDetail.paymentNetworkId == 0 ) {
111
- batchMultiERC20ConversionPayments (metaConversionDetail.conversionDetails, _feeAddress);
128
+ batchFeeAmountUSD = batchMultiERC20ConversionPayments (
129
+ metaConversionDetail.conversionDetails,
130
+ batchFeeAmountUSD,
131
+ pathsToUSD,
132
+ _feeAddress
133
+ );
112
134
} else if (metaConversionDetail.paymentNetworkId == 1 ) {
113
135
batchERC20Payments (
114
136
metaConversionDetail.cryptoDetails.tokenAddresses[0 ],
@@ -154,12 +176,15 @@ contract BatchConversionPayments is BatchNoConversionPayments {
154
176
* @notice Send a batch of ERC20 payments with amounts based on a request
155
177
* currency (e.g. fiat), with fees and paymentReferences to multiple accounts, with multiple tokens.
156
178
* @param conversionDetails list of requestInfo, each one containing all the information of a request
179
+ * @param pathsToUSD The list of paths into USD for every token
157
180
* @param _feeAddress The fee recipient
158
181
*/
159
182
function batchMultiERC20ConversionPayments (
160
183
ConversionDetail[] calldata conversionDetails ,
184
+ uint256 batchFeeAmountUSD ,
185
+ address [][] calldata pathsToUSD ,
161
186
address _feeAddress
162
- ) public {
187
+ ) public returns ( uint256 ) {
163
188
// a list of unique tokens, with the sum of maxToSpend by token
164
189
Token[] memory uTokens = new Token [](conversionDetails.length );
165
190
for (uint256 i = 0 ; i < conversionDetails.length ; i++ ) {
@@ -237,16 +262,23 @@ contract BatchConversionPayments is BatchNoConversionPayments {
237
262
requestedToken.safeTransfer (msg .sender , excessAmount);
238
263
}
239
264
265
+ uint256 batchFeeToPay = ((uTokens[k].amountAndFee - excessAmount) * batchConversionFee) /
266
+ tenThousand;
267
+
268
+ (batchFeeToPay, batchFeeAmountUSD) = calculateBatchFeeToPay (
269
+ batchFeeToPay,
270
+ uTokens[k].tokenAddress,
271
+ batchFeeAmountUSD,
272
+ pathsToUSD
273
+ );
274
+
240
275
// Payer pays the exact batch fees amount
241
276
require (
242
- safeTransferFrom (
243
- uTokens[k].tokenAddress,
244
- _feeAddress,
245
- ((uTokens[k].amountAndFee - excessAmount) * batchConversionFee) / tenThousand
246
- ),
277
+ safeTransferFrom (uTokens[k].tokenAddress, _feeAddress, batchFeeToPay),
247
278
'batch fee transferFrom() failed '
248
279
);
249
280
}
281
+ return batchFeeAmountUSD;
250
282
}
251
283
252
284
/**
@@ -295,6 +327,34 @@ contract BatchConversionPayments is BatchNoConversionPayments {
295
327
payerAuthorized = false ;
296
328
}
297
329
330
+ function calculateBatchFeeToPay (
331
+ uint256 batchFeeToPay ,
332
+ address tokenAddress ,
333
+ uint256 batchFeeAmountUSD ,
334
+ address [][] calldata pathsToUSD
335
+ ) internal view returns (uint256 , uint256 ) {
336
+ if (pathsToUSD.length > 0 ) {
337
+ for (uint256 i = 0 ; i < pathsToUSD.length ; i++ ) {
338
+ if (
339
+ pathsToUSD[i][0 ] == tokenAddress && pathsToUSD[i][pathsToUSD[i].length - 1 ] == USDAddress
340
+ ) {
341
+ uint256 conversionUSD = 0 ;
342
+ (conversionUSD, ) = chainlinkConversionPath.getConversion (batchFeeToPay, pathsToUSD[i]);
343
+ // calculate the batch fee to pay, taking care of the batchFeeAmountUSDLimit
344
+ uint256 conversionToPayUSD = conversionUSD;
345
+ if (batchFeeAmountUSD + conversionToPayUSD > batchFeeAmountUSDLimit) {
346
+ conversionToPayUSD = batchFeeAmountUSDLimit - batchFeeAmountUSD;
347
+ batchFeeToPay = (batchFeeToPay * conversionToPayUSD) / conversionUSD;
348
+ }
349
+ batchFeeAmountUSD += conversionToPayUSD;
350
+ // add only once the fees
351
+ break ;
352
+ }
353
+ }
354
+ }
355
+ return (batchFeeToPay, batchFeeAmountUSD);
356
+ }
357
+
298
358
/*
299
359
* Admin functions to edit the conversion proxies address and fees
300
360
*/
@@ -322,4 +382,20 @@ contract BatchConversionPayments is BatchNoConversionPayments {
322
382
function setPaymentEthConversionProxy (address _paymentEthConversionProxy ) external onlyOwner {
323
383
paymentEthConversionProxy = IEthConversionProxy (_paymentEthConversionProxy);
324
384
}
385
+
386
+ /**
387
+ * @notice Update the conversion path contract used to fetch conversions
388
+ * @param _chainlinkConversionPathAddress address of the conversion path contract
389
+ */
390
+ function setConversionPathAddress (address _chainlinkConversionPathAddress ) external onlyOwner {
391
+ chainlinkConversionPath = ChainlinkConversionPath (_chainlinkConversionPathAddress);
392
+ }
393
+
394
+ function setUSDAddress (address _USDAddress ) external onlyOwner {
395
+ USDAddress = _USDAddress;
396
+ }
397
+
398
+ function setBatchFeeAmountUSDLimit (uint256 _batchFeeAmountUSDLimit ) external onlyOwner {
399
+ batchFeeAmountUSDLimit = _batchFeeAmountUSDLimit;
400
+ }
325
401
}
0 commit comments