@@ -2231,4 +2231,128 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
2231
2231
2232
2232
// Required to receive ETH when withdrawing funds
2233
2233
receive () external payable {}
2234
+
2235
+ function testUpdateSubscriptionRemovesPriceUpdatesForRemovedPriceIds ()
2236
+ public
2237
+ {
2238
+ // 1. Setup: Add subscription with 3 price feeds, update prices
2239
+ uint8 numInitialFeeds = 3 ;
2240
+ uint256 subscriptionId = addTestSubscriptionWithFeeds (
2241
+ scheduler,
2242
+ numInitialFeeds,
2243
+ address (reader)
2244
+ );
2245
+ scheduler.addFunds {value: 1 ether }(subscriptionId);
2246
+
2247
+ // Get initial price IDs and create mock price feeds
2248
+ bytes32 [] memory initialPriceIds = createPriceIds (numInitialFeeds);
2249
+ uint64 publishTime = SafeCast.toUint64 (block .timestamp );
2250
+
2251
+ // Setup and perform initial price update
2252
+ (
2253
+ PythStructs.PriceFeed[] memory priceFeeds ,
2254
+ uint64 [] memory slots
2255
+ ) = createMockPriceFeedsWithSlots (publishTime, numInitialFeeds);
2256
+ mockParsePriceFeedUpdatesWithSlotsStrict (pyth, priceFeeds, slots);
2257
+
2258
+ vm.prank (pusher);
2259
+ scheduler.updatePriceFeeds (
2260
+ subscriptionId,
2261
+ createMockUpdateData (priceFeeds)
2262
+ );
2263
+
2264
+ // Store the removed price ID for later use
2265
+ bytes32 removedPriceId = initialPriceIds[numInitialFeeds - 1 ];
2266
+
2267
+ // 2. Action: Update subscription to remove the last price feed
2268
+ (SchedulerState.SubscriptionParams memory params , ) = scheduler
2269
+ .getSubscription (subscriptionId);
2270
+
2271
+ // Create new price IDs array without the last ID
2272
+ bytes32 [] memory newPriceIds = new bytes32 [](numInitialFeeds - 1 );
2273
+ for (uint i = 0 ; i < newPriceIds.length ; i++ ) {
2274
+ newPriceIds[i] = initialPriceIds[i];
2275
+ }
2276
+
2277
+ params.priceIds = newPriceIds;
2278
+
2279
+ vm.expectEmit ();
2280
+ emit SubscriptionUpdated (subscriptionId);
2281
+ scheduler.updateSubscription (subscriptionId, params);
2282
+
2283
+ // 3. Verification:
2284
+ // - Verify that the removed price ID is no longer part of the subscription's price IDs
2285
+ (SchedulerState.SubscriptionParams memory updatedParams , ) = scheduler
2286
+ .getSubscription (subscriptionId);
2287
+ assertEq (
2288
+ updatedParams.priceIds.length ,
2289
+ numInitialFeeds - 1 ,
2290
+ "Subscription should have one less price ID "
2291
+ );
2292
+
2293
+ bool removedPriceIdFound = false ;
2294
+ for (uint i = 0 ; i < updatedParams.priceIds.length ; i++ ) {
2295
+ if (updatedParams.priceIds[i] == removedPriceId) {
2296
+ removedPriceIdFound = true ;
2297
+ break ;
2298
+ }
2299
+ }
2300
+ assertFalse (
2301
+ removedPriceIdFound,
2302
+ "Removed price ID should not be in the subscription's price IDs "
2303
+ );
2304
+
2305
+ // - Querying all feeds should return only the remaining feeds
2306
+ PythStructs.Price[] memory allPricesAfterUpdate = scheduler
2307
+ .getPricesUnsafe (subscriptionId, new bytes32 [](0 ));
2308
+ assertEq (
2309
+ allPricesAfterUpdate.length ,
2310
+ newPriceIds.length ,
2311
+ "Querying all should only return remaining feeds "
2312
+ );
2313
+
2314
+ // - Verify that trying to get the price of the removed feed directly reverts
2315
+ bytes32 [] memory removedIdArray = new bytes32 [](1 );
2316
+ removedIdArray[0 ] = removedPriceId;
2317
+ vm.expectRevert (
2318
+ abi.encodeWithSelector (
2319
+ InvalidPriceId.selector ,
2320
+ removedPriceId,
2321
+ bytes32 (0 )
2322
+ )
2323
+ );
2324
+ scheduler.getPricesUnsafe (subscriptionId, removedIdArray);
2325
+ }
2326
+
2327
+ function testUpdateSubscriptionRevertsWithTooManyPriceIds () public {
2328
+ // 1. Setup: Create a subscription with a valid number of price IDs
2329
+ uint8 initialNumFeeds = 2 ;
2330
+ uint256 subscriptionId = addTestSubscriptionWithFeeds (
2331
+ scheduler,
2332
+ initialNumFeeds,
2333
+ address (reader)
2334
+ );
2335
+
2336
+ // 2. Prepare params with too many price IDs (MAX_PRICE_IDS_PER_SUBSCRIPTION + 1)
2337
+ (SchedulerState.SubscriptionParams memory currentParams , ) = scheduler
2338
+ .getSubscription (subscriptionId);
2339
+
2340
+ uint16 tooManyFeeds = uint16 (
2341
+ scheduler.MAX_PRICE_IDS_PER_SUBSCRIPTION ()
2342
+ ) + 1 ;
2343
+ bytes32 [] memory tooManyPriceIds = createPriceIds (tooManyFeeds);
2344
+
2345
+ SchedulerState.SubscriptionParams memory newParams = currentParams;
2346
+ newParams.priceIds = tooManyPriceIds;
2347
+
2348
+ // 3. Expect revert when trying to update with too many price IDs
2349
+ vm.expectRevert (
2350
+ abi.encodeWithSelector (
2351
+ TooManyPriceIds.selector ,
2352
+ tooManyFeeds,
2353
+ scheduler.MAX_PRICE_IDS_PER_SUBSCRIPTION ()
2354
+ )
2355
+ );
2356
+ scheduler.updateSubscription (subscriptionId, newParams);
2357
+ }
2234
2358
}
0 commit comments