[evm] parsePriceFeed with uniqueness validation (#1089)
* Implement uniqueness * Add tests and update abi * Fix MockPyth for the unique version * Bump version * Add gas benchmark functions
This commit is contained in:
parent
d11216f309
commit
eb9526675c
|
@ -58545,7 +58545,7 @@
|
|||
},
|
||||
"target_chains/ethereum/contracts": {
|
||||
"name": "@pythnetwork/pyth-evm-contract",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.22",
|
||||
|
@ -59572,7 +59572,7 @@
|
|||
},
|
||||
"target_chains/ethereum/sdk/solidity": {
|
||||
"name": "@pythnetwork/pyth-sdk-solidity",
|
||||
"version": "2.2.1",
|
||||
"version": "2.3.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
|
|
|
@ -440,17 +440,11 @@ abstract contract Pyth is
|
|||
if (!verifyPythVM(vm)) revert PythErrors.InvalidUpdateDataSource();
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdates(
|
||||
function parsePriceFeedUpdatesInternal(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
)
|
||||
external
|
||||
payable
|
||||
override
|
||||
returns (PythStructs.PriceFeed[] memory priceFeeds)
|
||||
{
|
||||
PythInternalStructs.ParseConfig memory config
|
||||
) internal returns (PythStructs.PriceFeed[] memory priceFeeds) {
|
||||
{
|
||||
uint requiredFee = getUpdateFee(updateData);
|
||||
if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
|
||||
|
@ -494,10 +488,12 @@ abstract contract Pyth is
|
|||
for (uint j = 0; j < numUpdates; j++) {
|
||||
PythInternalStructs.PriceInfo memory info;
|
||||
bytes32 priceId;
|
||||
uint64 prevPublishTime;
|
||||
(
|
||||
offset,
|
||||
info,
|
||||
priceId
|
||||
priceId,
|
||||
prevPublishTime
|
||||
) = extractPriceInfoFromMerkleProof(
|
||||
digest,
|
||||
encoded,
|
||||
|
@ -519,8 +515,10 @@ abstract contract Pyth is
|
|||
// If is not, default id value of 0 will still be set and
|
||||
// this will allow other updates for this price id to be processed.
|
||||
if (
|
||||
publishTime >= minPublishTime &&
|
||||
publishTime <= maxPublishTime
|
||||
publishTime >= config.minPublishTime &&
|
||||
publishTime <= config.maxPublishTime &&
|
||||
(!config.checkUniqueness ||
|
||||
config.minPublishTime > prevPublishTime)
|
||||
) {
|
||||
fillPriceFeedFromPriceInfo(
|
||||
priceFeeds,
|
||||
|
@ -592,8 +590,9 @@ abstract contract Pyth is
|
|||
// If is not, default id value of 0 will still be set and
|
||||
// this will allow other updates for this price id to be processed.
|
||||
if (
|
||||
publishTime >= minPublishTime &&
|
||||
publishTime <= maxPublishTime
|
||||
publishTime >= config.minPublishTime &&
|
||||
publishTime <= config.maxPublishTime &&
|
||||
!config.checkUniqueness // do not allow batch updates to be used by parsePriceFeedUpdatesUnique
|
||||
) {
|
||||
fillPriceFeedFromPriceInfo(
|
||||
priceFeeds,
|
||||
|
@ -617,6 +616,52 @@ abstract contract Pyth is
|
|||
}
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdates(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
)
|
||||
external
|
||||
payable
|
||||
override
|
||||
returns (PythStructs.PriceFeed[] memory priceFeeds)
|
||||
{
|
||||
return
|
||||
parsePriceFeedUpdatesInternal(
|
||||
updateData,
|
||||
priceIds,
|
||||
PythInternalStructs.ParseConfig(
|
||||
minPublishTime,
|
||||
maxPublishTime,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdatesUnique(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
)
|
||||
external
|
||||
payable
|
||||
override
|
||||
returns (PythStructs.PriceFeed[] memory priceFeeds)
|
||||
{
|
||||
return
|
||||
parsePriceFeedUpdatesInternal(
|
||||
updateData,
|
||||
priceIds,
|
||||
PythInternalStructs.ParseConfig(
|
||||
minPublishTime,
|
||||
maxPublishTime,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getTotalFee(
|
||||
uint totalNumUpdates
|
||||
) private view returns (uint requiredFee) {
|
||||
|
@ -682,6 +727,6 @@ abstract contract Pyth is
|
|||
}
|
||||
|
||||
function version() public pure returns (string memory) {
|
||||
return "1.3.1";
|
||||
return "1.3.2";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,8 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
|
|||
returns (
|
||||
uint endOffset,
|
||||
PythInternalStructs.PriceInfo memory priceInfo,
|
||||
bytes32 priceId
|
||||
bytes32 priceId,
|
||||
uint64 prevPublishTime
|
||||
)
|
||||
{
|
||||
unchecked {
|
||||
|
@ -257,12 +258,15 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
|
|||
UnsafeCalldataBytesLib.toUint8(encodedMessage, 0)
|
||||
);
|
||||
if (messageType == MessageType.PriceFeed) {
|
||||
(priceInfo, priceId) = parsePriceFeedMessage(encodedMessage, 1);
|
||||
(priceInfo, priceId, prevPublishTime) = parsePriceFeedMessage(
|
||||
encodedMessage,
|
||||
1
|
||||
);
|
||||
} else {
|
||||
revert PythErrors.InvalidUpdateData();
|
||||
}
|
||||
|
||||
return (endOffset, priceInfo, priceId);
|
||||
return (endOffset, priceInfo, priceId, prevPublishTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +278,8 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
|
|||
pure
|
||||
returns (
|
||||
PythInternalStructs.PriceInfo memory priceInfo,
|
||||
bytes32 priceId
|
||||
bytes32 priceId,
|
||||
uint64 prevPublishTime
|
||||
)
|
||||
{
|
||||
unchecked {
|
||||
|
@ -311,7 +316,7 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
|
|||
offset += 8;
|
||||
|
||||
// We do not store this field because it is not used on the latest feed queries.
|
||||
// uint64 prevPublishTime = UnsafeBytesLib.toUint64(encodedPriceFeed, offset);
|
||||
prevPublishTime = UnsafeBytesLib.toUint64(encodedPriceFeed, offset);
|
||||
offset += 8;
|
||||
|
||||
priceInfo.emaPrice = int64(
|
||||
|
@ -359,11 +364,13 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
|
|||
for (uint i = 0; i < numUpdates; i++) {
|
||||
PythInternalStructs.PriceInfo memory priceInfo;
|
||||
bytes32 priceId;
|
||||
(offset, priceInfo, priceId) = extractPriceInfoFromMerkleProof(
|
||||
digest,
|
||||
encoded,
|
||||
offset
|
||||
);
|
||||
uint64 prevPublishTime;
|
||||
(
|
||||
offset,
|
||||
priceInfo,
|
||||
priceId,
|
||||
prevPublishTime
|
||||
) = extractPriceInfoFromMerkleProof(digest, encoded, offset);
|
||||
uint64 latestPublishTime = latestPriceInfoPublishTime(priceId);
|
||||
if (priceInfo.publishTime > latestPublishTime) {
|
||||
setLatestPriceInfo(priceId, priceInfo);
|
||||
|
|
|
@ -9,6 +9,12 @@ import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
|
|||
contract PythInternalStructs {
|
||||
using BytesLib for bytes;
|
||||
|
||||
struct ParseConfig {
|
||||
uint64 minPublishTime;
|
||||
uint64 maxPublishTime;
|
||||
bool checkUniqueness;
|
||||
}
|
||||
|
||||
struct PriceInfo {
|
||||
// slot 1
|
||||
uint64 publishTime;
|
||||
|
|
|
@ -65,7 +65,7 @@ contract GasBenchmark is Test, WormholeTestUtils, PythTestUtils {
|
|||
}
|
||||
|
||||
for (uint i = 0; i < NUM_PRICES; ++i) {
|
||||
uint64 publishTime = uint64(getRand() % 10);
|
||||
uint64 publishTime = uint64(getRand() % 10) + 1; // to make sure prevPublishTime is >= 0
|
||||
|
||||
cachedPrices.push(
|
||||
PythStructs.Price(
|
||||
|
@ -274,6 +274,37 @@ contract GasBenchmark is Test, WormholeTestUtils, PythTestUtils {
|
|||
);
|
||||
}
|
||||
|
||||
function testBenchmarkParsePriceFeedUpdatesUniqueForWhMerkle() public {
|
||||
bytes32[] memory ids = new bytes32[](1);
|
||||
ids[0] = priceIds[0];
|
||||
|
||||
pyth.parsePriceFeedUpdatesUnique{
|
||||
value: freshPricesWhMerkleUpdateFee[0]
|
||||
}(
|
||||
freshPricesWhMerkleUpdateData[0],
|
||||
ids,
|
||||
uint64(freshPrices[0].publishTime),
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
function testBenchmarkParsePriceFeedUpdatesUniqueWhMerkleForOnePriceFeedNotWithinRange()
|
||||
public
|
||||
{
|
||||
bytes32[] memory ids = new bytes32[](1);
|
||||
ids[0] = priceIds[0];
|
||||
|
||||
vm.expectRevert(PythErrors.PriceFeedNotFoundWithinRange.selector);
|
||||
pyth.parsePriceFeedUpdatesUnique{
|
||||
value: freshPricesWhMerkleUpdateFee[0]
|
||||
}(
|
||||
freshPricesWhMerkleUpdateData[0],
|
||||
ids,
|
||||
uint64(freshPrices[0].publishTime) - 1,
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
function testBenchmarkParsePriceFeedUpdatesForWhMerkle1() public {
|
||||
uint numIds = 1;
|
||||
|
||||
|
|
|
@ -418,7 +418,7 @@ contract PythWormholeMerkleAccumulatorTest is
|
|||
assertPriceFeedMessageStored(priceFeedMessages1[0]);
|
||||
}
|
||||
|
||||
function testParsePriceFeedUpdatesWithWormholeMerklWorksWithOurOfOrderUpdateMultiCall()
|
||||
function testParsePriceFeedUpdatesWithWormholeMerkleWorksWithOutOfOrderUpdateMultiCall()
|
||||
public
|
||||
{
|
||||
PriceFeedMessage[]
|
||||
|
@ -851,6 +851,53 @@ contract PythWormholeMerkleAccumulatorTest is
|
|||
}
|
||||
}
|
||||
|
||||
function testParsePriceFeedUniqueWithWormholeMerkleWorks(uint seed) public {
|
||||
setRandSeed(seed);
|
||||
|
||||
uint numPriceFeeds = (getRandUint() % 10) + 1;
|
||||
PriceFeedMessage[]
|
||||
memory priceFeedMessages = generateRandomPriceFeedMessage(
|
||||
numPriceFeeds
|
||||
);
|
||||
uint64 publishTime = getRandUint64();
|
||||
bytes32[] memory priceIds = new bytes32[](1);
|
||||
priceIds[0] = priceFeedMessages[0].priceId;
|
||||
for (uint i = 0; i < numPriceFeeds; i++) {
|
||||
priceFeedMessages[i].priceId = priceFeedMessages[0].priceId;
|
||||
priceFeedMessages[i].publishTime = publishTime;
|
||||
priceFeedMessages[i].prevPublishTime = publishTime;
|
||||
}
|
||||
uint firstUpdate = (getRandUint() % numPriceFeeds);
|
||||
priceFeedMessages[firstUpdate].prevPublishTime = publishTime - 1;
|
||||
(
|
||||
bytes[] memory updateData,
|
||||
uint updateFee
|
||||
) = createWormholeMerkleUpdateData(priceFeedMessages);
|
||||
|
||||
vm.expectRevert(PythErrors.PriceFeedNotFoundWithinRange.selector);
|
||||
PythStructs.PriceFeed[] memory priceFeeds = pyth
|
||||
.parsePriceFeedUpdatesUnique{value: updateFee}(
|
||||
updateData,
|
||||
priceIds,
|
||||
publishTime - 1,
|
||||
MAX_UINT64
|
||||
);
|
||||
|
||||
priceFeeds = pyth.parsePriceFeedUpdatesUnique{value: updateFee}(
|
||||
updateData,
|
||||
priceIds,
|
||||
publishTime,
|
||||
MAX_UINT64
|
||||
);
|
||||
assertEq(priceFeeds.length, 1);
|
||||
|
||||
assertParsedPriceFeedEqualsMessage(
|
||||
priceFeeds[0],
|
||||
priceFeedMessages[firstUpdate],
|
||||
priceIds[0]
|
||||
);
|
||||
}
|
||||
|
||||
function testParsePriceFeedWithWormholeMerkleWorksRandomDistinctUpdatesInput(
|
||||
uint seed
|
||||
) public {
|
||||
|
|
|
@ -354,6 +354,9 @@ abstract contract PythTestUtils is Test, WormholeTestUtils {
|
|||
priceFeedMessages[i].conf = prices[i].conf;
|
||||
priceFeedMessages[i].expo = prices[i].expo;
|
||||
priceFeedMessages[i].publishTime = uint64(prices[i].publishTime);
|
||||
priceFeedMessages[i].prevPublishTime =
|
||||
uint64(prices[i].publishTime) -
|
||||
1;
|
||||
priceFeedMessages[i].emaPrice = prices[i].price;
|
||||
priceFeedMessages[i].emaConf = prices[i].conf;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@pythnetwork/pyth-evm-contract",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4.0",
|
||||
"description": "",
|
||||
"private": "true",
|
||||
"devDependencies": {
|
||||
|
@ -25,7 +25,7 @@
|
|||
"coverage": "./coverage.sh"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.22",
|
||||
"@matterlabs/hardhat-zksync-deploy": "^0.6.2",
|
||||
|
|
|
@ -121,4 +121,16 @@ abstract contract AbstractPyth is IPyth {
|
|||
virtual
|
||||
override
|
||||
returns (PythStructs.PriceFeed[] memory priceFeeds);
|
||||
|
||||
function parsePriceFeedUpdatesUnique(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
)
|
||||
external
|
||||
payable
|
||||
virtual
|
||||
override
|
||||
returns (PythStructs.PriceFeed[] memory priceFeeds);
|
||||
}
|
||||
|
|
|
@ -136,4 +136,23 @@ interface IPyth is IPythEvents {
|
|||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
|
||||
|
||||
/// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are
|
||||
/// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp,
|
||||
/// this method will return the first update.
|
||||
///
|
||||
///
|
||||
/// @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 and uniqueness condition.
|
||||
/// @param updateData Array of price update data.
|
||||
/// @param priceIds Array of price ids.
|
||||
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
|
||||
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
|
||||
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
|
||||
function parsePriceFeedUpdatesUnique(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
|
||||
}
|
||||
|
|
|
@ -78,12 +78,13 @@ contract MockPyth is AbstractPyth {
|
|||
return singleUpdateFeeInWei * updateData.length;
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdates(
|
||||
function parsePriceFeedUpdatesInternal(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
|
||||
uint64 maxPublishTime,
|
||||
bool unique
|
||||
) internal returns (PythStructs.PriceFeed[] memory feeds) {
|
||||
uint requiredFee = getUpdateFee(updateData);
|
||||
if (msg.value < requiredFee) revert PythErrors.InsufficientFee();
|
||||
|
||||
|
@ -91,13 +92,18 @@ contract MockPyth is AbstractPyth {
|
|||
|
||||
for (uint i = 0; i < priceIds.length; i++) {
|
||||
for (uint j = 0; j < updateData.length; j++) {
|
||||
feeds[i] = abi.decode(updateData[j], (PythStructs.PriceFeed));
|
||||
uint64 prevPublishTime;
|
||||
(feeds[i], prevPublishTime) = abi.decode(
|
||||
updateData[j],
|
||||
(PythStructs.PriceFeed, uint64)
|
||||
);
|
||||
|
||||
if (feeds[i].id == priceIds[i]) {
|
||||
uint publishTime = feeds[i].price.publishTime;
|
||||
if (
|
||||
minPublishTime <= publishTime &&
|
||||
publishTime <= maxPublishTime
|
||||
publishTime <= maxPublishTime &&
|
||||
(!unique || prevPublishTime < minPublishTime)
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
|
@ -111,6 +117,38 @@ contract MockPyth is AbstractPyth {
|
|||
}
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdates(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
|
||||
return
|
||||
parsePriceFeedUpdatesInternal(
|
||||
updateData,
|
||||
priceIds,
|
||||
minPublishTime,
|
||||
maxPublishTime,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function parsePriceFeedUpdatesUnique(
|
||||
bytes[] calldata updateData,
|
||||
bytes32[] calldata priceIds,
|
||||
uint64 minPublishTime,
|
||||
uint64 maxPublishTime
|
||||
) external payable override returns (PythStructs.PriceFeed[] memory feeds) {
|
||||
return
|
||||
parsePriceFeedUpdatesInternal(
|
||||
updateData,
|
||||
priceIds,
|
||||
minPublishTime,
|
||||
maxPublishTime,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
function createPriceFeedUpdateData(
|
||||
bytes32 id,
|
||||
int64 price,
|
||||
|
@ -118,7 +156,8 @@ contract MockPyth is AbstractPyth {
|
|||
int32 expo,
|
||||
int64 emaPrice,
|
||||
uint64 emaConf,
|
||||
uint64 publishTime
|
||||
uint64 publishTime,
|
||||
uint64 prevPublishTime
|
||||
) public pure returns (bytes memory priceFeedData) {
|
||||
PythStructs.PriceFeed memory priceFeed;
|
||||
|
||||
|
@ -134,6 +173,6 @@ contract MockPyth is AbstractPyth {
|
|||
priceFeed.emaPrice.expo = expo;
|
||||
priceFeed.emaPrice.publishTime = publishTime;
|
||||
|
||||
priceFeedData = abi.encode(priceFeed);
|
||||
priceFeedData = abi.encode(priceFeed, prevPublishTime);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -447,6 +447,101 @@
|
|||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes[]",
|
||||
"name": "updateData",
|
||||
"type": "bytes[]"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32[]",
|
||||
"name": "priceIds",
|
||||
"type": "bytes32[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "minPublishTime",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "maxPublishTime",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"name": "parsePriceFeedUpdatesUnique",
|
||||
"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[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
|
|
|
@ -432,6 +432,101 @@
|
|||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes[]",
|
||||
"name": "updateData",
|
||||
"type": "bytes[]"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32[]",
|
||||
"name": "priceIds",
|
||||
"type": "bytes32[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "minPublishTime",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "maxPublishTime",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"name": "parsePriceFeedUpdatesUnique",
|
||||
"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[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
|
|
|
@ -131,6 +131,11 @@
|
|||
"internalType": "uint64",
|
||||
"name": "publishTime",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "prevPublishTime",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"name": "createPriceFeedUpdateData",
|
||||
|
@ -527,6 +532,101 @@
|
|||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes[]",
|
||||
"name": "updateData",
|
||||
"type": "bytes[]"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32[]",
|
||||
"name": "priceIds",
|
||||
"type": "bytes32[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "minPublishTime",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"internalType": "uint64",
|
||||
"name": "maxPublishTime",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"name": "parsePriceFeedUpdatesUnique",
|
||||
"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": "feeds",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@pythnetwork/pyth-sdk-solidity",
|
||||
"version": "2.2.1",
|
||||
"version": "2.3.0",
|
||||
"description": "Read prices from the Pyth oracle",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
Loading…
Reference in New Issue