ETH Price: $2,712.38 (+1.69%)

Contract

0x56bC0Ec4049f25E7dd455B64d1c6318c1D9Ce789
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
FxChainlinkTwapOracle

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion
File 1 of 4 : FxChainlinkTwapOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

import "@openzeppelin/contracts/math/SafeMath.sol";

import { AggregatorV3Interface } from "../../price-oracle/interfaces/AggregatorV3Interface.sol";
import { ITwapOracle } from "../../price-oracle/interfaces/ITwapOracle.sol";

// solhint-disable not-rely-on-time
// solhint-disable reason-string

contract FxChainlinkTwapOracle is ITwapOracle {
  using SafeMath for uint256;

  uint256 private constant MAX_ITERATION = 500;

  /// @notice The twap duration.
  uint256 public immutable epoch;

  /// @notice Chainlink aggregator used as the data source.
  address public immutable chainlinkAggregator;

  /// @notice Minimum number of Chainlink rounds required in an epoch.
  uint256 public immutable chainlinkMinMessageCount;

  /// @notice Maximum gap between an epoch start and a previous Chainlink round for the round
  ///         to be used in TWAP calculation.
  /// @dev This should at least be equal to Chainlink's heartbeat duration.
  uint256 public immutable chainlinkMessageExpiration;

  /// @dev A multiplier that normalizes price from the Chainlink aggregator to 18 decimal places.
  uint256 private immutable _chainlinkPriceMultiplier;

  string public symbol;

  constructor(
    uint256 epoch_,
    address chainlinkAggregator_,
    uint256 chainlinkMinMessageCount_,
    uint256 chainlinkMessageExpiration_,
    string memory symbol_
  ) {
    require(chainlinkMinMessageCount_ > 0);

    epoch = epoch_;
    chainlinkAggregator = chainlinkAggregator_;
    chainlinkMinMessageCount = chainlinkMinMessageCount_;
    chainlinkMessageExpiration = chainlinkMessageExpiration_;
    uint256 decimal = AggregatorV3Interface(chainlinkAggregator_).decimals();
    _chainlinkPriceMultiplier = 10**(uint256(18).sub(decimal));
    symbol = symbol_;
  }

  /// @inheritdoc ITwapOracle
  function getLatest() external view override returns (uint256) {
    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(chainlinkAggregator).latestRoundData();
    require(updatedAt >= block.timestamp - chainlinkMessageExpiration, "Stale price oracle");
    return uint256(answer).mul(_chainlinkPriceMultiplier);
  }

  /// @inheritdoc ITwapOracle
  function getTwap(uint256 timestamp) external view override returns (uint256) {
    return _getTwapFromChainlink(timestamp);
  }

  /// @notice Search for the last round before the given timestamp. Zeros are returned
  ///         if the search fails.
  function findLastRoundBefore(uint256 timestamp)
    public
    view
    returns (
      uint80 roundID,
      int256 answer,
      uint256 updatedAt
    )
  {
    (roundID, answer, , updatedAt, ) = AggregatorV3Interface(chainlinkAggregator).latestRoundData();
    if (updatedAt < timestamp + epoch) {
      // Fast path: sequentially check each round when the target epoch is in the near past.
      for (uint256 i = 0; i < MAX_ITERATION && updatedAt >= timestamp && answer != 0; i++) {
        roundID--;
        (, answer, , updatedAt, ) = _getChainlinkRoundData(roundID);
      }
    } else {
      // Slow path: binary search. During the search, the `roundID` round is always updated
      // at or after the given timestamp, and the `leftRoundID` round is either invalid or
      // updated before the given timestamp.
      uint80 step = 1;
      uint80 leftRoundID = 0;
      while (step <= roundID) {
        leftRoundID = roundID - step;
        (, answer, , updatedAt, ) = _getChainlinkRoundData(leftRoundID);
        if (updatedAt < timestamp || answer == 0) {
          break;
        }
        step <<= 1;
        roundID = leftRoundID;
      }
      while (leftRoundID + 1 < roundID) {
        uint80 midRoundID = (leftRoundID + roundID) / 2;
        (, answer, , updatedAt, ) = _getChainlinkRoundData(midRoundID);
        if (updatedAt < timestamp || answer == 0) {
          leftRoundID = midRoundID;
        } else {
          roundID = midRoundID;
        }
      }
      roundID = leftRoundID;
      (, answer, , updatedAt, ) = _getChainlinkRoundData(roundID);
    }
    if (updatedAt >= timestamp || answer == 0) {
      // The last round before the epoch end is not found, due to either discontinuous
      // round IDs caused by a phase change or abnormal `updatedAt` timestamps.
      return (0, 0, 0);
    }
  }

  /// @dev Calculate TWAP of the given epoch from the Chainlink oracle.
  /// @param timestamp End timestamp of the epoch to be updated
  /// @return TWAP of the epoch calculated from Chainlink, or zero if there's no sufficient data
  function _getTwapFromChainlink(uint256 timestamp) private view returns (uint256) {
    require(block.timestamp >= timestamp, "Too soon");
    (uint80 roundID, int256 answer, uint256 updatedAt) = findLastRoundBefore(timestamp);
    if (answer == 0) {
      return 0;
    }
    uint256 sum = 0;
    uint256 sumTimestamp = timestamp;
    uint256 messageCount = 1;
    for (uint256 i = 0; i < MAX_ITERATION && updatedAt >= timestamp - epoch; i++) {
      sum = sum.add(uint256(answer).mul(sumTimestamp - updatedAt));
      sumTimestamp = updatedAt;
      if (roundID == 0) {
        break;
      }
      roundID--;
      (, int256 newAnswer, , uint256 newUpdatedAt, ) = _getChainlinkRoundData(roundID);
      if (newAnswer == 0 || newUpdatedAt > updatedAt || newUpdatedAt < timestamp - epoch - chainlinkMessageExpiration) {
        break; // Stop if the previous round is invalid
      }
      answer = newAnswer;
      updatedAt = newUpdatedAt;
      messageCount++;
    }
    if (messageCount >= chainlinkMinMessageCount) {
      // the only update is expired.
      if (messageCount == 1 && updatedAt < timestamp - chainlinkMessageExpiration) return 0;

      sum = sum.add(uint256(answer).mul(sumTimestamp - (timestamp - epoch)));
      return sum.mul(_chainlinkPriceMultiplier) / epoch;
    } else {
      return 0;
    }
  }

  /// @dev Call `chainlinkAggregator.getRoundData(roundID)`. Return zero if the call reverts.
  function _getChainlinkRoundData(uint80 roundID)
    private
    view
    returns (
      uint80,
      int256,
      uint256,
      uint256,
      uint80
    )
  {
    (bool success, bytes memory returnData) = chainlinkAggregator.staticcall(
      abi.encodePacked(AggregatorV3Interface.getRoundData.selector, abi.encode(roundID))
    );
    if (success) {
      return abi.decode(returnData, (uint80, int256, uint256, uint256, uint80));
    } else {
      return (roundID, 0, 0, 0, roundID);
    }
  }
}

File 2 of 4 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @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, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @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) {
        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, reverting 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) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * 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);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * 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) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * 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;
    }
}

File 3 of 4 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0 || ^0.8.0;

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function latestAnswer() external view returns (uint256);

  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}

File 4 of 4 : ITwapOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0 || ^0.8.0;

interface ITwapOracle {
  /// @notice Return TWAP with 18 decimal places in the epoch ending at the specified timestamp.
  ///         Zero is returned if TWAP in the epoch is not available.
  /// @param timestamp End Timestamp in seconds of the epoch
  /// @return TWAP (18 decimal places) in the epoch, or zero if not available
  function getTwap(uint256 timestamp) external view returns (uint256);

  /// @notice Return the latest price with 18 decimal places.
  function getLatest() external view returns (uint256);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"epoch_","type":"uint256"},{"internalType":"address","name":"chainlinkAggregator_","type":"address"},{"internalType":"uint256","name":"chainlinkMinMessageCount_","type":"uint256"},{"internalType":"uint256","name":"chainlinkMessageExpiration_","type":"uint256"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"chainlinkAggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlinkMessageExpiration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlinkMinMessageCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"findLastRoundBefore","outputs":[{"internalType":"uint80","name":"roundID","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getTwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100885760003560e01c806392ce710f1161005b57806392ce710f146100db57806395d89b41146101205780639f0571511461019d578063c36af460146101ba57610088565b80632ab4dd191461008d5780635004d36c146100a75780636a077536146100cb578063900cf0cf146100d3575b600080fd5b6100956101c2565b60408051918252519081900360200190f35b6100af6101e6565b604080516001600160a01b039092168252519081900360200190f35b61009561020a565b61009561022e565b6100f8600480360360208110156100f157600080fd5b5035610252565b604080516001600160501b039094168452602084019290925282820152519081900360600190f35b610128610463565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561016257818101518382015260200161014a565b50505050905090810190601f16801561018f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610095600480360360208110156101b357600080fd5b50356104f1565b610095610504565b7f000000000000000000000000000000000000000000000000000000000001fa4081565b7f0000000000000000000000008751f736e94f6cd167e8c5b97e245680fbd9cc3681565b7f000000000000000000000000000000000000000000000000000000000000000181565b7f000000000000000000000000000000000000000000000000000000000000070881565b60008060007f0000000000000000000000008751f736e94f6cd167e8c5b97e245680fbd9cc366001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156102b057600080fd5b505afa1580156102c4573d6000803e3d6000fd5b505050506040513d60a08110156102da57600080fd5b508051602082015160609092015190945090925090507f000000000000000000000000000000000000000000000000000000000000070884018110156103655760005b6101f48110801561032e5750848210155b801561033957508215155b1561035f576000199093019261034e8461069c565b50919550909350505060010161031d565b50610440565b600160005b846001600160501b0316826001600160501b0316116103c757508084036103908161069c565b509196509094505050858310806103a5575083155b156103af576103c7565b935060011b6a01fffffffffffffffffffe168361036a565b846001600160501b0316816001016001600160501b031610156104285760028582016001600160501b0316046103fc8161069c565b50919750909550505086841080610411575084155b1561041e57809150610422565b8095505b506103c7565b8094506104348561069c565b50919650909450505050505b838110158061044d575081155b1561045c575060009150819050805b9193909250565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104e95780601f106104be576101008083540402835291602001916104e9565b820191906000526020600020905b8154815290600101906020018083116104cc57829003601f168201915b505050505081565b60006104fc82610877565b90505b919050565b60008060007f0000000000000000000000008751f736e94f6cd167e8c5b97e245680fbd9cc366001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561056257600080fd5b505afa158015610576573d6000803e3d6000fd5b505050506040513d60a081101561058c57600080fd5b50602081015160609091015190925090507f000000000000000000000000000000000000000000000000000000000001fa404203811015610609576040805162461bcd60e51b81526020600482015260126024820152715374616c65207072696365206f7261636c6560701b604482015290519081900360640190fd5b610633827f00000000000000000000000000000000000000000000000000000002540be400610af8565b9250505090565b600082821115610691576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b60008060008060008060007f0000000000000000000000008751f736e94f6cd167e8c5b97e245680fbd9cc366001600160a01b0316639a6fc8f560e01b8960405160200180826001600160501b0316815260200191505060405160208183030381529060405260405160200180836001600160e01b031916815260040182805190602001908083835b602083106107445780518252601f199092019160209182019101610725565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040526040518082805190602001908083835b602083106107a85780518252601f199092019160209182019101610789565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610808576040519150601f19603f3d011682016040523d82523d6000602084013e61080d565b606091505b5091509150811561085a578080602001905160a081101561082d57600080fd5b508051602082015160408301516060840151608090940151929a509098509650909450925061086e915050565b8760008060008b9650965096509650965050505b91939590929450565b6000814210156108b9576040805162461bcd60e51b81526020600482015260086024820152672a37b79039b7b7b760c11b604482015290519081900360640190fd5b60008060006108c785610252565b92509250925081600014156108e257600093505050506104ff565b6000856001825b6101f48110801561091c57507f000000000000000000000000000000000000000000000000000000000000070889038510155b156109e25761093761093087878603610af8565b8590610b58565b93508492506001600160501b03871661094f576109e2565b600019909601956000806109628961069c565b50935050925050816000148061097757508681115b806109c557507f000000000000000000000000000000000000000000000000000000000001fa407f00000000000000000000000000000000000000000000000000000000000007088c030381105b156109d15750506109e2565b9096509450600191820191016108e9565b507f00000000000000000000000000000000000000000000000000000000000000018110610ae957806001148015610a3b57507f000000000000000000000000000000000000000000000000000000000001fa40880384105b15610a4f57600096505050505050506104ff565b610a87610a80867f00000000000000000000000000000000000000000000000000000000000007088b038503610af8565b8490610b58565b92507f0000000000000000000000000000000000000000000000000000000000000708610ad4847f00000000000000000000000000000000000000000000000000000002540be400610af8565b81610adb57fe5b0496505050505050506104ff565b600096505050505050506104ff565b600082610b0757506000610696565b82820282848281610b1457fe5b0414610b515760405162461bcd60e51b8152600401808060200182810382526021815260200180610bb36021913960400191505060405180910390fd5b9392505050565b600082820183811015610b51576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122068889fb82b49525a79f2e89a8be1eff8c5efed3e32d94fa5bc27dbde3296f13c64736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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.