| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- // contracts/Bridge.sol
- // SPDX-License-Identifier: Apache 2
- pragma solidity ^0.8.0;
- import "../libraries/external/BytesLib.sol";
- import "./PythGetters.sol";
- import "./PythSetters.sol";
- import "./PythStructs.sol";
- import "./PythGovernance.sol";
- contract Pyth is PythGovernance {
- using BytesLib for bytes;
- function attestPrice(bytes memory encodedVm) public returns (PythStructs.PriceAttestation memory pa) {
- (IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
- require(valid, reason);
- require(verifyPythVM(vm), "invalid emitter");
- PythStructs.PriceAttestation memory price = parsePriceAttestation(vm.payload);
- PythStructs.PriceAttestation memory latestPrice = latestAttestation(price.productId, price.priceType);
- if(price.timestamp > latestPrice.timestamp) {
- setLatestAttestation(price.productId, price.priceType, price);
- }
- return price;
- }
- function verifyPythVM(IWormhole.VM memory vm) public view returns (bool valid) {
- if (vm.emitterChainId != pyth2WormholeChainId()) {
- return false;
- }
- if (vm.emitterAddress != pyth2WormholeEmitter()) {
- return false;
- }
- return true;
- }
-
- function parseBatchPriceAttestation(bytes memory encoded) public pure returns (PythStructs.BatchPriceAttestation memory bpa) {
- uint index = 0;
- // Check header
- bpa.header.magic = encoded.toUint32(index);
- index += 4;
- require(bpa.header.magic == 0x50325748, "invalid magic value");
- bpa.header.version = encoded.toUint16(index);
- index += 2;
- require(bpa.header.version == 2, "invalid version");
- bpa.header.payloadId = encoded.toUint8(index);
- index += 1;
- // Payload ID of 2 required for batch header
- require(bpa.header.payloadId == 2, "invalid payload ID");
- // Parse the number of attestations
- bpa.nAttestations = encoded.toUint16(index);
- index += 2;
- // Parse the attestation size
- bpa.attestationSize = encoded.toUint16(index);
- index += 2;
- require(encoded.length == (index + (bpa.attestationSize * bpa.nAttestations)), "invalid BatchPriceAttestation size");
- bpa.attestations = new PythStructs.PriceAttestation[](bpa.nAttestations);
- // Deserialize each attestation
- for (uint j=0; j < bpa.nAttestations; j++) {
- // Header
- bpa.attestations[j].header.magic = encoded.toUint32(index);
- index += 4;
- require(bpa.attestations[j].header.magic == 0x50325748, "invalid magic value");
- bpa.attestations[j].header.version = encoded.toUint16(index);
- index += 2;
- require(bpa.attestations[j].header.version == 2, "invalid version");
- bpa.attestations[j].header.payloadId = encoded.toUint8(index);
- index += 1;
- // Payload ID of 1 required for individual attestation
- require(bpa.attestations[j].header.payloadId == 1, "invalid payload ID");
- // Attestation
- bpa.attestations[j].productId = encoded.toBytes32(index);
- index += 32;
- bpa.attestations[j].priceId = encoded.toBytes32(index);
- index += 32;
- bpa.attestations[j].priceType = encoded.toUint8(index);
- index += 1;
- bpa.attestations[j].price = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].exponent = int32(encoded.toUint32(index));
- index += 4;
- bpa.attestations[j].emaPrice.value = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].emaPrice.numerator = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].emaPrice.denominator = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].emaConf.value = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].emaConf.numerator = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].emaConf.denominator = int64(encoded.toUint64(index));
- index += 8;
- bpa.attestations[j].confidenceInterval = encoded.toUint64(index);
- index += 8;
- bpa.attestations[j].status = encoded.toUint8(index);
- index += 1;
- bpa.attestations[j].corpAct = encoded.toUint8(index);
- index += 1;
- bpa.attestations[j].timestamp = encoded.toUint64(index);
- index += 8;
- }
- }
- function parsePriceAttestation(bytes memory encodedPriceAttestation) public pure returns (PythStructs.PriceAttestation memory pa) {
- uint index = 0;
- pa.header.magic = encodedPriceAttestation.toUint32(index);
- index += 4;
- require(pa.header.magic == 0x50325748, "invalid protocol");
- pa.header.version = encodedPriceAttestation.toUint16(index);
- index += 2;
- require(pa.header.version == 1, "invalid protocol");
- pa.header.payloadId = encodedPriceAttestation.toUint8(index);
- index += 1;
- require(pa.header.payloadId == 1, "invalid PriceAttestation");
- pa.productId = encodedPriceAttestation.toBytes32(index);
- index += 32;
- pa.priceId = encodedPriceAttestation.toBytes32(index);
- index += 32;
- pa.priceType = encodedPriceAttestation.toUint8(index);
- index += 1;
- pa.price = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.exponent = int32(encodedPriceAttestation.toUint32(index));
- index += 4;
- pa.emaPrice.value = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.emaPrice.numerator = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.emaPrice.denominator = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.emaConf.value = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.emaConf.numerator = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.emaConf.denominator = int64(encodedPriceAttestation.toUint64(index));
- index += 8;
- pa.confidenceInterval = encodedPriceAttestation.toUint64(index);
- index += 8;
- pa.status = encodedPriceAttestation.toUint8(index);
- index += 1;
- pa.corpAct = encodedPriceAttestation.toUint8(index);
- index += 1;
- pa.timestamp = encodedPriceAttestation.toUint64(index);
- index += 8;
- require(encodedPriceAttestation.length == index, "invalid PriceAttestation");
- }
- }
|