账户
0xd2...c77d
0xD2...c77d

0xD2...c77d

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.19+commit.7dd6d404
语言
Solidity
合同源代码
文件 1 的 8:Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
合同源代码
文件 2 的 8:ICOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface ICOracle {
    function priceOf(string memory symbol, uint256 ts) external view returns (uint256 price_);
}
合同源代码
文件 3 的 8:IPyth.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./PythStructs.sol";
import "./IPythEvents.sol";

/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth is IPythEvents {
    /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time
    function getValidTimePeriod() external view returns (uint validTimePeriod);

    /// @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 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);

    /// @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.
    /// This function is unsafe as the returned price update may be arbitrarily far in the past.
    ///
    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
    /// 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);

    /// @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);

    /// @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.
    /// However, if the price is not recent this function returns the latest available price.
    ///
    /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
    /// the returned price is recent or useful for any particular application.
    ///
    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is
    /// 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);

    /// @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);

    /// @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 (uint feeAmount);

    /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
    /// within `minPublishTime` and `maxPublishTime`.
    ///
    /// 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.
    ///
    ///
    /// @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 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 parsePriceFeedUpdates(
        bytes[] calldata updateData,
        bytes32[] calldata priceIds,
        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. This method may store the price updates on-chain, if they
    /// are more recent than the current stored prices.
    ///
    ///
    /// @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);
}
合同源代码
文件 4 的 8:IPythEvents.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @title IPythEvents contains the events that Pyth contract emits.
/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
interface IPythEvents {
    /// @dev Emitted when the price feed with `id` has received a fresh update.
    /// @param id The Pyth Price Feed ID.
    /// @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
    );
}
合同源代码
文件 5 的 8:OraclePyth.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@pyth/IPyth.sol";
import { Ownable } from "@oz/access/Ownable.sol";
import { ICOracle } from "./interfaces/ICOracle.sol";
import "./libs/SymbolRegistryLib.sol";

contract OraclePyth is Ownable, ICOracle {
    using SymbolRegistryLib for SymbolRegistry;

    IPyth public immutable pyth;
    SymbolRegistry private symbolRegistry;

    mapping(string => mapping(uint256 => uint256)) public override priceOf;

    constructor(address _pyth, string[] memory symbols, bytes32[] memory ids) {
        pyth = IPyth(_pyth);
        addSymbolIds(symbols, ids);
    }

    event SymbolsRemoved(string[] symbols);
    event SymbolIdsAdded(string[] symbols, bytes32[] ids);
    event PriceUpdated(string symbol, uint256 ts, uint256 price);

    function getSymbolsById(bytes32 id) internal view returns (string[] memory) {
        return symbolRegistry.idToSymbols[id];
    }

    function getIdBySymbol(string memory symbol) internal view returns (bytes32) {
        return symbolRegistry.symbolToId[symbol];
    }

    function removeSymbolIds(string[] memory symbols) public onlyOwner {
        for (uint256 i = 0; i < symbols.length; i++) {
            symbolRegistry.removeSymbol(symbols[i]);
        }
        emit SymbolsRemoved(symbols);
    }

    function addSymbolIds(string[] memory symbols, bytes32[] memory ids) public onlyOwner {
        require(symbols.length == ids.length, "OraclePyth: symbols and ids length mismatch");
        for (uint256 i = 0; i < symbols.length; i++) {
            symbolRegistry.addSymbolId(symbols[i], ids[i]);
        }
        emit SymbolIdsAdded(symbols, ids);
    }

    function updatePrice(bytes32[] memory ids, bytes[] memory data, uint64 min, uint64 max) public payable {
        require(ids.length == data.length, "OraclePyth: ids and data length mismatch");
        for (uint256 i = 0; i < ids.length; i++) {
            require(symbolRegistry.getSymbolsById(ids[i]).length != 0, "OraclePyth: id not found");
        }
        PythStructs.PriceFeed[] memory ps = pyth.parsePriceFeedUpdatesUnique{ value: msg.value }(data, ids, min, max);
        for (uint256 i = 0; i < ps.length; i++) {
            PythStructs.Price memory price = ps[i].price;
            string[] storage symbols = symbolRegistry.getSymbolsById(ps[i].id);
            for (uint256 j = 0; j < symbols.length; j++) {
                string memory symbol = symbols[j];
                require(priceOf[symbol][price.publishTime] == 0, "OraclePyth: price already exists");
                uint256 price18Decimals = (uint256(uint64(price.price)) * (10 ** 18)) / (10 ** uint8(uint32(-1 * price.expo)));
                priceOf[symbol][price.publishTime] = price18Decimals;
                emit PriceUpdated(symbol, price.publishTime, price18Decimals);
            }
        }
    }
}
合同源代码
文件 6 的 8:Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
合同源代码
文件 7 的 8:PythStructs.sol
// SPDX-License-Identifier: Apache-2.0
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.
    // 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
        uint 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;
    }
}
合同源代码
文件 8 的 8:SymbolRegistryLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

struct SymbolRegistry {
    mapping(string => bytes32) symbolToId;
    mapping(bytes32 => string[]) idToSymbols;
}

library SymbolRegistryLib {
    function addSymbolId(SymbolRegistry storage self, string memory symbol, bytes32 id) internal {
        require(self.symbolToId[symbol] == bytes32(0), "SymbolRegistry: symbol already exists");
        self.symbolToId[symbol] = id;

        if (!symbolExistsInId(self, id, symbol)) {
            self.idToSymbols[id].push(symbol);
        }
    }

    function removeSymbol(SymbolRegistry storage self, string memory symbol) internal {
        bytes32 id = self.symbolToId[symbol];
        require(id != bytes32(0), "SymbolRegistry: symbol not found");

        string[] storage symbols = self.idToSymbols[id];
        for (uint256 i = 0; i < symbols.length; i++) {
            if (keccak256(bytes(symbols[i])) == keccak256(bytes(symbol))) {
                symbols[i] = symbols[symbols.length - 1];
                symbols.pop();
                break;
            }
        }

        delete self.symbolToId[symbol];

        if (symbols.length == 0) {
            delete self.idToSymbols[id];
        }
    }

    function symbolExistsInId(SymbolRegistry storage self, bytes32 id, string memory symbol) internal view returns (bool) {
        string[] storage symbols = self.idToSymbols[id];
        for (uint256 i = 0; i < symbols.length; i++) {
            if (keccak256(bytes(symbols[i])) == keccak256(bytes(symbol))) {
                return true;
            }
        }
        return false;
    }

    function getSymbolsById(SymbolRegistry storage self, bytes32 id) internal view returns (string[] storage) {
        return self.idToSymbols[id];
    }

    function getIdBySymbol(SymbolRegistry storage self, string memory symbol) internal view returns (bytes32) {
        return self.symbolToId[symbol];
    }
}
设置
{
  "compilationTarget": {
    "src/core/OraclePyth.sol": "OraclePyth"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [
    ":@diamond/=lib/diamond-3-hardhat/contracts/",
    ":@openzeppelin/=lib/openzeppelin-contracts/",
    ":@oz/=lib/openzeppelin-contracts/contracts/",
    ":@pyth/=node_modules/@pythnetwork/pyth-sdk-solidity/",
    ":@solid/=lib/solidstate-solidity/contracts/",
    ":@solmate/=lib/solmate/src/",
    ":@std/=lib/forge-std/src/",
    ":@uniswap/=lib/",
    ":@weth/=lib/canonical-weth/contracts/",
    ":chainlink/=lib/chainlink/contracts/src/v0.8/",
    ":core/=src/core/",
    ":ds-test/=lib/forge-std/lib/ds-test/src/",
    ":forge-std/=lib/forge-std/src/",
    ":openzeppelin-contracts/=lib/openzeppelin-contracts/",
    ":periphery/=src/periphery/",
    ":script/=script/",
    ":solmate/=lib/solmate/src/",
    ":test/=test/",
    ":v3-core/=lib/v3-core/contracts/",
    ":v3-periphery/=lib/v3-periphery/contracts/"
  ]
}
ABI
[{"inputs":[{"internalType":"address","name":"_pyth","type":"address"},{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"bytes32[]","name":"ids","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"PriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string[]","name":"symbols","type":"string[]"},{"indexed":false,"internalType":"bytes32[]","name":"ids","type":"bytes32[]"}],"name":"SymbolIdsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string[]","name":"symbols","type":"string[]"}],"name":"SymbolsRemoved","type":"event"},{"inputs":[{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"bytes32[]","name":"ids","type":"bytes32[]"}],"name":"addSymbolIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"priceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pyth","outputs":[{"internalType":"contract IPyth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"symbols","type":"string[]"}],"name":"removeSymbolIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"ids","type":"bytes32[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"uint64","name":"min","type":"uint64"},{"internalType":"uint64","name":"max","type":"uint64"}],"name":"updatePrice","outputs":[],"stateMutability":"payable","type":"function"}]