@@ -2231,4 +2231,128 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
22312231
22322232 // Required to receive ETH when withdrawing funds
22332233 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+ }
22342358}
0 commit comments