Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
25 changes: 17 additions & 8 deletions target_chains/ethereum/contracts/contracts/pyth/Pyth.sol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's bump the version() to 1.4.5-alpha.1

Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,17 @@ abstract contract Pyth is
return merkleData.numUpdates;
}

function parsePriceFeedUpdatesInternal(
function parsePriceFeedUpdatesWithConfig(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minAllowedPublishTime,
uint64 maxAllowedPublishTime,
bool checkUniqueness,
bool checkUpdateDataIsMinimal
bool checkUpdateDataIsMinimal,
bool storeUpdatesIfFresh
)
internal
public
payable
returns (
PythStructs.PriceFeed[] memory priceFeeds,
uint64[] memory slots
Expand Down Expand Up @@ -357,6 +359,10 @@ abstract contract Pyth is
updateData[i],
context
);
if (storeUpdatesIfFresh) {
bytes32 curPriceId = context.priceIds[i];
updateLatestPriceIfNecessary(curPriceId, _state.latestPriceInfo[curPriceId]);
}
}
}

Expand Down Expand Up @@ -389,13 +395,14 @@ abstract contract Pyth is
override
returns (PythStructs.PriceFeed[] memory priceFeeds)
{
(priceFeeds, ) = parsePriceFeedUpdatesInternal(
(priceFeeds, ) = parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false,
false
false,
true
);
}

Expand All @@ -414,12 +421,13 @@ abstract contract Pyth is
)
{
return
parsePriceFeedUpdatesInternal(
parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false,
true,
true
);
}
Expand Down Expand Up @@ -624,13 +632,14 @@ abstract contract Pyth is
override
returns (PythStructs.PriceFeed[] memory priceFeeds)
{
(priceFeeds, ) = parsePriceFeedUpdatesInternal(
(priceFeeds, ) = parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
true,
false
false,
true
);
}

Expand Down
31 changes: 31 additions & 0 deletions target_chains/ethereum/sdk/solidity/IPyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,37 @@ interface IPyth is IPythEvents {
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);

/// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
/// within `minPublishTime` and `maxPublishTime,` but choose to store price updates if `storeUpdatesIfFresh`.
///
/// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
/// otherwise, please consider using `updatePriceFeeds`. This method may store the price updates on-chain, if they
/// are more recent than the current stored prices.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
/// This method will eventually allow the caller to determine whether parsed price feeds should update
/// the stored values as well.
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minAllowedPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxAllowedPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @param storeUpdatesIfFresh flag for the parse function to
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdatesWithConfig(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minAllowedPublishTime,
uint64 maxAllowedPublishTime,
bool checkUniqueness,
bool checkUpdateDataIsMinimal,
bool storeUpdatesIfFresh
) external payable returns ( PythStructs.PriceFeed[] memory priceFeeds, uint64[] memory slots);

/// @notice Parse time-weighted average price (TWAP) from two consecutive price updates for the given `priceIds`.
///
/// This method calculates TWAP between two data points by processing the difference in cumulative price values
Expand Down
50 changes: 31 additions & 19 deletions target_chains/ethereum/sdk/solidity/MockPyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,21 @@ contract MockPyth is AbstractPyth {
return singleUpdateFeeInWei * updateData.length;
}

function parsePriceFeedUpdatesInternal(
function parsePriceFeedUpdatesWithConfig(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime,
bool unique
uint64 minAllowedPublishTime,
uint64 maxAllowedPublishTime,
bool checkUniqueness,
bool checkUpdateDataIsMinimal,
bool storeUpdatesIfFresh
)
internal
returns (PythStructs.PriceFeed[] memory feeds, uint64[] memory slots)
public
payable
returns (
PythStructs.PriceFeed[] memory feeds,
uint64[] memory slots
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this is a little confusing as a public API since it exposes lots of options (prone to misconfiguration) and also returns data most people won't need (slots). Might be better to keep this as a private method and expose public APIs targeted at specific use cases. The only thing using storeUpdatesIfFresh would be Pulse via parsePriceFeedUpdatesWithSlotsStrict, so we could expose the storeUpdatesIfFresh param there. Curious on your thoughts on this @ali-bahjati .

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm I think the practice I've seen elsewhere is a combination of both. You'd keep easy to understand shortcuts for people but one that is not often used (likely we only use it ourselves) because at the same time making API for every combo is not good (it comes more as confusing to people).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it makes sense. lets make sure to include a note in the natspec doc that it's recommended in most cases to use the standard parsePriceFeedUpdates or parsePriceFeedUpdatesStrict methods.

{
uint requiredFee = getUpdateFee(updateData);
if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
Expand Down Expand Up @@ -124,9 +130,9 @@ contract MockPyth is AbstractPyth {

if (feeds[i].id == priceIds[i]) {
if (
minPublishTime <= publishTime &&
publishTime <= maxPublishTime &&
(!unique || prevPublishTime < minPublishTime)
minAllowedPublishTime <= publishTime &&
publishTime <= maxAllowedPublishTime &&
(!checkUniqueness || prevPublishTime < minAllowedPublishTime)
) {
break;
} else {
Expand All @@ -146,12 +152,14 @@ contract MockPyth is AbstractPyth {
uint64 minPublishTime,
uint64 maxPublishTime
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
(feeds, ) = parsePriceFeedUpdatesInternal(
(feeds, ) = parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false
false,
true,
true
);
}

Expand All @@ -161,11 +169,13 @@ contract MockPyth is AbstractPyth {
uint64 minPublishTime,
uint64 maxPublishTime
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
(feeds, ) = parsePriceFeedUpdatesInternal(
(feeds, ) = parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false,
true,
true
);
}
Expand All @@ -182,13 +192,15 @@ contract MockPyth is AbstractPyth {
returns (PythStructs.PriceFeed[] memory feeds, uint64[] memory slots)
{
return
parsePriceFeedUpdatesInternal(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false
);
parsePriceFeedUpdatesWithConfig(
updateData,
priceIds,
minPublishTime,
maxPublishTime,
false,
true,
true
);
}

function parseTwapPriceFeedUpdates(
Expand Down
115 changes: 115 additions & 0 deletions target_chains/ethereum/sdk/solidity/abis/IPyth.json
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,121 @@
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes[]",
"name": "updateData",
"type": "bytes[]"
},
{
"internalType": "bytes32[]",
"name": "priceIds",
"type": "bytes32[]"
},
{
"internalType": "uint64",
"name": "minAllowedPublishTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "maxAllowedPublishTime",
"type": "uint64"
},
{
"internalType": "bool",
"name": "checkUniqueness",
"type": "bool"
},
{
"internalType": "bool",
"name": "checkUpdateDataIsMinimal",
"type": "bool"
},
{
"internalType": "bool",
"name": "storeUpdatesIfFresh",
"type": "bool"
}
],
"name": "parsePriceFeedUpdatesWithConfig",
"outputs": [
{
"components": [
{
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
},
{
"components": [
{
"internalType": "int64",
"name": "price",
"type": "int64"
},
{
"internalType": "uint64",
"name": "conf",
"type": "uint64"
},
{
"internalType": "int32",
"name": "expo",
"type": "int32"
},
{
"internalType": "uint256",
"name": "publishTime",
"type": "uint256"
}
],
"internalType": "struct PythStructs.Price",
"name": "price",
"type": "tuple"
},
{
"components": [
{
"internalType": "int64",
"name": "price",
"type": "int64"
},
{
"internalType": "uint64",
"name": "conf",
"type": "uint64"
},
{
"internalType": "int32",
"name": "expo",
"type": "int32"
},
{
"internalType": "uint256",
"name": "publishTime",
"type": "uint256"
}
],
"internalType": "struct PythStructs.Price",
"name": "emaPrice",
"type": "tuple"
}
],
"internalType": "struct PythStructs.PriceFeed[]",
"name": "priceFeeds",
"type": "tuple[]"
},
{
"internalType": "uint64[]",
"name": "slots",
"type": "uint64[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
Loading