diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f0d30a2..0000000 --- a/package-lock.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "smart-contract-evm", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "smart-contract-evm", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@pythnetwork/pyth-sdk-solidity": "^2.4.1", - "dotenv": "^16.4.1", - "minimist": "^1.2.8" - }, - "devDependencies": {} - }, - "node_modules/@pythnetwork/pyth-sdk-solidity": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-2.4.1.tgz", - "integrity": "sha512-QNrdtv+YiEszz0hvBOWXaJ3PeKJfcSnQnB9GuSZOK1WVuJxNtPTd1Hc2hrpxPm0B4SBKwSSo10I0jb4GXHi42g==" - }, - "node_modules/dotenv": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", - "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 399d627..0000000 --- a/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "smart-contract-evm", - "version": "1.0.0", - "description": "JOJO is a decentralized perpetual contract exchange based on an off-chain matching system that can be divided into three key components: trading, collateral lending, and funding rate arbitrage.", - "main": "index.js", - "directories": { - "lib": "lib", - "test": "test" - }, - "dependencies": { - "@pythnetwork/pyth-sdk-solidity": "^2.4.1", - "dotenv": "^16.4.1", - "minimist": "^1.2.8" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/src/interfaces/internal/IPyth.sol b/src/interfaces/internal/IPyth.sol new file mode 100644 index 0000000..8cb7444 --- /dev/null +++ b/src/interfaces/internal/IPyth.sol @@ -0,0 +1,85 @@ +/* + Copyright 2022 JOJO Exchange + SPDX-License-Identifier: BUSL-1.1 +*/ + +pragma solidity ^0.8.19; + +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. + // Both the price and confidence are stored in a fixed-point numeric representation, + // `x * (10^expo)`, where `expo` is the exponent. + // + // Please refer to the documentation at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices + // for how + // to how this price safely. + struct Price { + // Price + int64 price; + // Confidence interval around the price + uint64 conf; + // Price exponent + int32 expo; + // Unix timestamp describing when the price was published + uint256 publishTime; + } + + // PriceFeed represents a current aggregate price from pyth publisher feeds. + struct PriceFeed { + // The price ID. + bytes32 id; + // Latest available price + Price price; + // Latest available exponentially-weighted moving average price + Price emaPrice; + } +} + +interface IPyth { + /// @notice Returns the price and confidence interval. + /// @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); + + /// @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 + /// `getUpdateFee` with the length of the `updateData` array. + /// Prices will be updated if they are more recent than the current stored prices. + /// The call will succeed even if the update is not the most recent. + /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid. + /// @param updateData Array of price update data. + function updatePriceFeeds(bytes[] calldata updateData) external payable; + + /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is + /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the + /// given `publishTimes` for the price feeds and does not read the actual price update publish time within + /// `updateData`. + /// + /// 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. + /// + /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime + /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have + /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas. + /// Otherwise, it calls updatePriceFeeds method to update the prices. + /// + /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid. + /// @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; + + /// @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 (uint256 feeAmount); +} diff --git a/src/oracle/PythOracleAdaptor.sol b/src/oracle/PythOracleAdaptor.sol index 1814892..a7ddc66 100644 --- a/src/oracle/PythOracleAdaptor.sol +++ b/src/oracle/PythOracleAdaptor.sol @@ -7,8 +7,7 @@ pragma solidity ^0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; -import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; +import "../interfaces/internal/IPyth.sol"; import "../interfaces/internal/IChainlink.sol"; contract OracleAdaptor is Ownable { diff --git a/src/oracle/PythOracleUpdate.sol b/src/oracle/PythOracleUpdate.sol index 7e53790..a06f025 100644 --- a/src/oracle/PythOracleUpdate.sol +++ b/src/oracle/PythOracleUpdate.sol @@ -6,8 +6,7 @@ pragma solidity ^0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; -import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; +import "../interfaces/internal/IPyth.sol"; contract PythOracleAdaptor is Ownable { IPyth public pyth;