Source Code
Overview
S Balance
0 S
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xb87b0bC8...e35F0fbAE The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
PriceFeed
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 2000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interfaces/IPriceFeed.sol"; import "../interfaces/IBandStdReference.sol"; import "../interfaces/IChainlinkAggregator.sol"; import "../dependencies/openzeppelin/contracts/SafeMath.sol"; /* * PriceFeed for mainnet deployment, to be connected to Chainlink's live ETH:USD aggregator reference * contract, and a wrapper contract bandOracle, which connects to BandMaster contract. * * The PriceFeed uses Chainlink as primary oracle, and Band as fallback. It contains logic for * switching oracles based on oracle failures, timeouts, and conditions for returning to the primary * Chainlink oracle. */ contract PriceFeed is IPriceFeed { using SafeMath for uint256; uint constant public DECIMAL_PRECISION = 1e18; IChainlinkAggregator public chainlinkOracle; // Mainnet Chainlink aggregator IBandStdReference public bandOracle; // Wrapper contract that calls the Band system string public bandBase; string public constant bandQuote = "USD"; // Use to convert a price answer to an 18-digit precision uint uint constant public TARGET_DIGITS = 18; // Maximum time period allowed since Chainlink's latest round data timestamp, beyond which Chainlink is considered frozen. // For stablecoins we recommend 90000, as Chainlink updates once per day when there is no significant price movement // For volatile assets we recommend 14400 (4 hours) uint immutable public TIMEOUT; // Maximum deviation allowed between two consecutive Chainlink oracle prices. 18-digit precision. uint constant public 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 Chainlink oracle. 18-digit precision. */ uint constant public MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES = 5e16; // 5% // The last good price seen from an oracle by Liquity uint public lastGoodPrice; struct ChainlinkResponse { uint80 roundId; uint256 answer; uint256 timestamp; bool success; uint8 decimals; } struct BandResponse { uint256 value; uint256 timestamp; bool success; } enum Status { chainlinkWorking, usingBandChainlinkUntrusted, bothOraclesUntrusted, usingBandChainlinkFrozen, usingChainlinkBandUntrusted } // The current status of the PricFeed, which determines the conditions for the next price fetch attempt Status public status; event LastGoodPriceUpdated(uint _lastGoodPrice); event PriceFeedStatusChanged(Status newStatus); // --- Dependency setters --- constructor( IChainlinkAggregator _chainlinkOracleAddress, IBandStdReference _bandOracleAddress, uint256 _timeout, string memory _bandBase ) { chainlinkOracle = _chainlinkOracleAddress; bandOracle = _bandOracleAddress; TIMEOUT = _timeout; bandBase = _bandBase; // Explicitly set initial system status status = Status.chainlinkWorking; // Get an initial price from Chainlink to serve as first reference for lastGoodPrice ChainlinkResponse memory chainlinkResponse = _getCurrentChainlinkResponse(); ChainlinkResponse memory prevChainlinkResponse = _getPrevChainlinkResponse(chainlinkResponse.roundId, chainlinkResponse.decimals); require( !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) && block.timestamp.sub(chainlinkResponse.timestamp) < _timeout, "PriceFeed: Chainlink must be working and current" ); lastGoodPrice = _scaleChainlinkPriceByDigits(uint256(chainlinkResponse.answer), chainlinkResponse.decimals); } // --- 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 (Chainlink) and a fallback oracle (Band) in case Chainlink fails. If both fail, * it uses the last good price seen by Liquity. * */ function fetchPrice() external view override returns (uint) { (,uint price) = _fetchPrice(); return price; } function updatePrice() external override returns (uint) { (Status newStatus, uint price) = _fetchPrice(); lastGoodPrice = price; if (status != newStatus) { status = newStatus; emit PriceFeedStatusChanged(newStatus); } return price; } function _fetchPrice() internal view returns (Status, uint) { // Get current and previous price data from Chainlink, and current price data from Band ChainlinkResponse memory chainlinkResponse = _getCurrentChainlinkResponse(); ChainlinkResponse memory prevChainlinkResponse = _getPrevChainlinkResponse(chainlinkResponse.roundId, chainlinkResponse.decimals); BandResponse memory bandResponse = _getCurrentBandResponse(); // --- CASE 1: System fetched last price from Chainlink --- if (status == Status.chainlinkWorking) { // If Chainlink is broken, try Band if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) { // If Band is broken then both oracles are untrusted, so return the last good price if (_bandIsBroken(bandResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } /* * If Band is only frozen but otherwise returning valid data, return the last good price. */ if (_bandIsFrozen(bandResponse)) { return (Status.usingBandChainlinkUntrusted, lastGoodPrice); } // If Chainlink is broken and Band is working, switch to Band and return current Band price return (Status.usingBandChainlinkUntrusted, bandResponse.value); } // If Chainlink is frozen, try Band if (_chainlinkIsFrozen(chainlinkResponse)) { // If Band is broken too, remember Band broke, and return last good price if (_bandIsBroken(bandResponse)) { return (Status.usingChainlinkBandUntrusted, lastGoodPrice); } // If Band is frozen or working, remember Chainlink froze, and switch to Band if (_bandIsFrozen(bandResponse)) {return (Status.usingBandChainlinkFrozen, lastGoodPrice);} // If Band is working, use it return (Status.usingBandChainlinkFrozen, bandResponse.value); } // If Chainlink price has changed by > 50% between two consecutive rounds, compare it to Band's price if (_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)) { // If Band is broken, both oracles are untrusted, and return last good price if (_bandIsBroken(bandResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } // If Band is frozen, switch to Band and return last good price if (_bandIsFrozen(bandResponse)) { return (Status.usingBandChainlinkUntrusted, lastGoodPrice); } /* * If Band is live and both oracles have a similar price, conclude that Chainlink's large price deviation between * two consecutive rounds was likely a legitmate market price movement, and so continue using Chainlink */ if (_bothOraclesSimilarPrice(chainlinkResponse, bandResponse)) { return (Status.chainlinkWorking, chainlinkResponse.answer); } // If Band is live but the oracles differ too much in price, conclude that Chainlink's initial price deviation was // an oracle failure. Switch to Band, and use Band price return (Status.usingBandChainlinkUntrusted, bandResponse.value); } // If Chainlink is working and Band is broken, remember Band is broken if (_bandIsBroken(bandResponse)) { return (Status.usingChainlinkBandUntrusted, chainlinkResponse.answer); } // If Chainlink is working, return Chainlink current price (no status change) return (Status.chainlinkWorking, chainlinkResponse.answer); } // --- CASE 2: The system fetched last price from Band --- if (status == Status.usingBandChainlinkUntrusted) { // If both Band and Chainlink are live, unbroken, and reporting similar prices, switch back to Chainlink if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(chainlinkResponse, prevChainlinkResponse, bandResponse)) { return (Status.chainlinkWorking, chainlinkResponse.answer); } if (_bandIsBroken(bandResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } /* * If Band is only frozen but otherwise returning valid data, just return the last good price. * Band may need to be tipped to return current data. */ if (_bandIsFrozen(bandResponse)) {return (Status.usingBandChainlinkUntrusted, lastGoodPrice);} // Otherwise, use Band price return (Status.usingBandChainlinkUntrusted, bandResponse.value); } // --- 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 Chainlink. */ if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(chainlinkResponse, prevChainlinkResponse, bandResponse)) { return (Status.chainlinkWorking, chainlinkResponse.answer); } // Otherwise, return the last good price - both oracles are still untrusted (no status change) return (Status.bothOraclesUntrusted, lastGoodPrice); } // --- CASE 4: Using Band, and Chainlink is frozen --- if (status == Status.usingBandChainlinkFrozen) { if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) { // If both Oracles are broken, return last good price if (_bandIsBroken(bandResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } // If Chainlink is broken, remember it and switch to using Band if (_bandIsFrozen(bandResponse)) {return (Status.usingBandChainlinkUntrusted, lastGoodPrice);} // If Band is working, return Band current price return (Status.usingBandChainlinkUntrusted, bandResponse.value); } if (_chainlinkIsFrozen(chainlinkResponse)) { // if Chainlink is frozen and Band is broken, remember Band broke, and return last good price if (_bandIsBroken(bandResponse)) { return (Status.usingChainlinkBandUntrusted, lastGoodPrice); } // If both are frozen, just use lastGoodPrice if (_bandIsFrozen(bandResponse)) {return (Status.usingBandChainlinkFrozen, lastGoodPrice);} // if Chainlink is frozen and Band is working, keep using Band (no status change) return (Status.usingBandChainlinkFrozen, bandResponse.value); } // if Chainlink is live and Band is broken, remember Band broke, and return Chainlink price if (_bandIsBroken(bandResponse)) { return (Status.usingChainlinkBandUntrusted, chainlinkResponse.answer); } // If Chainlink is live and Band is frozen, just use last good price (no status change) since we have no basis for comparison if (_bandIsFrozen(bandResponse)) {return (Status.usingBandChainlinkFrozen, lastGoodPrice);} // If Chainlink is live and Band is working, compare prices. Switch to Chainlink // if prices are within 5%, and return Chainlink price. if (_bothOraclesSimilarPrice(chainlinkResponse, bandResponse)) { return (Status.chainlinkWorking, chainlinkResponse.answer); } // Otherwise if Chainlink is live but price not within 5% of Band, distrust Chainlink, and return Band price return (Status.usingBandChainlinkUntrusted, bandResponse.value); } // --- CASE 5: Using Chainlink, Band is untrusted --- if (status == Status.usingChainlinkBandUntrusted) { // If Chainlink breaks, now both oracles are untrusted if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } // If Chainlink is frozen, return last good price (no status change) if (_chainlinkIsFrozen(chainlinkResponse)) { return (Status.usingChainlinkBandUntrusted, lastGoodPrice); } // If Chainlink and Band are both live, unbroken and similar price, switch back to chainlinkWorking and return Chainlink price if (_bothOraclesLiveAndUnbrokenAndSimilarPrice(chainlinkResponse, prevChainlinkResponse, bandResponse)) { return (Status.chainlinkWorking, chainlinkResponse.answer); } // If Chainlink is live but deviated >50% from it's previous price and Band is still untrusted, switch // to bothOraclesUntrusted and return last good price if (_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)) { return (Status.bothOraclesUntrusted, lastGoodPrice); } // Otherwise if Chainlink is live and deviated <50% from it's previous price and Band is still untrusted, // return Chainlink price (no status change) return (Status.usingChainlinkBandUntrusted, chainlinkResponse.answer); } } // --- Helper functions --- /* Chainlink 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) Chainlink is the PriceFeed's preferred primary oracle - having two consecutive valid round responses adds * peace of mind when using or returning to Chainlink. */ function _chainlinkIsBroken(ChainlinkResponse memory _currentResponse, ChainlinkResponse memory _prevResponse) internal view returns (bool) { return _badChainlinkResponse(_currentResponse) || _badChainlinkResponse(_prevResponse); } function _badChainlinkResponse(ChainlinkResponse memory _response) internal view returns (bool) { // Check for response call reverted if (!_response.success) {return true;} // Check for an invalid roundId that is 0 if (_response.roundId == 0) {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 _chainlinkIsFrozen(ChainlinkResponse memory _response) internal view returns (bool) { return block.timestamp.sub(_response.timestamp) > TIMEOUT; } function _chainlinkPriceChangeAboveMax(ChainlinkResponse memory _currentResponse, ChainlinkResponse memory _prevResponse) internal pure returns (bool) { uint currentScaledPrice = _currentResponse.answer; uint prevScaledPrice = _prevResponse.answer; uint minPrice = (currentScaledPrice < prevScaledPrice) ? currentScaledPrice : prevScaledPrice; uint maxPrice = (currentScaledPrice >= prevScaledPrice) ? currentScaledPrice : prevScaledPrice; /* * Use the larger price as the denominator: * - If price decreased, the percentage deviation is in relation to the the previous price. * - If price increased, the percentage deviation is in relation to the current price. */ uint percentDeviation = maxPrice.sub(minPrice).mul(DECIMAL_PRECISION).div(maxPrice); // Return true if price has more than doubled, or more than halved. return percentDeviation > MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND; } function _bandIsBroken(BandResponse 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.value == 0) {return true;} return false; } function _bandIsFrozen(BandResponse memory _bandResponse) internal view returns (bool) { return block.timestamp.sub(_bandResponse.timestamp) > TIMEOUT; } function _bothOraclesLiveAndUnbrokenAndSimilarPrice ( ChainlinkResponse memory _chainlinkResponse, ChainlinkResponse memory _prevChainlinkResponse, BandResponse memory _bandResponse ) internal view returns (bool) { // Return false if either oracle is broken or frozen if ( _bandIsBroken(_bandResponse) || _bandIsFrozen(_bandResponse) || _chainlinkIsBroken(_chainlinkResponse, _prevChainlinkResponse) || _chainlinkIsFrozen(_chainlinkResponse) ) { return false; } return _bothOraclesSimilarPrice(_chainlinkResponse, _bandResponse); } function _bothOraclesSimilarPrice( ChainlinkResponse memory _chainlinkResponse, BandResponse memory _bandResponse) internal pure returns (bool) { uint scaledChainlinkPrice = _chainlinkResponse.answer; uint scaledBandPrice = _bandResponse.value; // Get the relative price difference between the oracles. Use the lower price as the denominator, i.e. the reference for the calculation. uint minPrice = (scaledBandPrice < scaledChainlinkPrice) ? scaledBandPrice : scaledChainlinkPrice; uint maxPrice = (scaledBandPrice >= scaledChainlinkPrice) ? scaledBandPrice : scaledChainlinkPrice; 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 _scaleChainlinkPriceByDigits(uint _price, uint _answerDigits) internal pure returns (uint) { /* * Convert the price returned by the Chainlink oracle to an 18-digit decimal for use by Liquity. * At date of Liquity launch, Chainlink uses an 8-digit price, but we also handle the possibility of * future changes. * */ uint price; if (_answerDigits >= TARGET_DIGITS) { // Scale the returned price value down to Liquity's target precision price = _price.div(10 ** (_answerDigits - TARGET_DIGITS)); } else if (_answerDigits < TARGET_DIGITS) { // Scale the returned price value up to Liquity's target precision price = _price.mul(10 ** (TARGET_DIGITS - _answerDigits)); } return price; } // --- Oracle response wrapper functions --- function _getCurrentBandResponse() internal view returns (BandResponse memory bandResponse) { try bandOracle.getReferenceData(bandBase, bandQuote) returns ( uint256 value, uint256 lastUpdatedBase, uint256 lastUpdatedQuote ) { // If call to Band succeeds, return the response and success = true bandResponse.value = value; bandResponse.timestamp = lastUpdatedBase < lastUpdatedQuote ? lastUpdatedBase : lastUpdatedQuote; bandResponse.success = true; return (bandResponse); }catch { // If call to Band reverts, return a zero response with success = false return (bandResponse); } } function _getCurrentChainlinkResponse() internal view returns (ChainlinkResponse memory chainlinkResponse) { // First, try to get current decimal precision: try chainlinkOracle.decimals() returns (uint8 decimals) { // If call to Chainlink succeeds, record the current decimal precision chainlinkResponse.decimals = decimals; } catch { // If call to Chainlink aggregator reverts, return a zero response with success = false return chainlinkResponse; } // Secondly, try to get latest price data: try chainlinkOracle.latestRoundData() returns ( uint80 roundId, int256 answer, uint256 /* startedAt */, uint256 timestamp, uint80 /* answeredInRound */ ) { // If call to Chainlink succeeds, return the response and success = true chainlinkResponse.roundId = roundId; chainlinkResponse.answer = _scaleChainlinkPriceByDigits(uint256(answer), chainlinkResponse.decimals); chainlinkResponse.timestamp = timestamp; chainlinkResponse.success = true; return chainlinkResponse; } catch { // If call to Chainlink aggregator reverts, return a zero response with success = false return chainlinkResponse; } } function _getPrevChainlinkResponse(uint80 _currentRoundId, uint8 _currentDecimals) internal view returns (ChainlinkResponse memory prevChainlinkResponse) { /* * NOTE: Chainlink only offers a current decimals() value - there is no way to obtain the decimal precision used in a * previous round. We assume the decimals used in the previous round are the same as the current round. */ // Try to get the price data from the previous round: try chainlinkOracle.getRoundData(_currentRoundId - 1) returns ( uint80 roundId, int256 answer, uint256 /* startedAt */, uint256 timestamp, uint80 /* answeredInRound */ ) { // If call to Chainlink succeeds, return the response and success = true prevChainlinkResponse.roundId = roundId; prevChainlinkResponse.answer = _scaleChainlinkPriceByDigits(uint256(answer), _currentDecimals); prevChainlinkResponse.timestamp = timestamp; prevChainlinkResponse.decimals = _currentDecimals; prevChainlinkResponse.success = true; return prevChainlinkResponse; } catch { // If call to Chainlink aggregator reverts, return a zero response with success = false return prevChainlinkResponse; } } }
// 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; } }
pragma solidity 0.7.6; interface IBandStdReference { /// Returns the price data for the given base/quote pair. Revert if not available. function getReferenceData(string memory _base, string memory _quote) external view returns (uint256 rate, uint256 lastUpdatedBase, uint256 lastUpdatedRate); }
// SPDX-License-Identifier: MIT // Code from https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol pragma solidity 0.7.6; interface IChainlinkAggregator { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. 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 ); }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; interface IPriceFeed { // --- Function --- function fetchPrice() external view returns (uint); function updatePrice() external returns (uint); }
{ "optimizer": { "enabled": true, "runs": 2000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"inputs":[{"internalType":"contract IChainlinkAggregator","name":"_chainlinkOracleAddress","type":"address"},{"internalType":"contract IBandStdReference","name":"_bandOracleAddress","type":"address"},{"internalType":"uint256","name":"_timeout","type":"uint256"},{"internalType":"string","name":"_bandBase","type":"string"}],"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 PriceFeed.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":"bandBase","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bandOracle","outputs":[{"internalType":"contract IBandStdReference","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bandQuote","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlinkOracle","outputs":[{"internalType":"contract IChainlinkAggregator","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":"status","outputs":[{"internalType":"enum PriceFeed.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updatePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100df5760003560e01c806358a6aa881161008c578063a20baee611610066578063a20baee6146101fd578063afa22d1f14610205578063ef06e72c1461020d578063f56f48f214610215576100df565b806358a6aa88146101bc578063673a7e28146101c4578063956dcd1f146101cc576100df565b8063200d2ed2116100bd578063200d2ed21461010e57806326d182d51461013757806345079cb4146101b4576100df565b80630490be83146100e45780630fdb11cf146100fe5780631be5c92f14610106575b600080fd5b6100ec61021d565b60408051918252519081900360200190f35b6100ec610223565b6100ec610236565b61011661023b565b6040518082600481111561012657fe5b815260200191505060405180910390f35b61013f610244565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610179578181015183820152602001610161565b50505050905090810190601f1680156101a65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6100ec6102cf565b6100ec6102da565b6100ec6102e6565b6101d46103a3565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100ec6103bf565b61013f6103cb565b6101d4610404565b6100ec610420565b60035481565b60008061022e61052a565b925050505b90565b601281565b60045460ff1681565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156102c75780601f1061029c576101008083540402835291602001916102c7565b820191906000526020600020905b8154815290600101906020018083116102aa57829003601f168201915b505050505081565b66b1a2bc2ec5000081565b6706f05b59d3b2000081565b60008060006102f361052a565b6003819055909250905081600481111561030957fe5b6004805460ff169081111561031a57fe5b1461039d57600480548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001838381111561035557fe5b02179055507f5c57579a8214fe4f710c1c56fa829f045b9fa6d225a744225a30c32188064d4e826040518082600481111561038c57fe5b815260200191505060405180910390a15b91505090565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b670de0b6b3a764000081565b6040518060400160405280600381526020017f555344000000000000000000000000000000000000000000000000000000000081525081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b7f000000000000000000000000000000000000000000000000000000000000384081565b600061048683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061088a565b90505b92915050565b600061048683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610926565b6000826104e057506000610489565b828202828482816104ed57fe5b04146104865760405162461bcd60e51b81526004018080602001828103825260218152602001806111356021913960400191505060405180910390fd5b600080600061053761098b565b9050600061054d82600001518360800151610b1c565b90506000610559610c2f565b905060006004805460ff169081111561056e57fe5b14156106c75761057e8383610e19565b156105d05761058c81610e33565b156105a257600260035494509450505050610886565b6105ab81610e7e565b156105c157600160035494509450505050610886565b51600194509250610886915050565b6105d983610ebf565b1561062a576105e781610e33565b156105fd57600460035494509450505050610886565b61060681610e7e565b1561061b576003805494509450505050610886565b51600394509250610886915050565b6106348383610ef9565b156106975761064281610e33565b1561065857600260035494509450505050610886565b61066181610e7e565b1561067757600160035494509450505050610886565b6106818382610f6b565b156105c157505060200151600092509050610886565b6106a081610e33565b156106b657505060200151600492509050610886565b505060200151600092509050610886565b60016004805460ff16908111156106da57fe5b141561070a576106eb838383610fce565b1561070157505060200151600092509050610886565b61058c81610e33565b60026004805460ff169081111561071d57fe5b14156107555761072e838383610fce565b1561074457505060200151600092509050610886565b600260035494509450505050610886565b60036004805460ff169081111561076857fe5b14156107da576107788383610e19565b156107865761058c81610e33565b61078f83610ebf565b1561079d576105e781610e33565b6107a681610e33565b156107bc57505060200151600492509050610886565b6107c581610e7e565b15610677576003805494509450505050610886565b6004805460ff16818111156107eb57fe5b1415610882576107fb8383610e19565b1561081157600260035494509450505050610886565b61081a83610ebf565b1561083057600460035494509450505050610886565b61083b838383610fce565b1561085157505060200151600092509050610886565b61085b8383610ef9565b1561087157600260035494509450505050610886565b505060200151600492509050610886565b5050505b9091565b600081848411156109195760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156108de5781810151838201526020016108c6565b50505050905090810190601f16801561090b5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50508183035b9392505050565b600081836109755760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156108de5781810151838201526020016108c6565b50600083858161098157fe5b0495945050505050565b6109936110e3565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156109f957600080fd5b505afa925050508015610a1e57506040513d6020811015610a1957600080fd5b505160015b610a2757610233565b60ff16608082015260008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015610a9557600080fd5b505afa925050508015610ad757506040513d60a0811015610ab557600080fd5b5080516020820151604083015160608401516080909401519293919290919060015b610ae057610233565b69ffffffffffffffffffff851686526080860151610b0290859060ff16611026565b602087015250604085015250506001606083015250610233565b610b246110e3565b600054604080517f9a6fc8f500000000000000000000000000000000000000000000000000000000815269ffffffffffffffffffff6000198701166004820152905173ffffffffffffffffffffffffffffffffffffffff90921691639a6fc8f59160248082019260a092909190829003018186803b158015610ba557600080fd5b505afa925050508015610be757506040513d60a0811015610bc557600080fd5b5080516020820151604083015160608401516080909401519293919290919060015b610bf057610489565b69ffffffffffffffffffff85168652610c0c8460ff8916611026565b602087015250604085015250505060ff8216608082015260016060820152610489565b610c37611111565b60018054604080518082018252600381527f5553440000000000000000000000000000000000000000000000000000000000602082015281517f65555bcc00000000000000000000000000000000000000000000000000000000815260048101928352600280546000199681161561010002969096019095168590046044820181905273ffffffffffffffffffffffffffffffffffffffff909416946365555bcc94909391829160248201916064019086908015610d365780601f10610d0b57610100808354040283529160200191610d36565b820191906000526020600020905b815481529060010190602001808311610d1957829003601f168201915b5050838103825284518152845160209182019186019080838360005b83811015610d6a578181015183820152602001610d52565b50505050905090810190601f168015610d975780820380516001836020036101000a031916815260200191505b5094505050505060606040518083038186803b158015610db657600080fd5b505afa925050508015610dea57506040513d6060811015610dd657600080fd5b508051602082015160409092015190919060015b610df357610233565b828452808210610e035780610e05565b815b602085015250506001604083015250610233565b6000610e2483611081565b80610486575061048682611081565b60008160400151610e4657506001610e79565b60208201511580610e5a5750428260200151115b15610e6757506001610e79565b8151610e7557506001610e79565b5060005b919050565b60007f0000000000000000000000000000000000000000000000000000000000003840610eb883602001514261044490919063ffffffff16565b1192915050565b60007f0000000000000000000000000000000000000000000000000000000000003840610eb883604001514261044490919063ffffffff16565b602080830151908201516000919082818310610f155781610f17565b825b9050600082841015610f295782610f2b565b835b90506000610f5582610f4f670de0b6b3a7640000610f498388610444565b906104d1565b9061048f565b6706f05b59d3b200001098975050505050505050565b602082015181516000919082828210610f845782610f86565b815b9050600083831015610f985783610f9a565b825b90506000610fb883610f4f670de0b6b3a7640000610f498684610444565b66b1a2bc2ec50000101598975050505050505050565b6000610fd982610e33565b80610fe85750610fe882610e7e565b80610ff85750610ff88484610e19565b80611007575061100784610ebf565b156110145750600061091f565b61101e8483610f6b565b949350505050565b6000806012831061106757611060847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee8501600a0a61048f565b9050610486565b60128310156104865761101e846012859003600a0a6104d1565b6000816060015161109457506001610e79565b815169ffffffffffffffffffff166110ae57506001610e79565b604082015115806110c25750428260400151115b156110cf57506001610e79565b6000826020015113610e7557506001610e79565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b60405180606001604052806000815260200160008152602001600015158152509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220080557f8f1170176c468c5266401b3267c409ba97268ec1b5d02ffcce263822c64736f6c63430007060033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
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.