@@ -98,6 +98,11 @@ abstract contract Scheduler is IScheduler, SchedulerState {
9898 bool wasActive = currentParams.isActive;
9999 bool willBeActive = newParams.isActive;
100100
101+ // Check for permanent subscription restrictions
102+ if (currentParams.isPermanent) {
103+ _validatePermanentSubscriptionUpdate (currentParams, newParams);
104+ }
105+
101106 // If subscription is inactive and will remain inactive, no need to validate parameters
102107 if (! wasActive && ! willBeActive) {
103108 // Update subscription parameters
@@ -385,6 +390,103 @@ abstract contract Scheduler is IScheduler, SchedulerState {
385390 revert UpdateConditionsNotMet ();
386391 }
387392
393+ /**
394+ * @notice Internal helper to validate modifications to a permanent subscription.
395+ * @param currentParams The current subscription parameters (storage).
396+ * @param newParams The proposed new subscription parameters (memory).
397+ */
398+ function _validatePermanentSubscriptionUpdate (
399+ SubscriptionParams storage currentParams ,
400+ SubscriptionParams memory newParams
401+ ) internal view {
402+ // Cannot disable isPermanent flag once set
403+ if (! newParams.isPermanent) {
404+ revert IllegalPermanentSubscriptionModification ();
405+ }
406+
407+ // Cannot deactivate a permanent subscription
408+ if (! newParams.isActive) {
409+ revert IllegalPermanentSubscriptionModification ();
410+ }
411+
412+ // Cannot remove price feeds from a permanent subscription
413+ if (newParams.priceIds.length < currentParams.priceIds.length ) {
414+ revert IllegalPermanentSubscriptionModification ();
415+ }
416+
417+ // Check that all existing price IDs are preserved (adding is allowed, not removing)
418+ for (uint i = 0 ; i < currentParams.priceIds.length ; i++ ) {
419+ bool found = false ;
420+ for (uint j = 0 ; j < newParams.priceIds.length ; j++ ) {
421+ if (currentParams.priceIds[i] == newParams.priceIds[j]) {
422+ found = true ;
423+ break ;
424+ }
425+ }
426+ if (! found) {
427+ revert IllegalPermanentSubscriptionModification ();
428+ }
429+ }
430+
431+ // Cannot change reader whitelist settings for permanent subscriptions
432+ if (newParams.whitelistEnabled != currentParams.whitelistEnabled) {
433+ revert IllegalPermanentSubscriptionModification ();
434+ }
435+
436+ // Check if the set of addresses in the whitelist is the same
437+ if (
438+ newParams.readerWhitelist.length !=
439+ currentParams.readerWhitelist.length
440+ ) {
441+ revert IllegalPermanentSubscriptionModification ();
442+ }
443+ uint256 n = newParams.readerWhitelist.length ;
444+ bool [] memory currentVisited = new bool [](n);
445+ uint256 matchesFound = 0 ;
446+ for (uint256 i = 0 ; i < n; i++ ) {
447+ bool foundInCurrent = false ;
448+ for (uint256 j = 0 ; j < n; j++ ) {
449+ if (
450+ ! currentVisited[j] &&
451+ newParams.readerWhitelist[i] ==
452+ currentParams.readerWhitelist[j]
453+ ) {
454+ currentVisited[j] = true ;
455+ foundInCurrent = true ;
456+ matchesFound++ ;
457+ break ;
458+ }
459+ }
460+ if (! foundInCurrent) {
461+ revert IllegalPermanentSubscriptionModification ();
462+ }
463+ }
464+
465+ // Cannot change update criteria for permanent subscriptions
466+ if (
467+ newParams.updateCriteria.updateOnHeartbeat !=
468+ currentParams.updateCriteria.updateOnHeartbeat ||
469+ newParams.updateCriteria.heartbeatSeconds !=
470+ currentParams.updateCriteria.heartbeatSeconds ||
471+ newParams.updateCriteria.updateOnDeviation !=
472+ currentParams.updateCriteria.updateOnDeviation ||
473+ newParams.updateCriteria.deviationThresholdBps !=
474+ currentParams.updateCriteria.deviationThresholdBps
475+ ) {
476+ revert IllegalPermanentSubscriptionModification ();
477+ }
478+
479+ // Cannot change gas config for permanent subscriptions
480+ if (
481+ newParams.gasConfig.maxBaseFeeMultiplierCapPct !=
482+ currentParams.gasConfig.maxBaseFeeMultiplierCapPct ||
483+ newParams.gasConfig.maxPriorityFeeMultiplierCapPct !=
484+ currentParams.gasConfig.maxPriorityFeeMultiplierCapPct
485+ ) {
486+ revert IllegalPermanentSubscriptionModification ();
487+ }
488+ }
489+
388490 /// FETCH PRICES
389491
390492 /**
@@ -487,9 +589,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
487589
488590 /// BALANCE MANAGEMENT
489591
490- function addFunds (
491- uint256 subscriptionId
492- ) external payable override onlyManager (subscriptionId) {
592+ function addFunds (uint256 subscriptionId ) external payable override {
493593 if (! _state.subscriptionParams[subscriptionId].isActive) {
494594 revert InactiveSubscription ();
495595 }
@@ -508,6 +608,11 @@ abstract contract Scheduler is IScheduler, SchedulerState {
508608 subscriptionId
509609 ];
510610
611+ // Prevent withdrawals from permanent subscriptions
612+ if (params.isPermanent) {
613+ revert IllegalPermanentSubscriptionModification ();
614+ }
615+
511616 if (status.balanceInWei < amount) {
512617 revert InsufficientBalance ();
513618 }
0 commit comments