@@ -3,6 +3,7 @@ pragma solidity ^0.8.27;
33
44import { EIP712Upgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol " ;
55import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol " ;
6+ import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol " ;
67import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol " ;
78import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol " ;
89import { Math } from "@openzeppelin/contracts/utils/math/Math.sol " ;
@@ -36,7 +37,14 @@ import { PPMMath } from "../../libraries/PPMMath.sol";
3637 * @custom:security-contact Please email security+contracts@thegraph.com if you find any
3738 * bugs. We may have an active bug bounty program.
3839 */
39- contract RecurringCollector is Initializable , EIP712Upgradeable , GraphDirectory , Authorizable , IRecurringCollector {
40+ contract RecurringCollector is
41+ Initializable ,
42+ EIP712Upgradeable ,
43+ GraphDirectory ,
44+ Authorizable ,
45+ PausableUpgradeable ,
46+ IRecurringCollector
47+ {
4048 using PPMMath for uint256 ;
4149
4250 /// @notice The minimum number of seconds that must be between two collections
@@ -94,9 +102,29 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
94102 }
95103
96104 /**
97- * @notice Constructs a new instance of the RecurringCollector contract.
98- * @param eip712Name The name of the EIP712 domain.
99- * @param eip712Version The version of the EIP712 domain.
105+ * @notice List of pause guardians and their allowed status
106+ * @param pauseGuardian The address to check
107+ * @return Whether the address is a pause guardian
108+ */
109+ function pauseGuardians (address pauseGuardian ) public view override returns (bool ) {
110+ return _getStorage ().pauseGuardians[pauseGuardian];
111+ }
112+
113+ /**
114+ * @notice Checks if the caller is a pause guardian.
115+ */
116+ modifier onlyPauseGuardian () {
117+ _checkPauseGuardian ();
118+ _;
119+ }
120+
121+ function _checkPauseGuardian () internal view {
122+ require (_getStorage ().pauseGuardians[msg .sender ], RecurringCollectorNotPauseGuardian (msg .sender ));
123+ }
124+
125+ /**
126+ * @notice Constructs a new instance of the RecurringCollector implementation contract.
127+ * @dev Immutables are set here; proxy state is initialized via {initialize}.
100128 * @param controller The address of the Graph controller.
101129 * @param revokeSignerThawingPeriod The duration (in seconds) in which a signer is thawing before they can be revoked.
102130 */
@@ -115,16 +143,47 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
115143 */
116144 function initialize (string memory eip712Name , string memory eip712Version ) external initializer {
117145 __EIP712_init (eip712Name, eip712Version);
146+ __Pausable_init ();
118147 }
119148 /* solhint-enable gas-calldata-parameters */
120149
150+ /// @inheritdoc IRecurringCollector
151+ function pause () external override onlyPauseGuardian {
152+ _pause ();
153+ }
154+
155+ /// @inheritdoc IRecurringCollector
156+ function unpause () external override onlyPauseGuardian {
157+ _unpause ();
158+ }
159+
160+ /**
161+ * @notice Sets a pause guardian.
162+ * @dev Only callable by the governor.
163+ * @param _pauseGuardian The address of the pause guardian
164+ * @param _allowed Whether the address should be a pause guardian
165+ */
166+ function setPauseGuardian (address _pauseGuardian , bool _allowed ) external {
167+ require (msg .sender == _graphController ().getGovernor (), RecurringCollectorNotGovernor (msg .sender ));
168+ RecurringCollectorStorage storage $ = _getStorage ();
169+ require (
170+ $.pauseGuardians[_pauseGuardian] != _allowed,
171+ RecurringCollectorPauseGuardianNoChange (_pauseGuardian, _allowed)
172+ );
173+ $.pauseGuardians[_pauseGuardian] = _allowed;
174+ emit PauseGuardianSet (_pauseGuardian, _allowed);
175+ }
176+
121177 /**
122178 * @inheritdoc IPaymentsCollector
123179 * @notice Initiate a payment collection through the payments protocol.
124180 * See {IPaymentsCollector.collect}.
125181 * @dev Caller must be the data service the RCA was issued to.
126182 */
127- function collect (IGraphPayments.PaymentTypes paymentType , bytes calldata data ) external returns (uint256 ) {
183+ function collect (
184+ IGraphPayments.PaymentTypes paymentType ,
185+ bytes calldata data
186+ ) external whenNotPaused returns (uint256 ) {
128187 try this .decodeCollectData (data) returns (CollectParams memory collectParams ) {
129188 return _collect (paymentType, collectParams);
130189 } catch {
@@ -137,7 +196,10 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
137196 * @notice Accept a Recurring Collection Agreement.
138197 * @dev Caller must be the data service the RCA was issued to.
139198 */
140- function accept (RecurringCollectionAgreement calldata rca , bytes calldata signature ) external returns (bytes16 ) {
199+ function accept (
200+ RecurringCollectionAgreement calldata rca ,
201+ bytes calldata signature
202+ ) external whenNotPaused returns (bytes16 ) {
141203 /* solhint-disable gas-strict-inequalities */
142204 require (
143205 rca.deadline >= block .timestamp ,
@@ -230,7 +292,7 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
230292 * See {IRecurringCollector.cancel}.
231293 * @dev Caller must be the data service for the agreement.
232294 */
233- function cancel (bytes16 agreementId , CancelAgreementBy by ) external {
295+ function cancel (bytes16 agreementId , CancelAgreementBy by ) external whenNotPaused {
234296 AgreementData storage agreement = _getAgreementStorage (agreementId);
235297 require (
236298 agreement.state == AgreementState.Accepted,
@@ -264,7 +326,7 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
264326 * @dev Note: Updated pricing terms apply immediately and will affect the next collection
265327 * for the entire period since lastCollectionAt.
266328 */
267- function update (RecurringCollectionAgreementUpdate calldata rcau , bytes calldata signature ) external {
329+ function update (RecurringCollectionAgreementUpdate calldata rcau , bytes calldata signature ) external whenNotPaused {
268330 AgreementData storage agreement = _requireValidUpdateTarget (rcau.agreementId);
269331
270332 /* solhint-disable gas-strict-inequalities */
@@ -343,7 +405,7 @@ contract RecurringCollector is Initializable, EIP712Upgradeable, GraphDirectory,
343405 uint8 offerType ,
344406 bytes calldata data ,
345407 uint16 /* options */
346- ) external returns (AgreementDetails memory details ) {
408+ ) external whenNotPaused returns (AgreementDetails memory details ) {
347409 if (offerType == OFFER_TYPE_NEW) details = _offerNew (data);
348410 else if (offerType == OFFER_TYPE_UPDATE) details = _offerUpdate (data);
349411 else revert RecurringCollectorInvalidCollectData (data);
0 commit comments