22pragma solidity ^ 0.8.0 ;
33
44import {ICollector} from './ICollector.sol ' ;
5+ import {IAccessControl} from '../dependencies/openzeppelin/contracts/IAccessControl.sol ' ;
56import {ReentrancyGuard} from '../dependencies/openzeppelin/ReentrancyGuard.sol ' ;
67import {VersionedInitializable} from '../misc/aave-upgradeability/VersionedInitializable.sol ' ;
78import {IERC20 } from '../dependencies/openzeppelin/contracts/IERC20.sol ' ;
@@ -28,14 +29,23 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
2829 /*** Storage Properties ***/
2930
3031 /**
31- * @notice Address of the current funds admin .
32+ * @notice Current revision of the contract .
3233 */
33- address internal _fundsAdmin;
34+ uint256 public constant REVISION = 6 ;
35+
36+ /// @inheritdoc ICollector
37+ address public constant ETH_MOCK_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ;
38+
39+ /// @inheritdoc ICollector
40+ bytes32 public constant FUNDS_ADMIN_ROLE = 'FUNDS_ADMIN ' ;
41+
42+ /// @inheritdoc ICollector
43+ address public immutable ACL_MANAGER;
3444
3545 /**
36- * @notice Current revision of the contract .
46+ * @notice [DEPRECATED] Use `isFundsAdmin()` to check address .
3747 */
38- uint256 public constant REVISION = 5 ;
48+ address internal _fundsAdmin_deprecated ;
3949
4050 /**
4151 * @notice Counter for new stream ids.
@@ -47,16 +57,15 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
4757 */
4858 mapping (uint256 => Stream) private _streams;
4959
50- /// @inheritdoc ICollector
51- address public constant ETH_MOCK_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ;
52-
5360 /*** Modifiers ***/
5461
5562 /**
56- * @dev Throws if the caller is not the funds admin.
63+ * @dev Throws if the caller does not have the FUNDS_ADMIN role
5764 */
5865 modifier onlyFundsAdmin () {
59- require (msg .sender == _fundsAdmin, 'ONLY_BY_FUNDS_ADMIN ' );
66+ if (_onlyFundsAdmin () == false ) {
67+ revert OnlyFundsAdmin ();
68+ }
6069 _;
6170 }
6271
@@ -65,30 +74,32 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
6574 * @param streamId The id of the stream to query.
6675 */
6776 modifier onlyAdminOrRecipient (uint256 streamId ) {
68- require (
69- msg .sender == _fundsAdmin || msg .sender == _streams[streamId].recipient,
70- 'caller is not the funds admin or the recipient of the stream '
71- );
77+ if (_onlyFundsAdmin () == false && msg .sender != _streams[streamId].recipient) {
78+ revert OnlyFundsAdminOrRceipient ();
79+ }
7280 _;
7381 }
7482
7583 /**
7684 * @dev Throws if the provided id does not point to a valid stream.
7785 */
7886 modifier streamExists (uint256 streamId ) {
79- require ( _streams[streamId].isEntity, ' stream does not exist ' );
87+ if ( ! _streams[streamId].isEntity) revert StreamDoesNotExist ( );
8088 _;
8189 }
8290
91+ constructor (address aclManager ) {
92+ if (aclManager == address (0 )) revert InvalidZeroAddress ();
93+ ACL_MANAGER = aclManager;
94+ }
95+
8396 /*** Contract Logic Starts Here */
8497
8598 /// @inheritdoc ICollector
86- function initialize (address fundsAdmin , uint256 nextStreamId ) external initializer {
99+ function initialize (uint256 nextStreamId ) external virtual initializer {
87100 if (nextStreamId != 0 ) {
88101 _nextStreamId = nextStreamId;
89102 }
90-
91- _setFundsAdmin (fundsAdmin);
92103 }
93104
94105 /*** View Functions ***/
@@ -99,8 +110,8 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
99110 }
100111
101112 /// @inheritdoc ICollector
102- function getFundsAdmin ( ) external view returns (address ) {
103- return _fundsAdmin ;
113+ function isFundsAdmin ( address admin ) external view returns (bool ) {
114+ return IAccessControl (ACL_MANAGER). hasRole (FUNDS_ADMIN_ROLE, admin) ;
104115 }
105116
106117 /// @inheritdoc ICollector
@@ -195,7 +206,7 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
195206
196207 /// @inheritdoc ICollector
197208 function transfer (IERC20 token , address recipient , uint256 amount ) external onlyFundsAdmin {
198- require (recipient != address (0 ), ' INVALID_0X_RECIPIENT ' );
209+ if (recipient == address (0 )) revert InvalidZeroAddress ( );
199210
200211 if (address (token) == ETH_MOCK_ADDRESS) {
201212 payable (recipient).sendValue (amount);
@@ -204,18 +215,8 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
204215 }
205216 }
206217
207- /// @inheritdoc ICollector
208- function setFundsAdmin (address admin ) external onlyFundsAdmin {
209- _setFundsAdmin (admin);
210- }
211-
212- /**
213- * @dev Transfer the ownership of the funds administrator role.
214- * @param admin The address of the new funds administrator
215- */
216- function _setFundsAdmin (address admin ) internal {
217- _fundsAdmin = admin;
218- emit NewFundsAdmin (admin);
218+ function _onlyFundsAdmin () internal view returns (bool ) {
219+ return IAccessControl (ACL_MANAGER).hasRole (FUNDS_ADMIN_ROLE, msg .sender );
219220 }
220221
221222 struct CreateStreamLocalVars {
@@ -244,21 +245,21 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
244245 uint256 startTime ,
245246 uint256 stopTime
246247 ) external onlyFundsAdmin returns (uint256 ) {
247- require (recipient != address (0 ), ' stream to the zero address ' );
248- require (recipient != address (this ), ' stream to the contract itself ' );
249- require (recipient != msg .sender , ' stream to the caller ' );
250- require (deposit > 0 , ' deposit is zero ' );
251- require (startTime >= block .timestamp , ' start time before block.timestamp ' );
252- require (stopTime > startTime, ' stop time before the start time ' );
248+ if (recipient == address (0 )) revert InvalidZeroAddress ( );
249+ if (recipient == address (this )) revert InvalidRecipient ( );
250+ if (recipient == msg .sender ) revert InvalidRecipient ( );
251+ if (deposit == 0 ) revert InvalidZeroAmount ( );
252+ if (startTime < block .timestamp ) revert InvalidStartTime ( );
253+ if (stopTime <= startTime) revert InvalidStopTime ( );
253254
254255 CreateStreamLocalVars memory vars;
255256 vars.duration = stopTime - startTime;
256257
257258 /* Without this, the rate per second would be zero. */
258- require (deposit >= vars.duration, ' deposit smaller than time delta ' );
259+ if (deposit < vars.duration) revert DepositSmallerTimeDelta ( );
259260
260261 /* This condition avoids dealing with remainders */
261- require (deposit % vars.duration == 0 , ' deposit not multiple of time delta ' );
262+ if (deposit % vars.duration > 0 ) revert DepositNotMultipleTimeDelta ( );
262263
263264 vars.ratePerSecond = deposit / vars.duration;
264265
@@ -302,11 +303,11 @@ contract Collector is VersionedInitializable, ICollector, ReentrancyGuard {
302303 uint256 streamId ,
303304 uint256 amount
304305 ) external nonReentrant streamExists (streamId) onlyAdminOrRecipient (streamId) returns (bool ) {
305- require (amount > 0 , ' amount is zero ' );
306+ if (amount == 0 ) revert InvalidZeroAmount ( );
306307 Stream memory stream = _streams[streamId];
307308
308309 uint256 balance = balanceOf (streamId, stream.recipient);
309- require (balance >= amount, ' amount exceeds the available balance ' );
310+ if (balance < amount) revert BalanceExceeded ( );
310311
311312 _streams[streamId].remainingBalance = stream.remainingBalance - amount;
312313
0 commit comments