Skip to content

Commit 507b5ca

Browse files
aditya520cctdaniel
authored andcommitted
update
1 parent e1dcc2f commit 507b5ca

File tree

5 files changed

+153
-27
lines changed

5 files changed

+153
-27
lines changed

target_chains/ethereum/contracts/contracts/pyth/Pyth.sol

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,16 @@ abstract contract Pyth is
311311
function parseTwapPriceFeedUpdates(
312312
bytes[2][] calldata updateData,
313313
bytes32[] calldata priceIds,
314-
unit8 windowSize
314+
uint8 windowSize
315315
)
316316
external
317317
payable
318-
override
319318
returns (PythStructs.TwapPriceFeed[] memory twapPriceFeeds)
320319
{
321320
{
322-
revert(updateData.length != 2, PythErrors.InvalidUpdateData());
321+
if (updateData.length != 2) {
322+
revert PythErrors.InvalidUpdateData();
323+
}
323324
uint requiredFee = getUpdateFee(updateData[0]);
324325

325326
// Check if the two updateData contains the same number of priceUpdates
@@ -330,6 +331,7 @@ abstract contract Pyth is
330331
}
331332

332333
// Parse the updateData
334+
unchecked {
333335
twapPriceFeeds = new PythStructs.TwapPriceFeed[](priceIds.length);
334336
for (uint i = 0; i < updateData[0].length; i++) {
335337
if (
@@ -341,6 +343,7 @@ abstract contract Pyth is
341343
ACCUMULATOR_MAGIC)
342344
) {
343345
// Parse the accumulator update
346+
// I believe the offset will be same for both updateData[0][i] and updateData[1][i]
344347
uint offsetFirst;
345348
uint offsetSecond;
346349
{
@@ -364,7 +367,7 @@ abstract contract Pyth is
364367
(
365368
offsetFirst,
366369
digestFirst,
367-
numUpdates,
370+
numUpdatesFirst,
368371
encodedFirst
369372
) = extractWormholeMerkleHeaderDigestAndNumUpdatesAndEncodedFromAccumulatorUpdate(
370373
updateData[0][i],
@@ -373,12 +376,12 @@ abstract contract Pyth is
373376
(
374377
offsetSecond,
375378
digestSecond,
376-
numUpdates,
379+
numUpdatesSecond,
377380
encodedSecond
378381
) = extractWormholeMerkleHeaderDigestAndNumUpdatesAndEncodedFromAccumulatorUpdate(
379382
updateData[1][i],
380383
offsetSecond);
381-
384+
// I believe this check is redundant
382385
if (numUpdatesFirst != numUpdatesSecond) {
383386
revert PythErrors.InvalidUpdateData();
384387
}
@@ -389,15 +392,86 @@ abstract contract Pyth is
389392
bytes32 priceIdFirst;
390393
bytes32 priceIdSecond;
391394

392-
(offsetFirst, twapPriceInfoFirst, priceIdFirst) = extractPriceInfoFromMerkleProof(digestFirst, encodedFirst, offsetFirst);
393-
(offsetSecond, twapPriceInfoSecond, priceIdSecond) = extractPriceInfoFromMerkleProof(digestSecond, encodedSecond, offsetSecond);
394-
}
395+
(offsetFirst, twapPriceInfoFirst, priceIdFirst) = extractTwapPriceInfoFromMerkleProof(digestFirst, encodedFirst, offsetFirst);
396+
(offsetSecond, twapPriceInfoSecond, priceIdSecond) = extractTwapPriceInfoFromMerkleProof(digestSecond, encodedSecond, offsetSecond);
395397

398+
require(priceIdFirst == priceIdSecond, PythErrors.InvalidTwapUpdateDataSet());
396399

400+
// No Updates here.
401+
// check whether caller requested for this data
402+
uint k = findIndexOfPriceId(priceIds, priceIdFirst);
403+
if (k == priceIds.length || twapPriceFeeds[k].id != 0) {
404+
continue;
405+
}
406+
407+
// Since we have already validated the twap price info, we can directly use it
408+
validateTwapPriceInfo(twapPriceInfoFirst, twapPriceInfoSecond);
409+
410+
// Now we will calcualte the cumulative price and cumulative conf
411+
// for the first and second priceId
412+
// I believe the cumulative price and cumulative conf will be same for both priceIdFirst and priceIdSecond
413+
// because they are both from the same accumulator update
414+
uint64 slotDiff = twapPriceInfoSecond.publishSlot - twapPriceInfoFirst.publishSlot;
415+
int128 priceDiff = twapPriceInfoSecond.price - twapPriceInfoFirst.price;
416+
uint128 confDiff = twapPriceInfoSecond.conf - twapPriceInfoFirst.conf;
417+
418+
// Now we will calculate the twap price and twap conf
419+
// for the first and second priceId
420+
int128 twapPrice = priceDiff / slotDiff;
421+
uint128 twapConf = confDiff / slotDiff;
422+
423+
twapPriceFeeds[k].id = priceIdFirst;
424+
twapPriceFeeds[k].twap.price = twapPrice;
425+
twapPriceFeeds[k].twap.conf = twapConf;
426+
twapPriceFeeds[k].twap.expo = twapPriceInfoFirst.expo;
427+
twapPriceFeeds[k].twap.publishTime = twapPriceInfoSecond.publishTime;
428+
twapPriceFeeds[k].startTime = twapPriceInfoFirst.publishTime;
429+
twapPriceFeeds[k].endTime = twapPriceInfoSecond.publishTime;
430+
//TODO: Calculate the downSlotRatio
431+
}
432+
if (offsetFirst != encodedFirst.length) {
433+
revert PythErrors.InvalidTwapUpdateData();
434+
}
435+
if (offsetSecond != encodedSecond.length) {
436+
revert PythErrors.InvalidTwapUpdateData();
437+
}
438+
if (offsetFirst != offsetSecond) {
439+
revert PythErrors.InvalidTwapUpdateData();
440+
} else {
441+
revert PythErrors.InvalidUpdateData();
442+
}
397443
} else {
398444
revert PythErrors.InvalidUpdateData();
399445
}
400446
}
447+
448+
for (uint k = 0; k < priceIds.length; k++) {
449+
if (twapPriceFeeds[k].id == 0) {
450+
revert PythErrors.PriceFeedNotFoundWithinRange();
451+
}
452+
}
453+
}
454+
}
455+
456+
function validateTwapPriceInfo(
457+
PythInternalStructs.TwapPriceInfo memory twapPriceInfoFirst,
458+
PythInternalStructs.TwapPriceInfo memory twapPriceInfoSecond
459+
) private pure {
460+
if (twapPriceInfoFirst.expo != twapPriceInfoSecond.expo) {
461+
revert PythErrors.InvalidTwapUpdateDataSet();
462+
}
463+
if (twapPriceInfoFirst.publishSlot > twapPriceInfoSecond.publishSlot) {
464+
revert PythErrors.InvalidTwapUpdateDataSet();
465+
}
466+
if (twapPriceInfoFirst.prevPublishTime > twapPriceInfoFirst.publishTime) {
467+
revert PythErrors.InvalidTwapUpdateData();
468+
}
469+
if (twapPriceInfoSecond.prevPublishTime > twapPriceInfoSecond.publishTime) {
470+
revert PythErrors.InvalidTwapUpdateDataSet();
471+
}
472+
if (twapPriceInfoFirst.publishTime > twapPriceInfoSecond.publishTime) {
473+
revert PythErrors.InvalidTwapUpdateDataSet();
474+
}
401475
}
402476

403477
function parsePriceFeedUpdatesUnique(

target_chains/ethereum/contracts/contracts/pyth/PythAccumulator.sol

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,66 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
263263
encodedMessage,
264264
1
265265
);
266-
} else if (messageType == MessageType.TwapPriceFeed) {
266+
} else revert PythErrors.InvalidUpdateData();
267+
268+
return (endOffset, priceInfo, priceId, prevPublishTime);
269+
}
270+
}
271+
272+
function extractTwapPriceInfoFromMerkleProof(
273+
bytes20 digest,
274+
bytes calldata encoded,
275+
uint offset
276+
)
277+
internal
278+
pure
279+
returns (
280+
uint endOffset,
281+
PythInternalStructs.TwapPriceInfo memory twapPriceInfo,
282+
bytes32 priceId
283+
)
284+
// TODO: Add the logic to extract the twap price info from the merkle proof
285+
{
286+
unchecked {
287+
bytes calldata encodedMessage;
288+
uint16 messageSize = UnsafeCalldataBytesLib.toUint16(
289+
encoded,
290+
offset
291+
);
292+
offset += 2;
293+
294+
encodedMessage = UnsafeCalldataBytesLib.slice(
295+
encoded,
296+
offset,
297+
messageSize
298+
);
299+
offset += messageSize;
300+
301+
bool valid;
302+
(valid, endOffset) = MerkleTree.isProofValid(
303+
encoded,
304+
offset,
305+
digest,
306+
encodedMessage
307+
);
308+
if (!valid) {
309+
revert PythErrors.InvalidUpdateData();
310+
}
311+
312+
MessageType messageType = MessageType(
313+
UnsafeCalldataBytesLib.toUint8(encodedMessage, 0)
314+
);
315+
if (messageType == MessageType.TwapPriceFeed) {
267316
(twapPriceInfo, priceId) = parseTwapPriceFeedMessage(
268317
encodedMessage,
269318
1
270319
);
271-
} else {
272-
revert PythErrors.InvalidUpdateData();
273-
}
320+
} else revert PythErrors.InvalidUpdateData();
274321

275-
return (endOffset, priceInfo, priceId, prevPublishTime);
322+
return (endOffset, twapPriceInfo, priceId);
276323
}
277324
}
325+
278326

279327
function parsePriceFeedMessage(
280328
bytes calldata encodedPriceFeed,
@@ -354,52 +402,52 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
354402
{
355403
unchecked {
356404
priceId = UnsafeCalldataBytesLib.toBytes32(
357-
encodedPriceFeed,
405+
encodedTwapPriceFeed,
358406
offset
359407
);
360408
offset += 32;
361409

362410
twapPriceInfo.cumulativePrice = int128(
363-
UnsafeCalldataBytesLib.toUint64(encodedPriceFeed, offset)
411+
UnsafeCalldataBytesLib.toUint128(encodedTwapPriceFeed, offset)
364412
);
365413
offset += 16;
366414

367415
twapPriceInfo.cumulativeConf = UnsafeCalldataBytesLib.toUint128(
368-
encodedPriceFeed,
416+
encodedTwapPriceFeed,
369417
offset
370418
);
371419
offset += 16;
372420

373421
twapPriceInfo.numDownSlots = UnsafeCalldataBytesLib.toUint64(
374-
encodedPriceFeed,
422+
encodedTwapPriceFeed,
375423
offset
376424
);
377425
offset += 8;
378426

379427
twapPriceInfo.publishSlot = UnsafeCalldataBytesLib.toUint64(
380-
encodedPriceFeed,
428+
encodedTwapPriceFeed,
381429
offset
382430
);
383431
offset += 8;
384432

385433
twapPriceInfo.publishTime = UnsafeCalldataBytesLib.toUint64(
386-
encodedPriceFeed,
434+
encodedTwapPriceFeed,
387435
offset
388436
);
389437
offset += 8;
390438

391439
twapPriceInfo.prevPublishTime = UnsafeCalldataBytesLib.toUint64(
392-
encodedPriceFeed,
440+
encodedTwapPriceFeed,
393441
offset
394442
);
395443
offset += 8;
396444

397445
twapPriceInfo.expo = int32(
398-
UnsafeCalldataBytesLib.toUint32(encodedPriceFeed, offset)
446+
UnsafeCalldataBytesLib.toUint32(encodedTwapPriceFeed, offset)
399447
);
400448
offset += 4;
401449

402-
if (offset > encodedPriceFeed.length)
450+
if (offset > encodedTwapPriceFeed.length)
403451
revert PythErrors.InvalidUpdateData();
404452
}
405453
}

target_chains/ethereum/contracts/contracts/pyth/PythInternalStructs.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ contract PythInternalStructs {
3434
// slot 2
3535
uint64 numDownSlots;
3636
uint64 publishSlot;
37-
int64 publishTime;
38-
int64 prevPublishTime;
37+
uint64 publishTime;
38+
uint64 prevPublishTime;
3939
// slot 3
4040

4141
int32 expo;

target_chains/ethereum/sdk/solidity/PythErrors.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ library PythErrors {
4545
// The wormhole address to set in SetWormholeAddress governance is invalid.
4646
// Signature: 0x13d3ed82
4747
error InvalidWormholeAddressToSet();
48+
// The twap update data is invalid.
49+
error InvalidTwapUpdateData();
50+
// The twap update data set is invalid.
51+
error InvalidTwapUpdateDataSet();
4852
}

target_chains/ethereum/sdk/solidity/PythStructs.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ contract PythStructs {
3939
// End time of the TWAP
4040
uint endTime;
4141
// TWAP price
42-
Price cumulativePrice;
42+
Price twap;
4343
// Down slot ratio
4444
uint32 downSlotRatio;
4545
}
46-
1}
46+
}

0 commit comments

Comments
 (0)