MNT Price: $0.86 (+1.08%)

Contract

0x42F9153e28c1D7D2f0d2fcCc5106a5DBB7367d2D
 

Overview

MNT Balance

Mantle Mainnet Network LogoMantle Mainnet Network LogoMantle Mainnet Network Logo0 MNT

MNT Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x2e014fA8...37a9d20Ee
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Api3PythPriceFeed

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;

import '../interfaces/IPriceFeed.sol';
import {IPyth, PythStructs} from '../interfaces/IPyth.sol';
import '../dependencies/openzeppelin/contracts/SafeMath.sol';

interface IApi3Proxy {
  function read() external view returns (int224 value, uint32 timestamp);
}

/*
 * The Api3PythPriceFeed uses Api3 as primary oracle and Pyth fallback oracle.
 */
contract Api3PythPriceFeed is IPriceFeed {
  using SafeMath for uint256;

  uint256 public constant DECIMAL_PRECISION = 1e18;

  IApi3Proxy public api3Oracle; // Api3 oracle contract
  IPyth public pythOracle; // Pyth oracle contract

  bytes32 public pythPriceId;

  // Use to convert a price answer to an 18-digit precision uint
  uint256 public constant TARGET_DIGITS = 18;

  // Maximum time period allowed since Api3's latest round data timestamp, beyond which Api3 is considered frozen.
  // For stablecoins we recommend 90000, as Api3 updates once per day when there is no significant price movement
  // For volatile assets we recommend 14400 (4 hours)
  uint256 public immutable TIMEOUT;

  // Maximum deviation allowed between two consecutive Api3 oracle prices. 18-digit precision.
  uint256 public constant MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND = 5e17; // 50%

  /*
   * The maximum relative price difference between two oracle responses allowed in order for the PriceFeed
   * to return to using the Api3 oracle. 18-digit precision.
   */
  uint256 public constant MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES = 5e16; // 5%

  // The last good price seen from an oracle by Liquity
  uint256 public lastGoodPrice;

  struct Api3Response {
    uint256 answer;
    uint256 timestamp;
    bool success;
  }

  struct PythResponse {
    uint256 answer;
    uint256 timestamp;
    bool success;
    uint32 decimals;
  }

  enum Status {
    api3Working,
    usingPythApi3Untrusted,
    bothOraclesUntrusted,
    usingPythApi3Frozen,
    usingApi3PythUntrusted
  }

  // The current status of the PricFeed, which determines the conditions for the next price fetch attempt
  Status public status;

  event LastGoodPriceUpdated(uint256 _lastGoodPrice);
  event PriceFeedStatusChanged(Status newStatus);

  // --- Dependency setters ---

  constructor(
    IApi3Proxy _api3OracleAddress,
    IPyth _pythOracleAddress,
    bytes32 _pythPriceId,
    uint256 _timeout
  ) {
    api3Oracle = _api3OracleAddress;
    pythOracle = _pythOracleAddress;
    pythPriceId = _pythPriceId;
    TIMEOUT = _timeout;

    // Explicitly set initial system status
    status = Status.api3Working;

    // Get an initial price from Api3 to serve as first reference for lastGoodPrice
    Api3Response memory response = _getCurrentApi3Response();

    require(
      !_api3IsBroken(response) &&
        block.timestamp.sub(response.timestamp) < _timeout,
      "PriceFeed: Api3 must be working and current"
    );

    lastGoodPrice = response.answer;
  }

  // --- Functions ---

  /*
   * fetchPrice():
   * Returns the latest price obtained from the Oracle. Called by Liquity functions that require a current price.
   *
   * Also callable by anyone externally.
   *
   * Non-view function - it stores the last good price seen by Liquity.
   *
   * Uses a main oracle (Api3). If it fails,
   * it uses the last good price seen by Liquity.
   *
   */
  function fetchPrice() external view override returns (uint256) {
    (, uint256 price) = _fetchPrice();
    return price;
  }

  function updatePrice() external override returns (uint256) {
    (Status newStatus, uint256 price) = _fetchPrice();
    lastGoodPrice = price;
    if (status != newStatus) {
      status = newStatus;
      emit PriceFeedStatusChanged(newStatus);
    }
    return price;
  }

  function _fetchPrice() internal view returns (Status, uint256) {
    // Get current and previous price data from Api3, and current price data from Band
    Api3Response memory api3Response = _getCurrentApi3Response();
    PythResponse memory pythResponse = _getCurrentPythResponse();

    // --- CASE 1: System fetched last price from Api3  ---
    if (status == Status.api3Working) {
      // If Api3 is broken, try to get a price from Pyth
      if (_api3IsBroken(api3Response)) {
        // If Pyth is broken then both oracles are untrusted, so return the last good price
        if (_pythIsBroken(pythResponse)) {
            return (Status.bothOraclesUntrusted, lastGoodPrice);
        }
        /*
        * If Pyth is only frozen but otherwise returning valid data, return the last good price.
        */
        if (_pythIsFrozen(pythResponse)) {
          return (Status.usingPythApi3Untrusted, lastGoodPrice);
        }

        // If Api3 is broken and Pyth is working, switch to Pyth and return current Pyth price
        return (Status.usingPythApi3Untrusted, pythResponse.answer);
      }

      // If Api3 is frozen, try Pyth
      if (_api3IsFrozen(api3Response)) {
        // If Pyth is broken too, remember Pyth broke, and return last good price
        if (_pythIsBroken(pythResponse)) {
          return (Status.usingApi3PythUntrusted, lastGoodPrice);
        }

        // If Pyth is frozen or working, remember Api3 froze, and switch to Pyth
        if (_pythIsFrozen(pythResponse)) {return (Status.usingPythApi3Frozen, lastGoodPrice);}

        // If Pyth is working, use it
        return (Status.usingPythApi3Frozen, pythResponse.answer);
      }

      // If Api3 is working and Pyth is broken, remember Pyth is broken
      if (_pythIsBroken(pythResponse)) {
        return (Status.usingApi3PythUntrusted, api3Response.answer);
      }

      // If Api3 is working, return Api3 current price (no status change)
      return (Status.api3Working, api3Response.answer);
    }

    // --- CASE 2: The system fetched last price from Pyth ---
    if (status == Status.usingPythApi3Untrusted) {
      // If both Pyth and Api3 are live, unbroken, and reporting similar prices, switch back to Api3
      if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(api3Response, pythResponse)) {
        return (Status.api3Working, api3Response.answer);
      }

      if (_pythIsBroken(pythResponse)) {
        return (Status.bothOraclesUntrusted, lastGoodPrice);
      }

      /*
      * If Pyth is only frozen but otherwise returning valid data, just return the last good price.
      * Pyth may need to be tipped to return current data.
      */
      if (_pythIsFrozen(pythResponse)) {return (Status.usingPythApi3Untrusted, lastGoodPrice);}

      // Otherwise, use Pyth price
      return (Status.usingPythApi3Untrusted, pythResponse.answer);
    }

    // --- CASE 3: Both oracles were untrusted at the last price fetch ---
    if (status == Status.bothOraclesUntrusted) {
      /*
      * If both oracles are now live, unbroken and similar price, we assume that they are reporting
      * accurately, and so we switch back to Api3.
      */
      if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(api3Response, pythResponse)) {
        return (Status.api3Working, api3Response.answer);
      }

      // Otherwise, return the last good price - both oracles are still untrusted (no status change)
      return (Status.bothOraclesUntrusted, lastGoodPrice);
    }
    
    // --- CASE 4: Using Pyth, and Api3 is frozen ---
    if (status == Status.usingPythApi3Frozen) {
      if (_api3IsBroken(api3Response)) {
        // If both Oracles are broken, return last good price
        if (_pythIsBroken(pythResponse)) {
          return (Status.bothOraclesUntrusted, lastGoodPrice);
        }

        // If Api3 is broken, remember it and switch to using Pyth
        if (_pythIsFrozen(pythResponse)) {
          return (Status.usingPythApi3Untrusted, lastGoodPrice);
        }

        // If Pyth is working, return Pyth current price
        return (Status.usingPythApi3Untrusted, pythResponse.answer);
      }

      if (_api3IsFrozen(api3Response)) {
        // if Api3 is frozen and Pyth is broken, remember Pyth broke, and return last good price
        if (_pythIsBroken(pythResponse)) {
          return (Status.usingApi3PythUntrusted, lastGoodPrice);
        }

        // If both are frozen, just use lastGoodPrice
        if (_pythIsFrozen(pythResponse)) {
          return (Status.usingPythApi3Frozen, lastGoodPrice);
        }

        // if Api3 is frozen and Pyth is working, keep using Pyth (no status change)
        return (Status.usingPythApi3Frozen, pythResponse.answer);
      }

      // if Api3 is live and Pyth is broken, remember Pyth broke, and return Api3 price
      if (_pythIsBroken(pythResponse)) {
        return (Status.usingApi3PythUntrusted, api3Response.answer);
      }

        // If Api3 is live and Pyth is frozen, just use last good price (no status change) since we have no basis for comparison
      if (_pythIsFrozen(pythResponse)) {
        return (Status.usingPythApi3Frozen, lastGoodPrice);
      }

      // If Api3 is live and Pyth is working, compare prices. Switch to Api3
      // if prices are within 5%, and return Api3 price.
      if (_bothOraclesSimilarPrice(api3Response, pythResponse)) {
        return (Status.api3Working, api3Response.answer);
      }

      // Otherwise if Api3 is live but price not within 5% of Pyth, distrust Api3, and return Pyth price
      return (Status.usingPythApi3Untrusted, pythResponse.answer);
    }

    // --- CASE 5: Using Api3, Pyth is untrusted ---
    if (status == Status.usingApi3PythUntrusted) {
      // If Api3 breaks, now both oracles are untrusted
      if (_api3IsBroken(api3Response)) {
        return (Status.bothOraclesUntrusted, lastGoodPrice);
      }

      // If Api3 is frozen, return last good price (no status change)
      if (_api3IsFrozen(api3Response)) {
        return (Status.usingApi3PythUntrusted, lastGoodPrice);
      }

      // If Api3 and Pyth are both live, unbroken and similar price, switch back to api3Working and return Api3 price
      if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(api3Response, pythResponse)) {
        return (Status.api3Working, api3Response.answer);
      }

      // Otherwise if Api3 is live and Pyth is still untrusted,
      // return Api3 price (no status change)
      return (Status.usingApi3PythUntrusted, api3Response.answer);
    }
  }

  // --- Helper functions ---

  /* Api3 is considered broken if its current or previous round data is in any way bad. We check the previous round
   * for two reasons:
   *
   * 1) It is necessary data for the price deviation check in case 1,
   * and
   * 2) Api3 is the PriceFeed's preferred primary oracle - having two consecutive valid round responses adds
   * peace of mind when using or returning to Api3.
   */
  function _api3IsBroken(Api3Response memory _currentResponse) internal view returns (bool) {
    return _badApi3Response(_currentResponse);
  }

  function _badApi3Response(Api3Response memory _response) internal view returns (bool) {
    // Check for response call reverted
    if (!_response.success) {return true;}
    // Check for an invalid timeStamp that is 0, or in the future
    if (_response.timestamp == 0 || _response.timestamp > block.timestamp) {return true;}
    // Check for non-positive price (original value returned from chainlink is int256)
    if (int256(_response.answer) <= 0) {return true;}

    return false;
  }

  function _api3IsFrozen(Api3Response memory _response) internal view returns (bool) {
    return block.timestamp.sub(_response.timestamp) > TIMEOUT;
  }

  function _pythIsBroken(PythResponse memory _response) internal view returns (bool) {
    // Check for response call reverted
    if (!_response.success) {return true;}
    // Check for an invalid timeStamp that is 0, or in the future
    if (_response.timestamp == 0 || _response.timestamp > block.timestamp) {return true;}
    // Check for zero price
    if (_response.answer == 0) {return true;}

    return false;
  }

  function _pythIsFrozen(PythResponse memory _response) internal view returns (bool) {
    return block.timestamp.sub(_response.timestamp) > TIMEOUT;
  }

  function _bothOraclesLiveAndUnbrokenAndSimilarPrice
  (
    Api3Response memory _api3Response,
    PythResponse memory _pythResponse
  )
    internal
    view
    returns (bool)
  {
    // Return false if either oracle is broken or frozen
    if (
      _pythIsBroken(_pythResponse) || _pythIsFrozen(_pythResponse) ||
      _api3IsBroken(_api3Response) || _api3IsFrozen(_api3Response)
    ) {
      return false;
    }

    return _bothOraclesSimilarPrice(_api3Response, _pythResponse);
  }

  function _bothOraclesSimilarPrice(Api3Response memory _api3Response, PythResponse memory _pythResponse) internal pure returns (bool) {
    uint scaledApi3Price = _api3Response.answer;
    uint scaledPythPrice = _pythResponse.answer;

    // Get the relative price difference between the oracles. Use the lower price as the denominator, i.e. the reference for the calculation.
    uint minPrice = (scaledPythPrice < scaledApi3Price) ? scaledPythPrice : scaledApi3Price;
    uint maxPrice = (scaledPythPrice >= scaledApi3Price) ? scaledPythPrice : scaledApi3Price;
    uint percentPriceDifference = maxPrice.sub(minPrice).mul(DECIMAL_PRECISION).div(minPrice);

    /*
    * Return true if the relative price difference is <= 3%: if so, we assume both oracles are probably reporting
    * the honest market price, as it is unlikely that both have been broken/hacked and are still in-sync.
    */
    return percentPriceDifference <= MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES;
  }

  function _scalePythPriceByDigits(uint256 _price, uint32 _digits) internal pure returns (uint256) {
    /*
     * Convert the price returned by the Api3 oracle to an 18-digit decimal for use by Liquity.
     * At date of Liquity launch, Api3 uses an 8-digit price, but we also handle the possibility of
     * future changes.
     */
    uint256 price;
    if (_digits >= TARGET_DIGITS) {
      // Scale the returned price value down to Liquity's target precision
      price = _price.div(10 ** (_digits - TARGET_DIGITS));
    } else if (_digits < TARGET_DIGITS) {
      // Scale the returned price value up to Liquity's target precision
      price = _price.mul(10 ** (TARGET_DIGITS - _digits));
    }
    return price;
  }

  // --- Oracle response wrapper functions ---

  function _getCurrentApi3Response() internal view returns (Api3Response memory response) {
    // Try to get latest price data:
    try api3Oracle.read() returns (
      int224 value,
      uint32 timestamp
    ) {
      // If call to Api3 succeeds, return the response and success = true
      response.answer = uint256(value);
      response.timestamp = timestamp;
      response.success = true;
      return response;
    } catch {
      // If call to Api3 aggregator reverts, return a zero response with success = false
      return response;
    }
  }

  function _getCurrentPythResponse()
    internal
    view
    returns (PythResponse memory response)
  {
    // Try to get latest price data:
    try pythOracle.getPriceUnsafe(pythPriceId) returns (
      PythStructs.Price memory price
    ) {
      uint32 decimals = uint32(price.expo >= 0 ? price.expo : -price.expo);
      // If call to Pyth succeeds, return the response and success = true
      response.answer = _scalePythPriceByDigits(uint256(price.price), decimals);
      response.timestamp = price.publishTime;
      response.decimals = decimals;
      response.success = true;
      return response;
    } catch {
      // If call to Pyth aggregator reverts, return a zero response with success = false
      return response;
    }
  }
}

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
  /**
   * @dev Returns the addition of two unsigned integers, reverting on
   * overflow.
   *
   * Counterpart to Solidity's `+` operator.
   *
   * Requirements:
   * - Addition cannot overflow.
   */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a, 'SafeMath: addition overflow');

    return c;
  }

  /**
   * @dev Returns the subtraction of two unsigned integers, reverting on
   * overflow (when the result is negative).
   *
   * Counterpart to Solidity's `-` operator.
   *
   * Requirements:
   * - Subtraction cannot overflow.
   */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    return sub(a, b, 'SafeMath: subtraction overflow');
  }

  /**
   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
   * overflow (when the result is negative).
   *
   * Counterpart to Solidity's `-` operator.
   *
   * Requirements:
   * - Subtraction cannot overflow.
   */
  function sub(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    require(b <= a, errorMessage);
    uint256 c = a - b;

    return c;
  }

  /**
   * @dev Returns the multiplication of two unsigned integers, reverting on
   * overflow.
   *
   * Counterpart to Solidity's `*` operator.
   *
   * Requirements:
   * - Multiplication cannot overflow.
   */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b, 'SafeMath: multiplication overflow');

    return c;
  }

  /**
   * @dev Returns the integer division of two unsigned integers. Reverts on
   * division by zero. The result is rounded towards zero.
   *
   * Counterpart to Solidity's `/` operator. Note: this function uses a
   * `revert` opcode (which leaves remaining gas untouched) while Solidity
   * uses an invalid opcode to revert (consuming all remaining gas).
   *
   * Requirements:
   * - The divisor cannot be zero.
   */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    return div(a, b, 'SafeMath: division by zero');
  }

  /**
   * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
   * division by zero. The result is rounded towards zero.
   *
   * Counterpart to Solidity's `/` operator. Note: this function uses a
   * `revert` opcode (which leaves remaining gas untouched) while Solidity
   * uses an invalid opcode to revert (consuming all remaining gas).
   *
   * Requirements:
   * - The divisor cannot be zero.
   */
  function div(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    // Solidity only automatically asserts when dividing by 0
    require(b > 0, errorMessage);
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;
  }

  /**
   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
   * Reverts when dividing by zero.
   *
   * Counterpart to Solidity's `%` operator. This function uses a `revert`
   * opcode (which leaves remaining gas untouched) while Solidity uses an
   * invalid opcode to revert (consuming all remaining gas).
   *
   * Requirements:
   * - The divisor cannot be zero.
   */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    return mod(a, b, 'SafeMath: modulo by zero');
  }

  /**
   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
   * Reverts with custom message when dividing by zero.
   *
   * Counterpart to Solidity's `%` operator. This function uses a `revert`
   * opcode (which leaves remaining gas untouched) while Solidity uses an
   * invalid opcode to revert (consuming all remaining gas).
   *
   * Requirements:
   * - The divisor cannot be zero.
   */
  function mod(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    require(b != 0, errorMessage);
    return a % b;
  }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPriceFeed {
  // --- Function ---
  function fetchPrice() external view returns (uint256);

  function updatePrice() external returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma abicoder v2;

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/consumers/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;
    }
}

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

    /// @dev Emitted when a batch price update is processed successfully.
    /// @param chainId ID of the source chain that the batch price update comes from.
    /// @param sequenceNumber Sequence number of the batch price update.
    event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber);
}

/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/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 does not store the price updates on-chain.
    ///
    /// 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);
}

Settings
{
  "evmVersion": "istanbul",
  "libraries": {},
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IApi3Proxy","name":"_api3OracleAddress","type":"address"},{"internalType":"contract IPyth","name":"_pythOracleAddress","type":"address"},{"internalType":"bytes32","name":"_pythPriceId","type":"bytes32"},{"internalType":"uint256","name":"_timeout","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastGoodPrice","type":"uint256"}],"name":"LastGoodPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum Api3PythPriceFeed.Status","name":"newStatus","type":"uint8"}],"name":"PriceFeedStatusChanged","type":"event"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TARGET_DIGITS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMEOUT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"api3Oracle","outputs":[{"internalType":"contract IApi3Proxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastGoodPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pythOracle","outputs":[{"internalType":"contract IPyth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pythPriceId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum Api3PythPriceFeed.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updatePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

0x60a06040523480156200001157600080fd5b506040516200105e3803806200105e83398101604081905262000034916200030d565b600080546001600160a01b038681166001600160a01b03199283161783556001805491871691909216179055600283905560808290526004805460ff191690556200007e620000ec565b90506200008b8162000195565b158015620000b5575081620000b3826020015142620001aa60201b6200026f1790919060201c565b105b620000dd5760405162461bcd60e51b8152600401620000d490620003a2565b60405180910390fd5b51600355506200040692505050565b620000f6620002ea565b600054604080516315f789a960e21b815281516001600160a01b03909316926357de26a492600480840193919291829003018186803b1580156200013957600080fd5b505afa9250505080156200016c575060408051601f3d908101601f19168201909252620001699181019062000359565b60015b620001775762000192565b601b9190910b825263ffffffff166020820152600160408201525b90565b6000620001a282620001fb565b90505b919050565b6000620001f483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506200024f60201b60201c565b9392505050565b600081604001516200021057506001620001a5565b60208201511580620002255750428260200151115b156200023457506001620001a5565b81516000126200024757506001620001a5565b506000919050565b60008184841115620002e25760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620002a65781810151838201526020016200028c565b50505050905090810190601f168015620002d45780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604051806060016040528060008152602001600081526020016000151581525090565b6000806000806080858703121562000323578384fd5b84516200033081620003ed565b60208601519094506200034381620003ed565b6040860151606090960151949790965092505050565b600080604083850312156200036c578182fd5b825180601b0b81146200037d578283fd5b602084015190925063ffffffff8116811462000397578182fd5b809150509250929050565b6020808252602b908201527f5072696365466565643a2041706933206d75737420626520776f726b696e672060408201526a185b990818dd5c9c995b9d60aa1b606082015260800190565b6001600160a01b03811681146200040357600080fd5b50565b608051610c38620004266000398061023e52806107e45250610c386000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806358a6aa881161007157806358a6aa8814610119578063673a7e2814610121578063a20baee614610129578063e4ea36f014610131578063f56f48f214610139578063f5d6ac9014610141576100b4565b80630490be83146100b95780630fdb11cf146100d75780631be5c92f146100df5780631f89bc37146100e7578063200d2ed2146100fc57806345079cb414610111575b600080fd5b6100c1610149565b6040516100ce9190610bb0565b60405180910390f35b6100c161014f565b6100c1610162565b6100ef610167565b6040516100ce9190610bb9565b610104610176565b6040516100ce9190610bcd565b6100c161017f565b6100c161018a565b6100c1610196565b6100c161022a565b6100c1610236565b6100c161023c565b6100ef610260565b60035481565b60008061015a6102ba565b925050505b90565b601281565b6000546001600160a01b031681565b60045460ff1681565b66b1a2bc2ec5000081565b6706f05b59d3b2000081565b60008060006101a36102ba565b600381905590925090508160048111156101b957fe5b6004805460ff16908111156101ca57fe5b14610224576004805483919060ff1916600183838111156101e757fe5b02179055507f5c57579a8214fe4f710c1c56fa829f045b9fa6d225a744225a30c32188064d4e8260405161021b9190610bcd565b60405180910390a15b91505090565b670de0b6b3a764000081565b60025481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001546001600160a01b031681565b60006102b183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610566565b90505b92915050565b60008060006102c76105fd565b905060006102d361069f565b905060006004805460ff16908111156102e857fe5b14156103c5576102f782610783565b156103465761030581610796565b1561031a576002600354935093505050610562565b610323816107e0565b15610338576001600354935093505050610562565b516001935091506105629050565b61034f826107e0565b1561039d5761035d81610796565b15610372576004600354935093505050610562565b61037b816107e0565b1561038f5760038054935093505050610562565b516003935091506105629050565b6103a681610796565b156103b8575051600492509050610562565b5051600092509050610562565b60016004805460ff16908111156103d857fe5b1415610403576103e88282610821565b156103fa575051600092509050610562565b61030581610796565b60026004805460ff169081111561041657fe5b1415610448576104268282610821565b15610438575051600092509050610562565b6002600354935093505050610562565b60036004805460ff169081111561045b57fe5b14156104e35761046a82610783565b156104785761030581610796565b610481826107e0565b1561048f5761035d81610796565b61049881610796565b156104aa575051600492509050610562565b6104b3816107e0565b156104c75760038054935093505050610562565b6104d1828261086c565b15610338575051600092509050610562565b6004805460ff16818111156104f457fe5b141561055f5761050382610783565b15610518576002600354935093505050610562565b610521826107e0565b15610536576004600354935093505050610562565b6105408282610821565b15610552575051600092509050610562565b5051600492509050610562565b50505b9091565b600081848411156105f55760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156105ba5781810151838201526020016105a2565b50505050905090810190601f1680156105e75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b610605610a7f565b600054604080516315f789a960e21b815281516001600160a01b03909316926357de26a492600480840193919291829003018186803b15801561064757600080fd5b505afa925050508015610677575060408051601f3d908101601f1916820190925261067491810190610ae4565b60015b6106805761015f565b601b9190910b825263ffffffff1660208201526001604082015261015f565b6106a7610aa2565b6001546002546040516396834ad360e01b81526001600160a01b03909216916396834ad3916106d891600401610bb0565b60806040518083038186803b1580156106f057600080fd5b505afa925050508015610720575060408051601f3d908101601f1916820190925261071d91810190610b2a565b60015b6107295761015f565b600080826040015160030b121561074757816040015160000361074d565b81604001515b9050610760826000015160070b826108d8565b8352606091820151602084015263ffffffff16908201526001604082015261015f565b600061078e8261093f565b90505b919050565b600081604001516107a957506001610791565b602082015115806107bd5750428260200151115b156107ca57506001610791565b81516107d857506001610791565b506000919050565b60007f000000000000000000000000000000000000000000000000000000000000000061081a83602001514261026f90919063ffffffff16565b1192915050565b600061082c82610796565b8061083b575061083b826107e0565b8061084a575061084a83610783565b806108595750610859836107e0565b15610866575060006102b4565b6102b183835b8151815160009190828282106108825782610884565b815b90506000838310156108965783610898565b825b905060006108c2836108bc670de0b6b3a76400006108b6868461026f565b90610984565b906109dd565b66b1a2bc2ec50000101598975050505050505050565b60008060128363ffffffff161061090f5761090860128463ffffffff1603600a0a856109dd90919063ffffffff16565b90506102b1565b60128363ffffffff1610156102b1576109378463ffffffff808616601203600a0a9061098416565b949350505050565b6000816040015161095257506001610791565b602082015115806109665750428260200151115b1561097357506001610791565b81516000126107d857506001610791565b600082610993575060006102b4565b828202828482816109a057fe5b04146102b15760405162461bcd60e51b8152600401808060200182810382526021815260200180610be26021913960400191505060405180910390fd5b60006102b183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060008183610a695760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156105ba5781810151838201526020016105a2565b506000838581610a7557fe5b0495945050505050565b604051806060016040528060008152602001600081526020016000151581525090565b60405180608001604052806000815260200160008152602001600015158152602001600063ffffffff1681525090565b8051600381900b811461079157600080fd5b60008060408385031215610af6578182fd5b825180601b0b8114610b06578283fd5b602084015190925063ffffffff81168114610b1f578182fd5b809150509250929050565b600060808284031215610b3b578081fd5b6040516080810167ffffffffffffffff8282108183111715610b5957fe5b81604052845191508160070b8214610b6f578384fd5b9082526020840151908082168214610b85578384fd5b506020820152610b9760408401610ad2565b6040820152606083015160608201528091505092915050565b90815260200190565b6001600160a01b0391909116815260200190565b6020810160058310610bdb57fe5b9190529056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212201073e8a2cadddc0b9f8990d2ae7a01938f540069a79cb4384735351cab0d158564736f6c63430007060033000000000000000000000000a790a882bb695d0286c391c0935a05c347290bdb000000000000000000000000a2aa501b19aff244d90cc15a4cf739d2725b5729eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a0000000000000000000000000000000000000000000000000000000000015180

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100b45760003560e01c806358a6aa881161007157806358a6aa8814610119578063673a7e2814610121578063a20baee614610129578063e4ea36f014610131578063f56f48f214610139578063f5d6ac9014610141576100b4565b80630490be83146100b95780630fdb11cf146100d75780631be5c92f146100df5780631f89bc37146100e7578063200d2ed2146100fc57806345079cb414610111575b600080fd5b6100c1610149565b6040516100ce9190610bb0565b60405180910390f35b6100c161014f565b6100c1610162565b6100ef610167565b6040516100ce9190610bb9565b610104610176565b6040516100ce9190610bcd565b6100c161017f565b6100c161018a565b6100c1610196565b6100c161022a565b6100c1610236565b6100c161023c565b6100ef610260565b60035481565b60008061015a6102ba565b925050505b90565b601281565b6000546001600160a01b031681565b60045460ff1681565b66b1a2bc2ec5000081565b6706f05b59d3b2000081565b60008060006101a36102ba565b600381905590925090508160048111156101b957fe5b6004805460ff16908111156101ca57fe5b14610224576004805483919060ff1916600183838111156101e757fe5b02179055507f5c57579a8214fe4f710c1c56fa829f045b9fa6d225a744225a30c32188064d4e8260405161021b9190610bcd565b60405180910390a15b91505090565b670de0b6b3a764000081565b60025481565b7f000000000000000000000000000000000000000000000000000000000001518081565b6001546001600160a01b031681565b60006102b183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610566565b90505b92915050565b60008060006102c76105fd565b905060006102d361069f565b905060006004805460ff16908111156102e857fe5b14156103c5576102f782610783565b156103465761030581610796565b1561031a576002600354935093505050610562565b610323816107e0565b15610338576001600354935093505050610562565b516001935091506105629050565b61034f826107e0565b1561039d5761035d81610796565b15610372576004600354935093505050610562565b61037b816107e0565b1561038f5760038054935093505050610562565b516003935091506105629050565b6103a681610796565b156103b8575051600492509050610562565b5051600092509050610562565b60016004805460ff16908111156103d857fe5b1415610403576103e88282610821565b156103fa575051600092509050610562565b61030581610796565b60026004805460ff169081111561041657fe5b1415610448576104268282610821565b15610438575051600092509050610562565b6002600354935093505050610562565b60036004805460ff169081111561045b57fe5b14156104e35761046a82610783565b156104785761030581610796565b610481826107e0565b1561048f5761035d81610796565b61049881610796565b156104aa575051600492509050610562565b6104b3816107e0565b156104c75760038054935093505050610562565b6104d1828261086c565b15610338575051600092509050610562565b6004805460ff16818111156104f457fe5b141561055f5761050382610783565b15610518576002600354935093505050610562565b610521826107e0565b15610536576004600354935093505050610562565b6105408282610821565b15610552575051600092509050610562565b5051600492509050610562565b50505b9091565b600081848411156105f55760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156105ba5781810151838201526020016105a2565b50505050905090810190601f1680156105e75780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b610605610a7f565b600054604080516315f789a960e21b815281516001600160a01b03909316926357de26a492600480840193919291829003018186803b15801561064757600080fd5b505afa925050508015610677575060408051601f3d908101601f1916820190925261067491810190610ae4565b60015b6106805761015f565b601b9190910b825263ffffffff1660208201526001604082015261015f565b6106a7610aa2565b6001546002546040516396834ad360e01b81526001600160a01b03909216916396834ad3916106d891600401610bb0565b60806040518083038186803b1580156106f057600080fd5b505afa925050508015610720575060408051601f3d908101601f1916820190925261071d91810190610b2a565b60015b6107295761015f565b600080826040015160030b121561074757816040015160000361074d565b81604001515b9050610760826000015160070b826108d8565b8352606091820151602084015263ffffffff16908201526001604082015261015f565b600061078e8261093f565b90505b919050565b600081604001516107a957506001610791565b602082015115806107bd5750428260200151115b156107ca57506001610791565b81516107d857506001610791565b506000919050565b60007f000000000000000000000000000000000000000000000000000000000001518061081a83602001514261026f90919063ffffffff16565b1192915050565b600061082c82610796565b8061083b575061083b826107e0565b8061084a575061084a83610783565b806108595750610859836107e0565b15610866575060006102b4565b6102b183835b8151815160009190828282106108825782610884565b815b90506000838310156108965783610898565b825b905060006108c2836108bc670de0b6b3a76400006108b6868461026f565b90610984565b906109dd565b66b1a2bc2ec50000101598975050505050505050565b60008060128363ffffffff161061090f5761090860128463ffffffff1603600a0a856109dd90919063ffffffff16565b90506102b1565b60128363ffffffff1610156102b1576109378463ffffffff808616601203600a0a9061098416565b949350505050565b6000816040015161095257506001610791565b602082015115806109665750428260200151115b1561097357506001610791565b81516000126107d857506001610791565b600082610993575060006102b4565b828202828482816109a057fe5b04146102b15760405162461bcd60e51b8152600401808060200182810382526021815260200180610be26021913960400191505060405180910390fd5b60006102b183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060008183610a695760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156105ba5781810151838201526020016105a2565b506000838581610a7557fe5b0495945050505050565b604051806060016040528060008152602001600081526020016000151581525090565b60405180608001604052806000815260200160008152602001600015158152602001600063ffffffff1681525090565b8051600381900b811461079157600080fd5b60008060408385031215610af6578182fd5b825180601b0b8114610b06578283fd5b602084015190925063ffffffff81168114610b1f578182fd5b809150509250929050565b600060808284031215610b3b578081fd5b6040516080810167ffffffffffffffff8282108183111715610b5957fe5b81604052845191508160070b8214610b6f578384fd5b9082526020840151908082168214610b85578384fd5b506020820152610b9760408401610ad2565b6040820152606083015160608201528091505092915050565b90815260200190565b6001600160a01b0391909116815260200190565b6020810160058310610bdb57fe5b9190529056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212201073e8a2cadddc0b9f8990d2ae7a01938f540069a79cb4384735351cab0d158564736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.