Skip to content

Commit b44aea5

Browse files
fix: remove priceids from updatepricefeeds (#2636)
1 parent edddc0a commit b44aea5

File tree

4 files changed

+26
-52
lines changed

4 files changed

+26
-52
lines changed

target_chains/ethereum/contracts/contracts/pulse/IScheduler.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ interface IScheduler is SchedulerEvents {
4949

5050
/**
5151
* @notice Updates price feeds for a subscription.
52-
* @dev Internally, this verifies the updateData using the Pyth contract and validates update conditions.
52+
* @dev The updateData must contain all price feeds for the subscription, not a subset or superset.
53+
* @dev Internally, the updateData is verified using the Pyth contract and validates update conditions.
54+
* The call will only succeed if the update conditions for the subscription are met.
5355
* @param subscriptionId The ID of the subscription
5456
* @param updateData The price update data from Pyth
55-
* @param priceIds The IDs of the price feeds to update
5657
*/
5758
function updatePriceFeeds(
5859
uint256 subscriptionId,
59-
bytes[] calldata updateData,
60-
bytes32[] calldata priceIds
60+
bytes[] calldata updateData
6161
) external;
6262

6363
/** @notice Returns the price of a price feed without any sanity checks.

target_chains/ethereum/contracts/contracts/pulse/Scheduler.sol

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
247247

248248
function updatePriceFeeds(
249249
uint256 subscriptionId,
250-
bytes[] calldata updateData,
251-
bytes32[] calldata priceIds
250+
bytes[] calldata updateData
252251
) external override {
253252
uint256 startGas = gasleft();
254253

@@ -263,21 +262,6 @@ abstract contract Scheduler is IScheduler, SchedulerState {
263262
revert InactiveSubscription();
264263
}
265264

266-
// Verify price IDs match subscription length
267-
if (priceIds.length != params.priceIds.length) {
268-
revert InvalidPriceIdsLength(
269-
priceIds.length,
270-
params.priceIds.length
271-
);
272-
}
273-
274-
// Keepers must provide priceIds in the exact same order as defined in the subscription
275-
for (uint8 i = 0; i < priceIds.length; i++) {
276-
if (priceIds[i] != params.priceIds[i]) {
277-
revert InvalidPriceId(priceIds[i], params.priceIds[i]);
278-
}
279-
}
280-
281265
// Get the Pyth contract and parse price updates
282266
IPyth pyth = IPyth(_state.pyth);
283267
uint256 pythFee = pyth.getUpdateFee(updateData);
@@ -295,7 +279,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
295279
uint64[] memory slots
296280
) = pyth.parsePriceFeedUpdatesWithSlots{value: pythFee}(
297281
updateData,
298-
priceIds,
282+
params.priceIds,
299283
curTime > PAST_TIMESTAMP_MAX_VALIDITY_PERIOD
300284
? curTime - PAST_TIMESTAMP_MAX_VALIDITY_PERIOD
301285
: 0,
@@ -329,7 +313,7 @@ abstract contract Scheduler is IScheduler, SchedulerState {
329313

330314
_storePriceUpdates(subscriptionId, priceFeeds);
331315

332-
_processFeesAndPayKeeper(status, startGas, priceIds.length);
316+
_processFeesAndPayKeeper(status, startGas, params.priceIds.length);
333317

334318
emit PricesUpdated(subscriptionId, latestPublishTime);
335319
}

target_chains/ethereum/contracts/forge-test/PulseScheduler.t.sol

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
252252
bytes[] memory updateData = createMockUpdateData(initialPriceFeeds);
253253

254254
vm.prank(pusher);
255-
scheduler.updatePriceFeeds(subscriptionId, updateData, initialPriceIds);
255+
scheduler.updatePriceFeeds(subscriptionId, updateData);
256256

257257
// Verify initial state: All 3 feeds should be readable
258258
assertTrue(
@@ -830,7 +830,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
830830
emit PricesUpdated(subscriptionId, publishTime1);
831831
vm.prank(pusher);
832832

833-
scheduler.updatePriceFeeds(subscriptionId, updateData1, priceIds);
833+
scheduler.updatePriceFeeds(subscriptionId, updateData1);
834834

835835
// Verify first update
836836
(, SchedulerState.SubscriptionStatus memory status1) = scheduler
@@ -881,7 +881,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
881881
emit PricesUpdated(subscriptionId, publishTime2);
882882
vm.prank(pusher);
883883

884-
scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
884+
scheduler.updatePriceFeeds(subscriptionId, updateData2);
885885

886886
// Verify second update
887887
(, SchedulerState.SubscriptionStatus memory status2) = scheduler
@@ -948,7 +948,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
948948

949949
// Perform update
950950
vm.prank(pusher);
951-
scheduler.updatePriceFeeds(subscriptionId, updateData, params.priceIds);
951+
scheduler.updatePriceFeeds(subscriptionId, updateData);
952952

953953
// Get state after
954954
(, SchedulerState.SubscriptionStatus memory statusAfter) = scheduler
@@ -1050,7 +1050,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
10501050
// Expect revert due to insufficient balance for total fee
10511051
vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector));
10521052
vm.prank(pusher);
1053-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1053+
scheduler.updatePriceFeeds(subscriptionId, updateData);
10541054
}
10551055

10561056
function testUpdatePriceFeedsRevertsOnHeartbeatUpdateConditionNotMet()
@@ -1073,15 +1073,14 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
10731073
uint256 fundAmount = 1 ether;
10741074
scheduler.addFunds{value: fundAmount}(subscriptionId);
10751075
// First update to set initial timestamp
1076-
bytes32[] memory priceIds = createPriceIds();
10771076
uint64 publishTime1 = SafeCast.toUint64(block.timestamp);
10781077
PythStructs.PriceFeed[] memory priceFeeds1;
10791078
uint64[] memory slots1;
10801079
(priceFeeds1, slots1) = createMockPriceFeedsWithSlots(publishTime1, 2);
10811080
mockParsePriceFeedUpdatesWithSlots(pyth, priceFeeds1, slots1);
10821081
bytes[] memory updateData1 = createMockUpdateData(priceFeeds1);
10831082
vm.prank(pusher);
1084-
scheduler.updatePriceFeeds(subscriptionId, updateData1, priceIds);
1083+
scheduler.updatePriceFeeds(subscriptionId, updateData1);
10851084

10861085
// Prepare second update within heartbeat interval
10871086
vm.warp(block.timestamp + 30); // Advance time by 30 seconds (less than 60)
@@ -1097,7 +1096,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
10971096
abi.encodeWithSelector(UpdateConditionsNotMet.selector)
10981097
);
10991098
vm.prank(pusher);
1100-
scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
1099+
scheduler.updatePriceFeeds(subscriptionId, updateData2);
11011100
}
11021101

11031102
function testUpdatePriceFeedsRevertsOnDeviationUpdateConditionNotMet()
@@ -1121,15 +1120,14 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
11211120
scheduler.addFunds{value: fundAmount}(subscriptionId);
11221121

11231122
// First update to set initial price
1124-
bytes32[] memory priceIds = createPriceIds();
11251123
uint64 publishTime1 = SafeCast.toUint64(block.timestamp);
11261124
PythStructs.PriceFeed[] memory priceFeeds1;
11271125
uint64[] memory slots;
11281126
(priceFeeds1, slots) = createMockPriceFeedsWithSlots(publishTime1, 2);
11291127
mockParsePriceFeedUpdatesWithSlots(pyth, priceFeeds1, slots);
11301128
bytes[] memory updateData1 = createMockUpdateData(priceFeeds1);
11311129
vm.prank(pusher);
1132-
scheduler.updatePriceFeeds(subscriptionId, updateData1, priceIds);
1130+
scheduler.updatePriceFeeds(subscriptionId, updateData1);
11331131

11341132
// Prepare second update with price deviation less than threshold (e.g., 50 bps)
11351133
vm.warp(block.timestamp + 1000); // Advance time significantly (doesn't matter for deviation)
@@ -1160,7 +1158,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
11601158
abi.encodeWithSelector(UpdateConditionsNotMet.selector)
11611159
);
11621160
vm.prank(pusher);
1163-
scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
1161+
scheduler.updatePriceFeeds(subscriptionId, updateData2);
11641162
}
11651163

11661164
function testUpdatePriceFeedsRevertsOnOlderTimestamp() public {
@@ -1173,7 +1171,6 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
11731171
scheduler.addFunds{value: fundAmount}(subscriptionId);
11741172

11751173
// First update to establish last updated timestamp
1176-
bytes32[] memory priceIds = createPriceIds();
11771174
uint64 publishTime1 = SafeCast.toUint64(block.timestamp);
11781175
PythStructs.PriceFeed[] memory priceFeeds1;
11791176
uint64[] memory slots1;
@@ -1182,7 +1179,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
11821179
bytes[] memory updateData1 = createMockUpdateData(priceFeeds1);
11831180

11841181
vm.prank(pusher);
1185-
scheduler.updatePriceFeeds(subscriptionId, updateData1, priceIds);
1182+
scheduler.updatePriceFeeds(subscriptionId, updateData1);
11861183

11871184
// Prepare second update with an older timestamp
11881185
uint64 publishTime2 = publishTime1 - 10; // Timestamp older than the first update
@@ -1204,7 +1201,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
12041201

12051202
// Attempt to update price feeds
12061203
vm.prank(pusher);
1207-
scheduler.updatePriceFeeds(subscriptionId, updateData2, priceIds);
1204+
scheduler.updatePriceFeeds(subscriptionId, updateData2);
12081205
}
12091206

12101207
function testUpdatePriceFeedsRevertsOnMismatchedSlots() public {
@@ -1217,7 +1214,6 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
12171214
scheduler.addFunds{value: fundAmount}(subscriptionId);
12181215

12191216
// Create two price feeds with same timestamp but different slots
1220-
bytes32[] memory priceIds = createPriceIds(2);
12211217
uint64 publishTime = SafeCast.toUint64(block.timestamp);
12221218
PythStructs.PriceFeed[] memory priceFeeds = new PythStructs.PriceFeed[](
12231219
2
@@ -1239,7 +1235,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
12391235

12401236
// Attempt to update price feeds
12411237
vm.prank(pusher);
1242-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1238+
scheduler.updatePriceFeeds(subscriptionId, updateData);
12431239
}
12441240

12451241
function testUpdateSubscriptionEnforcesMinimumBalanceOnAddingFeeds()
@@ -1350,7 +1346,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
13501346
bytes[] memory updateData = createMockUpdateData(priceFeeds);
13511347

13521348
vm.prank(pusher);
1353-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1349+
scheduler.updatePriceFeeds(subscriptionId, updateData);
13541350

13551351
// Get all latest prices (empty priceIds array)
13561352
bytes32[] memory emptyPriceIds = new bytes32[](0);
@@ -1392,7 +1388,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
13921388
bytes[] memory updateData = createMockUpdateData(priceFeeds);
13931389

13941390
vm.prank(pusher);
1395-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1391+
scheduler.updatePriceFeeds(subscriptionId, updateData);
13961392

13971393
// Get only the first price feed
13981394
bytes32[] memory selectedPriceIds = new bytes32[](1);
@@ -1445,10 +1441,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
14451441
(priceFeeds, slots) = createMockPriceFeedsWithSlots(publishTime, 2);
14461442
mockParsePriceFeedUpdatesWithSlots(pyth, priceFeeds, slots);
14471443
bytes[] memory updateData = createMockUpdateData(priceFeeds);
1448-
bytes32[] memory priceIds = params.priceIds;
14491444

14501445
vm.prank(pusher);
1451-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1446+
scheduler.updatePriceFeeds(subscriptionId, updateData);
14521447

14531448
// Try to access from a non-whitelisted address (should succeed)
14541449
address randomUser = address(0xdead);
@@ -1492,7 +1487,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
14921487
bytes[] memory updateData = createMockUpdateData(priceFeeds);
14931488

14941489
vm.prank(pusher);
1495-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1490+
scheduler.updatePriceFeeds(subscriptionId, updateData);
14961491

14971492
// Try to access from a non-whitelisted address (should fail)
14981493
vm.startPrank(address(0xdead));
@@ -1559,7 +1554,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
15591554
bytes[] memory updateData = createMockUpdateData(priceFeeds);
15601555

15611556
vm.prank(pusher);
1562-
scheduler.updatePriceFeeds(subscriptionId, updateData, priceIds);
1557+
scheduler.updatePriceFeeds(subscriptionId, updateData);
15631558

15641559
// Get EMA prices
15651560
bytes32[] memory emptyPriceIds = new bytes32[](0);

target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
7676
uint256 startGas = gasleft();
7777
scheduler.updatePriceFeeds(
7878
subscriptionId,
79-
createMockUpdateData(newPriceFeeds),
80-
params.priceIds
79+
createMockUpdateData(newPriceFeeds)
8180
);
8281
uint256 updateGasUsed = startGas - gasleft();
8382

@@ -114,10 +113,6 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
114113
address(manager)
115114
);
116115

117-
// Fetch the price IDs
118-
(SchedulerState.SubscriptionParams memory params, ) = scheduler
119-
.getSubscription(subscriptionId);
120-
121116
// Create initial price feed updates
122117
uint64 publishTime = SafeCast.toUint64(block.timestamp);
123118
PythStructs.PriceFeed[] memory priceFeeds;
@@ -133,7 +128,7 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils {
133128

134129
// Update the price feeds. We should have enough balance to cover the update
135130
// because we funded the subscription with the minimum balance during creation.
136-
scheduler.updatePriceFeeds(subscriptionId, updateData, params.priceIds);
131+
scheduler.updatePriceFeeds(subscriptionId, updateData);
137132
return subscriptionId;
138133
}
139134

0 commit comments

Comments
 (0)