@@ -7,7 +7,6 @@ import "@pythnetwork/pyth-sdk-solidity/AbstractPyth.sol";
77import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol " ;
88
99import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol " ;
10- import "@pythnetwork/pyth-sdk-solidity/PythUtils.sol " ;
1110import "./PythAccumulator.sol " ;
1211import "./PythGetters.sol " ;
1312import "./PythSetters.sol " ;
@@ -628,16 +627,53 @@ abstract contract Pyth is
628627 return "1.4.4-alpha.5 " ;
629628 }
630629
630+ /// @notice Calculates TWAP from two price points
631+ /// @dev The calculation is done by taking the difference of cumulative values and dividing by the time difference
632+ /// @param priceId The price feed ID
633+ /// @param twapPriceInfoStart The starting price point
634+ /// @param twapPriceInfoEnd The ending price point
635+ /// @return twapPriceFeed The calculated TWAP price feed
631636 function calculateTwap (
632637 bytes32 priceId ,
633638 PythStructs.TwapPriceInfo memory twapPriceInfoStart ,
634639 PythStructs.TwapPriceInfo memory twapPriceInfoEnd
635- ) private pure returns (PythStructs.TwapPriceFeed memory ) {
636- return
637- PythUtils.calculateTwap (
638- priceId,
639- twapPriceInfoStart,
640- twapPriceInfoEnd
641- );
640+ ) private pure returns (PythStructs.TwapPriceFeed memory twapPriceFeed ) {
641+ twapPriceFeed.id = priceId;
642+ twapPriceFeed.startTime = twapPriceInfoStart.publishTime;
643+ twapPriceFeed.endTime = twapPriceInfoEnd.publishTime;
644+
645+ // Calculate differences between start and end points for slots and cumulative values
646+ uint64 slotDiff = twapPriceInfoEnd.publishSlot -
647+ twapPriceInfoStart.publishSlot;
648+ int128 priceDiff = twapPriceInfoEnd.cumulativePrice -
649+ twapPriceInfoStart.cumulativePrice;
650+ uint128 confDiff = twapPriceInfoEnd.cumulativeConf -
651+ twapPriceInfoStart.cumulativeConf;
652+
653+ // Calculate time-weighted average price (TWAP) and confidence by dividing
654+ // the difference in cumulative values by the number of slots between data points
655+ int128 twapPrice = priceDiff / int128 (uint128 (slotDiff));
656+ uint128 twapConf = confDiff / uint128 (slotDiff);
657+
658+ // The conversion from int128 to int64 is safe because:
659+ // 1. Individual prices fit within int64 by protocol design
660+ // 2. TWAP is essentially an average price over time (cumulativePrice₂-cumulativePrice₁)/slotDiff
661+ // 3. This average must be within the range of individual prices that went into the calculation
662+ // We use int128 only as an intermediate type to safely handle cumulative sums
663+ twapPriceFeed.twap.price = int64 (twapPrice);
664+ twapPriceFeed.twap.conf = uint64 (twapConf);
665+ twapPriceFeed.twap.expo = twapPriceInfoStart.expo;
666+ twapPriceFeed.twap.publishTime = twapPriceInfoEnd.publishTime;
667+
668+ // Calculate downSlotsRatio as a value between 0 and 1,000,000
669+ // 0 means no slots were missed, 1,000,000 means all slots were missed
670+ uint64 totalDownSlots = twapPriceInfoEnd.numDownSlots -
671+ twapPriceInfoStart.numDownSlots;
672+ uint64 downSlotsRatio = (totalDownSlots * 1_000_000 ) / slotDiff;
673+
674+ // Safely downcast to uint32 (sufficient for value range 0-1,000,000)
675+ twapPriceFeed.downSlotsRatio = uint32 (downSlotsRatio);
676+
677+ return twapPriceFeed;
642678 }
643679}
0 commit comments