140 lines
4.8 KiB
Solidity
140 lines
4.8 KiB
Solidity
// SPDX-License-Identifier: Apache-2.0
|
|
pragma solidity ^0.8.0;
|
|
|
|
import "./AbstractPyth.sol";
|
|
import "./PythStructs.sol";
|
|
import "./PythErrors.sol";
|
|
|
|
contract MockPyth is AbstractPyth {
|
|
mapping(bytes32 => PythStructs.PriceFeed) priceFeeds;
|
|
uint64 sequenceNumber;
|
|
|
|
uint singleUpdateFeeInWei;
|
|
uint validTimePeriod;
|
|
|
|
constructor(uint _validTimePeriod, uint _singleUpdateFeeInWei) {
|
|
singleUpdateFeeInWei = _singleUpdateFeeInWei;
|
|
validTimePeriod = _validTimePeriod;
|
|
}
|
|
|
|
function queryPriceFeed(
|
|
bytes32 id
|
|
) public view override returns (PythStructs.PriceFeed memory priceFeed) {
|
|
if (priceFeeds[id].id == 0) revert PythErrors.PriceFeedNotFound();
|
|
return priceFeeds[id];
|
|
}
|
|
|
|
function priceFeedExists(bytes32 id) public view override returns (bool) {
|
|
return (priceFeeds[id].id != 0);
|
|
}
|
|
|
|
function getValidTimePeriod() public view override returns (uint) {
|
|
return validTimePeriod;
|
|
}
|
|
|
|
// Takes an array of encoded price feeds and stores them.
|
|
// You can create this data either by calling createPriceFeedUpdateData or
|
|
// by using web3.js or ethers abi utilities.
|
|
function updatePriceFeeds(
|
|
bytes[] calldata updateData
|
|
) public payable override {
|
|
uint requiredFee = getUpdateFee(updateData);
|
|
if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
|
|
|
|
// Chain ID is id of the source chain that the price update comes from. Since it is just a mock contract
|
|
// We set it to 1.
|
|
uint16 chainId = 1;
|
|
|
|
for (uint i = 0; i < updateData.length; i++) {
|
|
PythStructs.PriceFeed memory priceFeed = abi.decode(
|
|
updateData[i],
|
|
(PythStructs.PriceFeed)
|
|
);
|
|
|
|
uint lastPublishTime = priceFeeds[priceFeed.id].price.publishTime;
|
|
|
|
if (lastPublishTime < priceFeed.price.publishTime) {
|
|
// Price information is more recent than the existing price information.
|
|
priceFeeds[priceFeed.id] = priceFeed;
|
|
emit PriceFeedUpdate(
|
|
priceFeed.id,
|
|
uint64(lastPublishTime),
|
|
priceFeed.price.price,
|
|
priceFeed.price.conf
|
|
);
|
|
}
|
|
}
|
|
|
|
// In the real contract, the input of this function contains multiple batches that each contain multiple prices.
|
|
// This event is emitted when a batch is processed. In this mock contract we consider there is only one batch of prices.
|
|
// Each batch has (chainId, sequenceNumber) as it's unique identifier. Here chainId is set to 1 and an increasing sequence number is used.
|
|
emit BatchPriceFeedUpdate(chainId, sequenceNumber);
|
|
sequenceNumber += 1;
|
|
}
|
|
|
|
function getUpdateFee(
|
|
bytes[] calldata updateData
|
|
) public view override returns (uint feeAmount) {
|
|
return singleUpdateFeeInWei * updateData.length;
|
|
}
|
|
|
|
function parsePriceFeedUpdates(
|
|
bytes[] calldata updateData,
|
|
bytes32[] calldata priceIds,
|
|
uint64 minPublishTime,
|
|
uint64 maxPublishTime
|
|
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
|
|
uint requiredFee = getUpdateFee(updateData);
|
|
if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
|
|
|
|
feeds = new PythStructs.PriceFeed[](priceIds.length);
|
|
|
|
for (uint i = 0; i < priceIds.length; i++) {
|
|
for (uint j = 0; j < updateData.length; j++) {
|
|
feeds[i] = abi.decode(updateData[j], (PythStructs.PriceFeed));
|
|
|
|
if (feeds[i].id == priceIds[i]) {
|
|
uint publishTime = feeds[i].price.publishTime;
|
|
if (
|
|
minPublishTime <= publishTime &&
|
|
publishTime <= maxPublishTime
|
|
) {
|
|
break;
|
|
} else {
|
|
feeds[i].id = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (feeds[i].id != priceIds[i])
|
|
revert PythErrors.PriceFeedNotFoundWithinRange();
|
|
}
|
|
}
|
|
|
|
function createPriceFeedUpdateData(
|
|
bytes32 id,
|
|
int64 price,
|
|
uint64 conf,
|
|
int32 expo,
|
|
int64 emaPrice,
|
|
uint64 emaConf,
|
|
uint64 publishTime
|
|
) public pure returns (bytes memory priceFeedData) {
|
|
PythStructs.PriceFeed memory priceFeed;
|
|
|
|
priceFeed.id = id;
|
|
|
|
priceFeed.price.price = price;
|
|
priceFeed.price.conf = conf;
|
|
priceFeed.price.expo = expo;
|
|
priceFeed.price.publishTime = publishTime;
|
|
|
|
priceFeed.emaPrice.price = emaPrice;
|
|
priceFeed.emaPrice.conf = emaConf;
|
|
priceFeed.emaPrice.expo = expo;
|
|
priceFeed.emaPrice.publishTime = publishTime;
|
|
|
|
priceFeedData = abi.encode(priceFeed);
|
|
}
|
|
}
|