@@ -98,6 +98,11 @@ abstract contract Scheduler is IScheduler, SchedulerState {
98
98
bool wasActive = currentParams.isActive;
99
99
bool willBeActive = newParams.isActive;
100
100
101
+ // Check for permanent subscription restrictions
102
+ if (currentParams.isPermanent) {
103
+ _validatePermanentSubscriptionUpdate (currentParams, newParams);
104
+ }
105
+
101
106
// If subscription is inactive and will remain inactive, no need to validate parameters
102
107
if (! wasActive && ! willBeActive) {
103
108
// Update subscription parameters
@@ -385,6 +390,103 @@ abstract contract Scheduler is IScheduler, SchedulerState {
385
390
revert UpdateConditionsNotMet ();
386
391
}
387
392
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
+
388
490
/// FETCH PRICES
389
491
390
492
/**
@@ -487,9 +589,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
487
589
488
590
/// BALANCE MANAGEMENT
489
591
490
- function addFunds (
491
- uint256 subscriptionId
492
- ) external payable override onlyManager (subscriptionId) {
592
+ function addFunds (uint256 subscriptionId ) external payable override {
493
593
if (! _state.subscriptionParams[subscriptionId].isActive) {
494
594
revert InactiveSubscription ();
495
595
}
@@ -508,6 +608,11 @@ abstract contract Scheduler is IScheduler, SchedulerState {
508
608
subscriptionId
509
609
];
510
610
611
+ // Prevent withdrawals from permanent subscriptions
612
+ if (params.isPermanent) {
613
+ revert IllegalPermanentSubscriptionModification ();
614
+ }
615
+
511
616
if (status.balanceInWei < amount) {
512
617
revert InsufficientBalance ();
513
618
}
0 commit comments