@@ -26,35 +26,35 @@ abstract contract Scheduler is IScheduler, SchedulerState {
2626        if  (subscriptionParams.priceIds.length  >  MAX_PRICE_IDS) {
2727            revert  TooManyPriceIds (subscriptionParams.priceIds.length , MAX_PRICE_IDS);
2828        }
29-          
29+ 
3030        // Validate update criteria 
31-         if  (! subscriptionParams.updateCriteria.updateOnHeartbeat &&   
31+         if  (! subscriptionParams.updateCriteria.updateOnHeartbeat && 
3232            ! subscriptionParams.updateCriteria.updateOnDeviation) {
3333            revert  InvalidUpdateCriteria ();
3434        }
35-          
35+ 
3636        // Validate gas config 
37-         if  (subscriptionParams.gasConfig.maxGasPrice ==  0  ||   
37+         if  (subscriptionParams.gasConfig.maxGasPrice ==  0  || 
3838            subscriptionParams.gasConfig.maxGasLimit ==  0 ) {
3939            revert  InvalidGasConfig ();
4040        }
4141
4242        subscriptionId =  _state.subscriptionNumber++ ;
43-          
43+ 
4444        // Store the subscription parameters 
4545        _state.subscriptionParams[subscriptionId] =  subscriptionParams;
46-          
46+ 
4747        // Initialize subscription status 
4848        SubscriptionStatus storage  status =  _state.subscriptionStatuses[subscriptionId];
4949        status.priceLastUpdatedAt =  0 ;
5050        status.balanceInWei =  0 ;
5151        status.totalUpdates =  0 ;
5252        status.totalSpent =  0 ;
5353        status.isActive =  true ;
54-          
54+ 
5555        // Map manager to subscription ID 
5656        _state.managerToSubscriptionId[msg .sender ] =  subscriptionId;
57-          
57+ 
5858        emit  SubscriptionCreated (subscriptionId, msg .sender );
5959        return  subscriptionId;
6060    }
@@ -72,26 +72,26 @@ abstract contract Scheduler is IScheduler, SchedulerState {
7272        if  (! _state.subscriptionStatuses[subscriptionId].isActive) {
7373            revert  InactiveSubscription ();
7474        }
75-          
75+ 
7676        if  (newSubscriptionParams.priceIds.length  >  MAX_PRICE_IDS) {
7777            revert  TooManyPriceIds (newSubscriptionParams.priceIds.length , MAX_PRICE_IDS);
7878        }
79-          
79+ 
8080        // Validate update criteria 
81-         if  (! newSubscriptionParams.updateCriteria.updateOnHeartbeat &&   
81+         if  (! newSubscriptionParams.updateCriteria.updateOnHeartbeat && 
8282            ! newSubscriptionParams.updateCriteria.updateOnDeviation) {
8383            revert  InvalidUpdateCriteria ();
8484        }
85-          
85+ 
8686        // Validate gas config 
87-         if  (newSubscriptionParams.gasConfig.maxGasPrice ==  0  ||   
87+         if  (newSubscriptionParams.gasConfig.maxGasPrice ==  0  || 
8888            newSubscriptionParams.gasConfig.maxGasLimit ==  0 ) {
8989            revert  InvalidGasConfig ();
9090        }
91-          
91+ 
9292        // Update subscription parameters 
9393        _state.subscriptionParams[subscriptionId] =  newSubscriptionParams;
94-          
94+ 
9595        emit  SubscriptionUpdated (subscriptionId);
9696    }
9797
@@ -101,9 +101,9 @@ abstract contract Scheduler is IScheduler, SchedulerState {
101101        if  (! _state.subscriptionStatuses[subscriptionId].isActive) {
102102            revert  InactiveSubscription ();
103103        }
104-          
104+ 
105105        _state.subscriptionStatuses[subscriptionId].isActive =  false ;
106-          
106+ 
107107        emit  SubscriptionDeactivated (subscriptionId);
108108    }
109109
@@ -114,32 +114,32 @@ abstract contract Scheduler is IScheduler, SchedulerState {
114114    ) external  override  onlyPusher {
115115        SubscriptionStatus storage  status =  _state.subscriptionStatuses[subscriptionId];
116116        SubscriptionParams storage  params =  _state.subscriptionParams[subscriptionId];
117-          
117+ 
118118        if  (! status.isActive) {
119119            revert  InactiveSubscription ();
120120        }
121-          
121+ 
122122        // Verify price IDs match subscription 
123123        if  (priceIds.length  !=  params.priceIds.length ) {
124124            revert  InvalidPriceIdsLength (priceIds[0 ], params.priceIds[0 ]);
125125        }
126-          
126+ 
127127        // Keepers must provide priceIds in the exact same order as defined in the subscription 
128128        for  (uint8  i =  0 ; i <  priceIds.length ; i++ ) {
129129            if  (priceIds[i] !=  params.priceIds[i]) {
130130                revert  InvalidPriceId (priceIds[i], params.priceIds[i]);
131131            }
132132        }
133-          
133+ 
134134        // Get the Pyth contract and parse price updates 
135135        IPyth pyth =  IPyth (_state.pyth);
136136        uint256  pythFee =  pyth.getUpdateFee (updateData);
137-          
137+ 
138138        // Check if subscription has enough balance 
139139        if  (status.balanceInWei <  pythFee) {
140140            revert  InsufficientBalance ();
141141        }
142-          
142+ 
143143        // Parse price feed updates with the same timestamp for all feeds 
144144        uint64  publishTime =  SafeCast.toUint64 (block .timestamp );
145145        PythStructs.PriceFeed[] memory  priceFeeds =  pyth.parsePriceFeedUpdates {
@@ -150,26 +150,26 @@ abstract contract Scheduler is IScheduler, SchedulerState {
150150            publishTime,
151151            publishTime
152152        );
153-          
153+ 
154154        // Verify all price feeds have the same timestamp 
155155        uint64  timestamp =  SafeCast.toUint64 (priceFeeds[0 ].price.publishTime);
156156        for  (uint8  i =  1 ; i <  priceFeeds.length ; i++ ) {
157157            if  (SafeCast.toUint64 (priceFeeds[i].price.publishTime) !=  timestamp) {
158158                revert  PriceTimestampMismatch ();
159159            }
160160        }
161-          
161+ 
162162        // Store the price updates in the mapping 
163163        for  (uint8  i =  0 ; i <  priceFeeds.length ; i++ ) {
164164            _state.priceUpdates[subscriptionId][priceIds[i]] =  priceFeeds[i];
165165        }
166-          
166+ 
167167        // Update subscription status 
168168        status.priceLastUpdatedAt =  timestamp;
169169        status.balanceInWei -=  pythFee;
170170        status.totalUpdates +=  1 ;
171171        status.totalSpent +=  pythFee;
172-          
172+ 
173173        emit  PricesUpdated (subscriptionId, timestamp);
174174    }
175175
@@ -180,9 +180,9 @@ abstract contract Scheduler is IScheduler, SchedulerState {
180180        if  (! _state.subscriptionStatuses[subscriptionId].isActive) {
181181            revert  InactiveSubscription ();
182182        }
183-          
183+ 
184184        SubscriptionParams storage  params =  _state.subscriptionParams[subscriptionId];
185-          
185+ 
186186        // If no price IDs provided, return all price feeds for the subscription 
187187        if  (priceIds.length  ==  0 ) {
188188            PythStructs.PriceFeed[] memory  allFeeds =  new  PythStructs.PriceFeed [](params.priceIds.length );
@@ -191,7 +191,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
191191            }
192192            return  allFeeds;
193193        }
194-          
194+ 
195195        // Return only the requested price feeds 
196196        PythStructs.PriceFeed[] memory  requestedFeeds =  new  PythStructs.PriceFeed [](priceIds.length );
197197        for  (uint8  i =  0 ; i <  priceIds.length ; i++ ) {
@@ -203,14 +203,14 @@ abstract contract Scheduler is IScheduler, SchedulerState {
203203                    break ;
204204                }
205205            }
206-              
206+ 
207207            if  (! validPriceId) {
208208                revert  InvalidPriceId (priceIds[i], params.priceIds[0 ]);
209209            }
210-              
210+ 
211211            requestedFeeds[i] =  _state.priceUpdates[subscriptionId][priceIds[i]];
212212        }
213-          
213+ 
214214        return  requestedFeeds;
215215    }
216216
@@ -220,7 +220,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
220220        if  (! _state.subscriptionStatuses[subscriptionId].isActive) {
221221            revert  InactiveSubscription ();
222222        }
223-          
223+ 
224224        _state.subscriptionStatuses[subscriptionId].balanceInWei +=  msg .value ;
225225    }
226226
@@ -229,17 +229,17 @@ abstract contract Scheduler is IScheduler, SchedulerState {
229229        uint256  amount 
230230    ) external  override  onlyManager (subscriptionId) {
231231        SubscriptionStatus storage  status =  _state.subscriptionStatuses[subscriptionId];
232-          
232+ 
233233        if  (! status.isActive) {
234234            revert  InactiveSubscription ();
235235        }
236-          
236+ 
237237        if  (status.balanceInWei <  amount) {
238238            revert  InsufficientBalance ();
239239        }
240-          
240+ 
241241        status.balanceInWei -=  amount;
242-          
242+ 
243243        (bool  sent , ) =  msg .sender .call {value: amount}("" );
244244        require (sent, "Failed to send funds " );
245245    }
@@ -264,13 +264,13 @@ abstract contract Scheduler is IScheduler, SchedulerState {
264264            _; 
265265            return ;
266266        }
267-          
267+ 
268268        // If whitelist is not used, allow any reader 
269269        if  (! _state.subscriptionParams[subscriptionId].useWhitelist) {
270270            _; 
271271            return ;
272272        }
273-          
273+ 
274274        // Check if caller is in whitelist 
275275        address [] storage  whitelist =  _state.subscriptionParams[subscriptionId].readerWhitelist;
276276        bool  isWhitelisted =  false ;
@@ -280,13 +280,13 @@ abstract contract Scheduler is IScheduler, SchedulerState {
280280                break ;
281281            }
282282        }
283-          
283+ 
284284        if  (! isWhitelisted) {
285285            revert  Unauthorized ();
286286        }
287287        _; 
288288    }
289-      
289+ 
290290    function getActiveSubscriptions  () external  view  override  returns  (
291291        uint256 [] memory  subscriptionIds ,
292292        SubscriptionParams[] memory  subscriptionParams 
@@ -298,11 +298,11 @@ abstract contract Scheduler is IScheduler, SchedulerState {
298298                activeCount++ ;
299299            }
300300        }
301-          
301+ 
302302        // Create arrays for subscription IDs and parameters 
303303        subscriptionIds =  new  uint256 [](activeCount);
304304        subscriptionParams =  new  SubscriptionParams [](activeCount);
305-          
305+ 
306306        // Populate arrays with active subscription data 
307307        uint256  index =  0 ;
308308        for  (uint256  i =  1 ; i <  _state.subscriptionNumber; i++ ) {
@@ -312,7 +312,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
312312                index++ ;
313313            }
314314        }
315-          
315+ 
316316        return  (subscriptionIds, subscriptionParams);
317317    }
318318}
0 commit comments