Skip to content
This repository was archived by the owner on May 6, 2025. It is now read-only.

Add Solidity prettier extension #33

Merged
merged 1 commit into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ repos:
- id: check-added-large-files
args: ["--maxkb=1024"]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v2.6.2"
rev: "v2.7.1"
hooks:
- id: prettier
additional_dependencies:
- "prettier@2.7.1"
- "prettier-plugin-solidity@1.0.0-rc.1"
85 changes: 64 additions & 21 deletions AbstractPyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,77 @@ abstract contract AbstractPyth is IPyth {
/// @notice Returns the price feed with given id.
/// @dev Reverts if the price does not exist.
/// @param id The Pyth Price Feed ID of which to fetch the PriceFeed.
function queryPriceFeed(bytes32 id) public view virtual returns (PythStructs.PriceFeed memory priceFeed);
function queryPriceFeed(
bytes32 id
) public view virtual returns (PythStructs.PriceFeed memory priceFeed);

/// @notice Returns true if a price feed with the given id exists.
/// @param id The Pyth Price Feed ID of which to check its existence.
function priceFeedExists(bytes32 id) public view virtual returns (bool exists);

function getValidTimePeriod() public view virtual override returns (uint validTimePeriod);

function getPrice(bytes32 id) external virtual view override returns (PythStructs.Price memory price) {
function priceFeedExists(
bytes32 id
) public view virtual returns (bool exists);

function getValidTimePeriod()
public
view
virtual
override
returns (uint validTimePeriod);

function getPrice(
bytes32 id
) external view virtual override returns (PythStructs.Price memory price) {
return getPriceNoOlderThan(id, getValidTimePeriod());
}

function getEmaPrice(bytes32 id) external virtual view override returns (PythStructs.Price memory price) {
function getEmaPrice(
bytes32 id
) external view virtual override returns (PythStructs.Price memory price) {
return getEmaPriceNoOlderThan(id, getValidTimePeriod());
}

function getPriceUnsafe(bytes32 id) public virtual view override returns (PythStructs.Price memory price) {
function getPriceUnsafe(
bytes32 id
) public view virtual override returns (PythStructs.Price memory price) {
PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id);
return priceFeed.price;
}

function getPriceNoOlderThan(bytes32 id, uint age) public virtual view override returns (PythStructs.Price memory price) {
function getPriceNoOlderThan(
bytes32 id,
uint age
) public view virtual override returns (PythStructs.Price memory price) {
price = getPriceUnsafe(id);

require(diff(block.timestamp, price.publishTime) <= age, "no price available which is recent enough");
require(
diff(block.timestamp, price.publishTime) <= age,
"no price available which is recent enough"
);

return price;
}

function getEmaPriceUnsafe(bytes32 id) public virtual view override returns (PythStructs.Price memory price) {
function getEmaPriceUnsafe(
bytes32 id
) public view virtual override returns (PythStructs.Price memory price) {
PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id);
return priceFeed.emaPrice;
}

function getEmaPriceNoOlderThan(bytes32 id, uint age) public virtual view override returns (PythStructs.Price memory price) {
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) public view virtual override returns (PythStructs.Price memory price) {
price = getEmaPriceUnsafe(id);

require(diff(block.timestamp, price.publishTime) <= age, "no ema price available which is recent enough");
require(
diff(block.timestamp, price.publishTime) <= age,
"no ema price available which is recent enough"
);

return price;
}


function diff(uint x, uint y) internal pure returns (uint) {
if (x > y) {
return x - y;
Expand All @@ -60,20 +88,35 @@ abstract contract AbstractPyth is IPyth {
}

// Access modifier is overridden to public to be able to call it locally.
function updatePriceFeeds(bytes[] calldata updateData) public virtual payable override;

function updatePriceFeedsIfNecessary(bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes) external virtual payable override {
require(priceIds.length == publishTimes.length, "priceIds and publishTimes arrays should have same length");
function updatePriceFeeds(
bytes[] calldata updateData
) public payable virtual override;

function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable virtual override {
require(
priceIds.length == publishTimes.length,
"priceIds and publishTimes arrays should have same length"
);

bool updateNeeded = false;
for(uint i = 0; i < priceIds.length; i++) {
if (!priceFeedExists(priceIds[i]) || queryPriceFeed(priceIds[i]).price.publishTime < publishTimes[i]) {
for (uint i = 0; i < priceIds.length; i++) {
if (
!priceFeedExists(priceIds[i]) ||
queryPriceFeed(priceIds[i]).price.publishTime < publishTimes[i]
) {
updateNeeded = true;
break;
}
}

require(updateNeeded, "no prices in the submitted batch have fresh prices, so this update will have no effect");
require(
updateNeeded,
"no prices in the submitted batch have fresh prices, so this update will have no effect"
);

updatePriceFeeds(updateData);
}
Expand Down
36 changes: 28 additions & 8 deletions IPyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ interface IPyth is IPythEvents {
/// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.
/// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPrice(bytes32 id) external view returns (PythStructs.Price memory price);
function getPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);

/// @notice Returns the exponentially-weighted moving average price and confidence interval.
/// @dev Reverts if the EMA price is not available.
/// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPrice(bytes32 id) external view returns (PythStructs.Price memory price);
function getEmaPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);

/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
Expand All @@ -31,14 +35,19 @@ interface IPyth is IPythEvents {
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);
function getPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);

/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(bytes32 id, uint age) external view returns (PythStructs.Price memory price);
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);

/// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
/// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
Expand All @@ -51,15 +60,20 @@ interface IPyth is IPythEvents {
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);
function getEmaPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);

/// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
/// of the current time.
/// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceNoOlderThan(bytes32 id, uint age) external view returns (PythStructs.Price memory price);
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);

/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
Expand All @@ -86,10 +100,16 @@ interface IPyth is IPythEvents {
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
function updatePriceFeedsIfNecessary(bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes) external payable;
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;

/// @notice Returns the required fee to update an array of price updates.
/// @param updateData Array of price update data.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(bytes[] calldata updateData) external view returns (uint feeAmount);
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
}
7 changes: 6 additions & 1 deletion IPythEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ interface IPythEvents {
/// @param publishTime Publish time of the given price update.
/// @param price Price of the given price update.
/// @param conf Confidence interval of the given price update.
event PriceFeedUpdate(bytes32 indexed id, uint64 publishTime, int64 price, uint64 conf);
event PriceFeedUpdate(
bytes32 indexed id,
uint64 publishTime,
int64 price,
uint64 conf
);

/// @dev Emitted when a batch price update is processed successfully.
/// @param chainId ID of the source chain that the batch price update comes from.
Expand Down
39 changes: 29 additions & 10 deletions MockPyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,61 @@ contract MockPyth is AbstractPyth {
validTimePeriod = _validTimePeriod;
}

function queryPriceFeed(bytes32 id) public override view returns (PythStructs.PriceFeed memory priceFeed) {
require(priceFeeds[id].id != 0, "no price feed found for the given price id");
function queryPriceFeed(
bytes32 id
) public view override returns (PythStructs.PriceFeed memory priceFeed) {
require(
priceFeeds[id].id != 0,
"no price feed found for the given price id"
);
return priceFeeds[id];
}

function priceFeedExists(bytes32 id) public override view returns (bool) {
function priceFeedExists(bytes32 id) public view override returns (bool) {
return (priceFeeds[id].id != 0);
}

function getValidTimePeriod() public override view returns (uint) {
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 createPriceFeedData or
// by using web3.js or ethers abi utilities.
function updatePriceFeeds(bytes[] calldata updateData) public override payable {
function updatePriceFeeds(
bytes[] calldata updateData
) public payable override {
uint requiredFee = getUpdateFee(updateData);
require(msg.value >= requiredFee, "Insufficient paid fee amount");

if (msg.value > requiredFee) {
(bool success, ) = payable(msg.sender).call{value: msg.value - requiredFee}("");
(bool success, ) = payable(msg.sender).call{
value: msg.value - requiredFee
}("");
require(success, "failed to transfer update fee");
}

// 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));
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);
emit PriceFeedUpdate(
priceFeed.id,
uint64(lastPublishTime),
priceFeed.price.price,
priceFeed.price.conf
);
}
}

Expand All @@ -64,7 +81,9 @@ contract MockPyth is AbstractPyth {
sequenceNumber += 1;
}

function getUpdateFee(bytes[] calldata updateData) public override view returns (uint feeAmount) {
function getUpdateFee(
bytes[] calldata updateData
) public view override returns (uint feeAmount) {
return singleUpdateFeeInWei * updateData.length;
}

Expand Down
1 change: 0 additions & 1 deletion PythStructs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.0;

contract PythStructs {

// A price with a degree of uncertainty, represented as a price +- a confidence interval.
//
// The confidence interval roughly corresponds to the standard error of a normal distribution.
Expand Down
41 changes: 22 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,29 @@ import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";

contract ExampleContract {
IPyth pyth;

constructor(address pythContract) {
pyth = IPyth(pythContract);
}

function getBTCUSDPrice(bytes[] calldata priceUpdateData) public returns (PythStructs.Price memory) {
// Update the prices to the latest available values and pay the required fee for it. The `priceUpdateData` data
// should be retrieved from our off-chain Price Service API using the `pyth-evm-js` package.
// See section "How Pyth Works on EVM Chains" below for more information.
uint fee = pyth.getUpdateFee(priceUpdateData);
pyth.updatePriceFeeds{value: fee}(priceUpdateData);

bytes32 priceID = 0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b;
// Read the current value of priceID, aborting the transaction if the price has not been updated recently.
// Every chain has a default recency threshold which can be retrieved by calling the getValidTimePeriod() function on the contract.
// Please see IPyth.sol for variants of this function that support configurable recency thresholds and other useful features.
return pyth.getPrice(priceID);
}
IPyth pyth;

constructor(address pythContract) {
pyth = IPyth(pythContract);
}

function getBTCUSDPrice(
bytes[] calldata priceUpdateData
) public returns (PythStructs.Price memory) {
// Update the prices to the latest available values and pay the required fee for it. The `priceUpdateData` data
// should be retrieved from our off-chain Price Service API using the `pyth-evm-js` package.
// See section "How Pyth Works on EVM Chains" below for more information.
uint fee = pyth.getUpdateFee(priceUpdateData);
pyth.updatePriceFeeds{ value: fee }(priceUpdateData);

bytes32 priceID = 0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b;
// Read the current value of priceID, aborting the transaction if the price has not been updated recently.
// Every chain has a default recency threshold which can be retrieved by calling the getValidTimePeriod() function on the contract.
// Please see IPyth.sol for variants of this function that support configurable recency thresholds and other useful features.
return pyth.getPrice(priceID);
}
}

```

## How Pyth Works on EVM Chains
Expand Down
Loading