MockPyth.sol 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: Apache-2.0
  2. pragma solidity ^0.8.0;
  3. import "./AbstractPyth.sol";
  4. import "./PythStructs.sol";
  5. import "./PythErrors.sol";
  6. contract MockPyth is AbstractPyth {
  7. mapping(bytes32 => PythStructs.PriceFeed) priceFeeds;
  8. uint singleUpdateFeeInWei;
  9. uint validTimePeriod;
  10. constructor(uint _validTimePeriod, uint _singleUpdateFeeInWei) {
  11. singleUpdateFeeInWei = _singleUpdateFeeInWei;
  12. validTimePeriod = _validTimePeriod;
  13. }
  14. function queryPriceFeed(
  15. bytes32 id
  16. ) public view override returns (PythStructs.PriceFeed memory priceFeed) {
  17. if (priceFeeds[id].id == 0) revert PythErrors.PriceFeedNotFound();
  18. return priceFeeds[id];
  19. }
  20. function priceFeedExists(bytes32 id) public view override returns (bool) {
  21. return (priceFeeds[id].id != 0);
  22. }
  23. function getValidTimePeriod() public view override returns (uint) {
  24. return validTimePeriod;
  25. }
  26. // Takes an array of encoded price feeds and stores them.
  27. // You can create this data either by calling createPriceFeedUpdateData or
  28. // by using web3.js or ethers abi utilities.
  29. function updatePriceFeeds(
  30. bytes[] calldata updateData
  31. ) public payable override {
  32. uint requiredFee = getUpdateFee(updateData);
  33. if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
  34. for (uint i = 0; i < updateData.length; i++) {
  35. PythStructs.PriceFeed memory priceFeed = abi.decode(
  36. updateData[i],
  37. (PythStructs.PriceFeed)
  38. );
  39. uint lastPublishTime = priceFeeds[priceFeed.id].price.publishTime;
  40. if (lastPublishTime < priceFeed.price.publishTime) {
  41. // Price information is more recent than the existing price information.
  42. priceFeeds[priceFeed.id] = priceFeed;
  43. emit PriceFeedUpdate(
  44. priceFeed.id,
  45. uint64(priceFeed.price.publishTime),
  46. priceFeed.price.price,
  47. priceFeed.price.conf
  48. );
  49. }
  50. }
  51. }
  52. function getUpdateFee(
  53. bytes[] calldata updateData
  54. ) public view override returns (uint feeAmount) {
  55. return singleUpdateFeeInWei * updateData.length;
  56. }
  57. function parsePriceFeedUpdatesInternal(
  58. bytes[] calldata updateData,
  59. bytes32[] calldata priceIds,
  60. uint64 minPublishTime,
  61. uint64 maxPublishTime,
  62. bool unique
  63. ) internal returns (PythStructs.PriceFeed[] memory feeds) {
  64. uint requiredFee = getUpdateFee(updateData);
  65. if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
  66. feeds = new PythStructs.PriceFeed[](priceIds.length);
  67. for (uint i = 0; i < priceIds.length; i++) {
  68. for (uint j = 0; j < updateData.length; j++) {
  69. uint64 prevPublishTime;
  70. (feeds[i], prevPublishTime) = abi.decode(
  71. updateData[j],
  72. (PythStructs.PriceFeed, uint64)
  73. );
  74. uint publishTime = feeds[i].price.publishTime;
  75. if (priceFeeds[feeds[i].id].price.publishTime < publishTime) {
  76. priceFeeds[feeds[i].id] = feeds[i];
  77. emit PriceFeedUpdate(
  78. feeds[i].id,
  79. uint64(publishTime),
  80. feeds[i].price.price,
  81. feeds[i].price.conf
  82. );
  83. }
  84. if (feeds[i].id == priceIds[i]) {
  85. if (
  86. minPublishTime <= publishTime &&
  87. publishTime <= maxPublishTime &&
  88. (!unique || prevPublishTime < minPublishTime)
  89. ) {
  90. break;
  91. } else {
  92. feeds[i].id = 0;
  93. }
  94. }
  95. }
  96. if (feeds[i].id != priceIds[i])
  97. revert PythErrors.PriceFeedNotFoundWithinRange();
  98. }
  99. }
  100. function parsePriceFeedUpdates(
  101. bytes[] calldata updateData,
  102. bytes32[] calldata priceIds,
  103. uint64 minPublishTime,
  104. uint64 maxPublishTime
  105. ) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
  106. return
  107. parsePriceFeedUpdatesInternal(
  108. updateData,
  109. priceIds,
  110. minPublishTime,
  111. maxPublishTime,
  112. false
  113. );
  114. }
  115. function parsePriceFeedUpdatesUnique(
  116. bytes[] calldata updateData,
  117. bytes32[] calldata priceIds,
  118. uint64 minPublishTime,
  119. uint64 maxPublishTime
  120. ) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
  121. return
  122. parsePriceFeedUpdatesInternal(
  123. updateData,
  124. priceIds,
  125. minPublishTime,
  126. maxPublishTime,
  127. true
  128. );
  129. }
  130. function createPriceFeedUpdateData(
  131. bytes32 id,
  132. int64 price,
  133. uint64 conf,
  134. int32 expo,
  135. int64 emaPrice,
  136. uint64 emaConf,
  137. uint64 publishTime,
  138. uint64 prevPublishTime
  139. ) public pure returns (bytes memory priceFeedData) {
  140. PythStructs.PriceFeed memory priceFeed;
  141. priceFeed.id = id;
  142. priceFeed.price.price = price;
  143. priceFeed.price.conf = conf;
  144. priceFeed.price.expo = expo;
  145. priceFeed.price.publishTime = publishTime;
  146. priceFeed.emaPrice.price = emaPrice;
  147. priceFeed.emaPrice.conf = emaConf;
  148. priceFeed.emaPrice.expo = expo;
  149. priceFeed.emaPrice.publishTime = publishTime;
  150. priceFeedData = abi.encode(priceFeed, prevPublishTime);
  151. }
  152. }