Răsfoiți Sursa

Merge pull request #2611 from pyth-network/migrate-evm-twap

feat(target_chains/ethereum): implement TWAP calculation directly in Pyth contract
Daniel Chew 7 luni în urmă
părinte
comite
05cdc67765

+ 44 - 8
target_chains/ethereum/contracts/contracts/pyth/Pyth.sol

@@ -7,7 +7,6 @@ import "@pythnetwork/pyth-sdk-solidity/AbstractPyth.sol";
 import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
 
 import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol";
-import "@pythnetwork/pyth-sdk-solidity/PythUtils.sol";
 import "./PythAccumulator.sol";
 import "./PythGetters.sol";
 import "./PythSetters.sol";
@@ -628,16 +627,53 @@ abstract contract Pyth is
         return "1.4.4-alpha.5";
     }
 
+    /// @notice Calculates TWAP from two price points
+    /// @dev The calculation is done by taking the difference of cumulative values and dividing by the time difference
+    /// @param priceId The price feed ID
+    /// @param twapPriceInfoStart The starting price point
+    /// @param twapPriceInfoEnd The ending price point
+    /// @return twapPriceFeed The calculated TWAP price feed
     function calculateTwap(
         bytes32 priceId,
         PythStructs.TwapPriceInfo memory twapPriceInfoStart,
         PythStructs.TwapPriceInfo memory twapPriceInfoEnd
-    ) private pure returns (PythStructs.TwapPriceFeed memory) {
-        return
-            PythUtils.calculateTwap(
-                priceId,
-                twapPriceInfoStart,
-                twapPriceInfoEnd
-            );
+    ) private pure returns (PythStructs.TwapPriceFeed memory twapPriceFeed) {
+        twapPriceFeed.id = priceId;
+        twapPriceFeed.startTime = twapPriceInfoStart.publishTime;
+        twapPriceFeed.endTime = twapPriceInfoEnd.publishTime;
+
+        // Calculate differences between start and end points for slots and cumulative values
+        uint64 slotDiff = twapPriceInfoEnd.publishSlot -
+            twapPriceInfoStart.publishSlot;
+        int128 priceDiff = twapPriceInfoEnd.cumulativePrice -
+            twapPriceInfoStart.cumulativePrice;
+        uint128 confDiff = twapPriceInfoEnd.cumulativeConf -
+            twapPriceInfoStart.cumulativeConf;
+
+        // Calculate time-weighted average price (TWAP) and confidence by dividing
+        // the difference in cumulative values by the number of slots between data points
+        int128 twapPrice = priceDiff / int128(uint128(slotDiff));
+        uint128 twapConf = confDiff / uint128(slotDiff);
+
+        // The conversion from int128 to int64 is safe because:
+        // 1. Individual prices fit within int64 by protocol design
+        // 2. TWAP is essentially an average price over time (cumulativePrice₂-cumulativePrice₁)/slotDiff
+        // 3. This average must be within the range of individual prices that went into the calculation
+        // We use int128 only as an intermediate type to safely handle cumulative sums
+        twapPriceFeed.twap.price = int64(twapPrice);
+        twapPriceFeed.twap.conf = uint64(twapConf);
+        twapPriceFeed.twap.expo = twapPriceInfoStart.expo;
+        twapPriceFeed.twap.publishTime = twapPriceInfoEnd.publishTime;
+
+        // Calculate downSlotsRatio as a value between 0 and 1,000,000
+        // 0 means no slots were missed, 1,000,000 means all slots were missed
+        uint64 totalDownSlots = twapPriceInfoEnd.numDownSlots -
+            twapPriceInfoStart.numDownSlots;
+        uint64 downSlotsRatio = (totalDownSlots * 1_000_000) / slotDiff;
+
+        // Safely downcast to uint32 (sufficient for value range 0-1,000,000)
+        twapPriceFeed.downSlotsRatio = uint32(downSlotsRatio);
+
+        return twapPriceFeed;
     }
 }

+ 0 - 50
target_chains/ethereum/sdk/solidity/PythUtils.sol

@@ -33,54 +33,4 @@ library PythUtils {
                 10 ** uint32(priceDecimals - targetDecimals);
         }
     }
-
-    /// @notice Calculates TWAP from two price points
-    /// @dev The calculation is done by taking the difference of cumulative values and dividing by the time difference
-    /// @param priceId The price feed ID
-    /// @param twapPriceInfoStart The starting price point
-    /// @param twapPriceInfoEnd The ending price point
-    /// @return twapPriceFeed The calculated TWAP price feed
-    function calculateTwap(
-        bytes32 priceId,
-        PythStructs.TwapPriceInfo memory twapPriceInfoStart,
-        PythStructs.TwapPriceInfo memory twapPriceInfoEnd
-    ) public pure returns (PythStructs.TwapPriceFeed memory twapPriceFeed) {
-        twapPriceFeed.id = priceId;
-        twapPriceFeed.startTime = twapPriceInfoStart.publishTime;
-        twapPriceFeed.endTime = twapPriceInfoEnd.publishTime;
-
-        // Calculate differences between start and end points for slots and cumulative values
-        uint64 slotDiff = twapPriceInfoEnd.publishSlot -
-            twapPriceInfoStart.publishSlot;
-        int128 priceDiff = twapPriceInfoEnd.cumulativePrice -
-            twapPriceInfoStart.cumulativePrice;
-        uint128 confDiff = twapPriceInfoEnd.cumulativeConf -
-            twapPriceInfoStart.cumulativeConf;
-
-        // Calculate time-weighted average price (TWAP) and confidence by dividing
-        // the difference in cumulative values by the number of slots between data points
-        int128 twapPrice = priceDiff / int128(uint128(slotDiff));
-        uint128 twapConf = confDiff / uint128(slotDiff);
-
-        // The conversion from int128 to int64 is safe because:
-        // 1. Individual prices fit within int64 by protocol design
-        // 2. TWAP is essentially an average price over time (cumulativePrice₂-cumulativePrice₁)/slotDiff
-        // 3. This average must be within the range of individual prices that went into the calculation
-        // We use int128 only as an intermediate type to safely handle cumulative sums
-        twapPriceFeed.twap.price = int64(twapPrice);
-        twapPriceFeed.twap.conf = uint64(twapConf);
-        twapPriceFeed.twap.expo = twapPriceInfoStart.expo;
-        twapPriceFeed.twap.publishTime = twapPriceInfoEnd.publishTime;
-
-        // Calculate downSlotsRatio as a value between 0 and 1,000,000
-        // 0 means no slots were missed, 1,000,000 means all slots were missed
-        uint64 totalDownSlots = twapPriceInfoEnd.numDownSlots -
-            twapPriceInfoStart.numDownSlots;
-        uint64 downSlotsRatio = (totalDownSlots * 1_000_000) / slotDiff;
-
-        // Safely downcast to uint32 (sufficient for value range 0-1,000,000)
-        twapPriceFeed.downSlotsRatio = uint32(downSlotsRatio);
-
-        return twapPriceFeed;
-    }
 }

+ 0 - 152
target_chains/ethereum/sdk/solidity/abis/PythUtils.json

@@ -1,156 +1,4 @@
 [
-  {
-    "inputs": [
-      {
-        "internalType": "bytes32",
-        "name": "priceId",
-        "type": "bytes32"
-      },
-      {
-        "components": [
-          {
-            "internalType": "int128",
-            "name": "cumulativePrice",
-            "type": "int128"
-          },
-          {
-            "internalType": "uint128",
-            "name": "cumulativeConf",
-            "type": "uint128"
-          },
-          {
-            "internalType": "uint64",
-            "name": "numDownSlots",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "publishSlot",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "publishTime",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "prevPublishTime",
-            "type": "uint64"
-          },
-          {
-            "internalType": "int32",
-            "name": "expo",
-            "type": "int32"
-          }
-        ],
-        "internalType": "struct PythStructs.TwapPriceInfo",
-        "name": "twapPriceInfoStart",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          {
-            "internalType": "int128",
-            "name": "cumulativePrice",
-            "type": "int128"
-          },
-          {
-            "internalType": "uint128",
-            "name": "cumulativeConf",
-            "type": "uint128"
-          },
-          {
-            "internalType": "uint64",
-            "name": "numDownSlots",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "publishSlot",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "publishTime",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "prevPublishTime",
-            "type": "uint64"
-          },
-          {
-            "internalType": "int32",
-            "name": "expo",
-            "type": "int32"
-          }
-        ],
-        "internalType": "struct PythStructs.TwapPriceInfo",
-        "name": "twapPriceInfoEnd",
-        "type": "tuple"
-      }
-    ],
-    "name": "calculateTwap",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "bytes32",
-            "name": "id",
-            "type": "bytes32"
-          },
-          {
-            "internalType": "uint64",
-            "name": "startTime",
-            "type": "uint64"
-          },
-          {
-            "internalType": "uint64",
-            "name": "endTime",
-            "type": "uint64"
-          },
-          {
-            "components": [
-              {
-                "internalType": "int64",
-                "name": "price",
-                "type": "int64"
-              },
-              {
-                "internalType": "uint64",
-                "name": "conf",
-                "type": "uint64"
-              },
-              {
-                "internalType": "int32",
-                "name": "expo",
-                "type": "int32"
-              },
-              {
-                "internalType": "uint256",
-                "name": "publishTime",
-                "type": "uint256"
-              }
-            ],
-            "internalType": "struct PythStructs.Price",
-            "name": "twap",
-            "type": "tuple"
-          },
-          {
-            "internalType": "uint32",
-            "name": "downSlotsRatio",
-            "type": "uint32"
-          }
-        ],
-        "internalType": "struct PythStructs.TwapPriceFeed",
-        "name": "twapPriceFeed",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "pure",
-    "type": "function"
-  },
   {
     "inputs": [
       {