Pyth.sol 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // contracts/Bridge.sol
  2. // SPDX-License-Identifier: Apache 2
  3. pragma solidity ^0.8.0;
  4. import "../libraries/external/BytesLib.sol";
  5. import "./PythGetters.sol";
  6. import "./PythSetters.sol";
  7. import "./PythStructs.sol";
  8. import "./PythGovernance.sol";
  9. contract Pyth is PythGovernance {
  10. using BytesLib for bytes;
  11. function attestPrice(bytes memory encodedVm) public returns (PythStructs.PriceAttestation memory pa) {
  12. (IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
  13. require(valid, reason);
  14. require(verifyPythVM(vm), "invalid emitter");
  15. PythStructs.PriceAttestation memory price = parsePriceAttestation(vm.payload);
  16. PythStructs.PriceAttestation memory latestPrice = latestAttestation(price.productId, price.priceType);
  17. if(price.timestamp > latestPrice.timestamp) {
  18. setLatestAttestation(price.productId, price.priceType, price);
  19. }
  20. return price;
  21. }
  22. function verifyPythVM(IWormhole.VM memory vm) public view returns (bool valid) {
  23. if (vm.emitterChainId != pyth2WormholeChainId()) {
  24. return false;
  25. }
  26. if (vm.emitterAddress != pyth2WormholeEmitter()) {
  27. return false;
  28. }
  29. return true;
  30. }
  31. function parsePriceAttestation(bytes memory encodedPriceAttestation) public pure returns (PythStructs.PriceAttestation memory pa) {
  32. uint index = 0;
  33. pa.magic = encodedPriceAttestation.toUint32(index);
  34. index += 4;
  35. require(pa.magic == 0x50325748, "invalid protocol");
  36. pa.version = encodedPriceAttestation.toUint16(index);
  37. index += 2;
  38. require(pa.version == 1, "invalid protocol");
  39. pa.payloadId = encodedPriceAttestation.toUint8(index);
  40. index += 1;
  41. require(pa.payloadId == 1, "invalid PriceAttestation");
  42. pa.productId = encodedPriceAttestation.toBytes32(index);
  43. index += 32;
  44. pa.priceId = encodedPriceAttestation.toBytes32(index);
  45. index += 32;
  46. pa.priceType = encodedPriceAttestation.toUint8(index);
  47. index += 1;
  48. pa.price = int64(encodedPriceAttestation.toUint64(index));
  49. index += 8;
  50. pa.exponent = int32(encodedPriceAttestation.toUint32(index));
  51. index += 4;
  52. pa.twap.value = int64(encodedPriceAttestation.toUint64(index));
  53. index += 8;
  54. pa.twap.numerator = int64(encodedPriceAttestation.toUint64(index));
  55. index += 8;
  56. pa.twap.denominator = int64(encodedPriceAttestation.toUint64(index));
  57. index += 8;
  58. pa.twac.value = int64(encodedPriceAttestation.toUint64(index));
  59. index += 8;
  60. pa.twac.numerator = int64(encodedPriceAttestation.toUint64(index));
  61. index += 8;
  62. pa.twac.denominator = int64(encodedPriceAttestation.toUint64(index));
  63. index += 8;
  64. pa.confidenceInterval = encodedPriceAttestation.toUint64(index);
  65. index += 8;
  66. pa.status = encodedPriceAttestation.toUint8(index);
  67. index += 1;
  68. pa.corpAct = encodedPriceAttestation.toUint8(index);
  69. index += 1;
  70. pa.timestamp = encodedPriceAttestation.toUint64(index);
  71. index += 8;
  72. require(encodedPriceAttestation.length == index, "invalid PriceAttestation");
  73. }
  74. }