ETH Price: $1,597.50 (+0.84%)
 

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

Contract Source Code Verified (Exact Match)

Contract Name:
SfrxEthUsdDualOracle

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 99999999 runs

Other Settings:
paris EvmVersion
File 1 of 23 : SfrxEthUsdDualOracle.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ======================= SfrxEthUsdDualOracle =======================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// ====================================================================
import { Timelock2Step } from "frax-std/access-control/v1/Timelock2Step.sol";
import { ITimelock2Step } from "frax-std/access-control/v1/interfaces/ITimelock2Step.sol";
import { DualOracleBase, ConstructorParams as DualOracleBaseParams } from "src/contracts/DualOracleBase.sol";
import { CurvePoolEmaPriceOracleWithMinMax, ConstructorParams as CurvePoolEmaPriceOracleWithMinMaxParams } from "./abstracts/CurvePoolEmaPriceOracleWithMinMax.sol";
import { EthUsdChainlinkOracleWithMaxDelay, ConstructorParams as EthUsdChainlinkOracleWithMaxDelayParams } from "./abstracts/EthUsdChainlinkOracleWithMaxDelay.sol";
import { FraxUsdChainlinkOracleWithMaxDelay, ConstructorParams as FraxUsdChainlinkOracleWithMaxDelayParams } from "./abstracts/FraxUsdChainlinkOracleWithMaxDelay.sol";
import { UniswapV3SingleTwapOracle, ConstructorParams as UniswapV3SingleTwapOracleParams } from "./abstracts/UniswapV3SingleTwapOracle.sol";
import { IDualOracle } from "interfaces/IDualOracle.sol";
import { IPriceSource } from "./frax-oracle/interfaces/IPriceSource.sol";
import { IPriceSourceReceiver } from "./frax-oracle/interfaces/IPriceSourceReceiver.sol";
import { ISfrxEth } from "interfaces/ISfrxEth.sol";

struct ConstructorParams {
    // = DualOracleBase
    address baseToken0; // sfrxEth
    uint8 baseToken0Decimals;
    address quoteToken0; // usd
    uint8 quoteToken0Decimals;
    address baseToken1; // sfrxEth
    uint8 baseToken1Decimals;
    address quoteToken1; // usd
    uint8 quoteToken1Decimals;
    // = UniswapV3SingleTwapOracle
    address frxEthErc20;
    address fraxErc20;
    address uniV3PairAddress;
    uint32 twapDuration;
    // = FraxUsdChainlinkOracleWithMaxDelay
    address fraxUsdChainlinkFeedAddress;
    uint256 fraxUsdMaximumOracleDelay;
    // = EthUsdChainlinkOracleWithMaxDelay
    address ethUsdChainlinkFeed;
    uint256 maxEthUsdOracleDelay;
    // = CurvePoolEmaPriceOracleWithMinMax
    address curvePoolEmaPriceOracleAddress;
    uint256 minimumCurvePoolEma;
    uint256 maximumCurvePoolEma;
    // = Timelock2Step
    address timelockAddress;
    // = sfrxEth Erc4626
    address sfrxEthErc4626Address;
}

/// @title FrxEthWethDualOracle
/// @notice This price source feeds prices to the FraxOracle system
/// @dev Returns prices of Frax assets in Ether
contract SfrxEthUsdDualOracle is
    DualOracleBase,
    CurvePoolEmaPriceOracleWithMinMax,
    UniswapV3SingleTwapOracle,
    FraxUsdChainlinkOracleWithMaxDelay,
    EthUsdChainlinkOracleWithMaxDelay,
    IPriceSource,
    Timelock2Step
{
    /// @notice The address of the Erc4626 token contract for sfrxEth
    ISfrxEth public immutable SFRXETH_ERC4626;

    constructor(
        ConstructorParams memory _params
    )
        DualOracleBase(
            DualOracleBaseParams({
                baseToken0: _params.baseToken0,
                baseToken0Decimals: _params.baseToken0Decimals,
                quoteToken0: _params.quoteToken0,
                quoteToken0Decimals: _params.quoteToken0Decimals,
                baseToken1: _params.baseToken1,
                baseToken1Decimals: _params.baseToken1Decimals,
                quoteToken1: _params.quoteToken1,
                quoteToken1Decimals: _params.quoteToken1Decimals
            })
        )
        CurvePoolEmaPriceOracleWithMinMax(
            CurvePoolEmaPriceOracleWithMinMaxParams({
                curvePoolEmaPriceOracleAddress: _params.curvePoolEmaPriceOracleAddress,
                minimumCurvePoolEma: _params.minimumCurvePoolEma,
                maximumCurvePoolEma: _params.maximumCurvePoolEma
            })
        )
        UniswapV3SingleTwapOracle(
            UniswapV3SingleTwapOracleParams({
                uniswapV3PairAddress: _params.uniV3PairAddress,
                twapDuration: _params.twapDuration,
                baseToken: _params.frxEthErc20,
                quoteToken: _params.fraxErc20
            })
        )
        EthUsdChainlinkOracleWithMaxDelay(
            EthUsdChainlinkOracleWithMaxDelayParams({
                ethUsdChainlinkFeedAddress: _params.ethUsdChainlinkFeed,
                maxEthUsdOracleDelay: _params.maxEthUsdOracleDelay
            })
        )
        FraxUsdChainlinkOracleWithMaxDelay(
            FraxUsdChainlinkOracleWithMaxDelayParams({
                fraxUsdChainlinkFeedAddress: _params.fraxUsdChainlinkFeedAddress,
                fraxUsdMaximumOracleDelay: _params.fraxUsdMaximumOracleDelay
            })
        )
        Timelock2Step()
    {
        _setTimelock({ _newTimelock: _params.timelockAddress });
        _registerInterface({ interfaceId: type(IDualOracle).interfaceId });
        _registerInterface({ interfaceId: type(ITimelock2Step).interfaceId });
        _registerInterface({ interfaceId: type(IPriceSource).interfaceId });

        SFRXETH_ERC4626 = ISfrxEth(_params.sfrxEthErc4626Address);
    }

    // ====================================================================
    // Metadata
    // ====================================================================

    /// @notice The ```name``` function returns the name of the contract
    /// @return _name The name of the contract
    function name() external pure virtual returns (string memory _name) {
        _name = "v2 sfrxEth Dual Oracle In USD with Curve Pool (WETH) EMA and Uniswap v3 TWAP and Frax and ETH Chainlink";
    }

    /// @notice The ```version``` function returns the version of the contract
    /// @return _major The major version of the contract
    /// @return _minor The minor version of the contract
    /// @return _patch The patch version of the contract
    function version() external pure virtual returns (uint256 _major, uint256 _minor, uint256 _patch) {
        _major = 2;
        _minor = 0;
        _patch = 0;
    }

    // ====================================================================
    // Configuration Setters
    // ====================================================================

    /// @notice The ```setMinimumCurvePoolEma``` function sets the minimum price of frxEth in Ether units of the EMA
    /// @dev Must match precision of the EMA
    /// @param _minimumPrice The minimum price of frxEth in Ether units of the EMA
    function setMinimumCurvePoolEma(uint256 _minimumPrice) external override {
        _requireTimelock();
        _setMinimumCurvePoolEma({ _minimumPrice: _minimumPrice });
    }

    /// @notice The ```setMaximumCurvePoolEma``` function sets the maximum price of frxEth in Ether units of the EMA
    /// @dev Must match precision of the EMA
    /// @param _maximumPrice The maximum price of frxEth in Ether units of the EMA
    function setMaximumCurvePoolEma(uint256 _maximumPrice) external override {
        _requireTimelock();
        _setMaximumCurvePoolEma({ _maximumPrice: _maximumPrice });
    }

    /// @notice The ```setTwapDuration``` function sets the TWAP duration for the Uniswap V3 oracle
    /// @dev Must be called by the timelock
    /// @param _newTwapDuration The new TWAP duration
    function setTwapDuration(uint32 _newTwapDuration) external override {
        _requireTimelock();
        _setTwapDuration({ _newTwapDuration: _newTwapDuration });
    }

    /// @notice The ```setMaximumOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
    /// @dev Requires msg.sender to be the timelock address
    /// @param _newMaxOracleDelay The new max oracle delay
    function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external override {
        _requireTimelock();
        _setMaximumEthUsdOracleDelay({ _newMaxOracleDelay: _newMaxOracleDelay });
    }

    /// @notice The ```setMaximumFraxUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
    /// @dev Must be called by the timelock
    /// @param _newMaxOracleDelay The new max oracle delay
    function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external override {
        _requireTimelock();
        _setMaximumFraxUsdOracleDelay({ _newMaxOracleDelay: _newMaxOracleDelay });
    }

    // ====================================================================
    // Price Source Function
    // ====================================================================

    /// @notice The ```addRoundData``` adds new price data to a FraxOracle
    /// @dev This contract must be whitelisted on the receiver address
    /// @param _fraxOracle Address of a FraxOracle that has this contract set as its priceSource
    function addRoundData(IPriceSourceReceiver _fraxOracle) external {
        (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) = getPrices();
        // Authorization is handled on fraxOracle side
        _fraxOracle.addRoundData({
            isBadData: _isBadData,
            priceLow: uint104(_priceLow),
            priceHigh: uint104(_priceHigh),
            timestamp: uint40(block.timestamp)
        });
    }

    // ====================================================================
    // Price Functions
    // ====================================================================

    /// @notice The ```getWethPerFrxEthCurveEma``` function gets the EMA price of frxEth in weth units
    /// @dev normalized to match precision of oracle
    /// @return _wethPerFrxEth
    function getWethPerFrxEthCurveEma() public view returns (uint256 _wethPerFrxEth) {
        _wethPerFrxEth = _getCurvePoolToken1EmaPrice();

        // Note: ORACLE_PRECISION == CURVE_POOL_EMA_PRICE_ORACLE_PRECISION
        // _wethPerFrxEth = (ORACLE_PRECISION * _getCurvePoolToken1EmaPrice()) / CURVE_POOL_EMA_PRICE_ORACLE_PRECISION;
    }

    /// @notice The ```getUsdPerFraxChainlink``` function gets the Chainlink price of frax in usd units
    /// @dev normalized to match precision of oracle
    /// @return _isBadData Whether the Chainlink data is stale
    /// @return _usdPerFrax
    function getUsdPerFraxChainlink() public view returns (bool _isBadData, uint256 _usdPerFrax) {
        (bool _isBadDataChainlink, , uint256 _usdPerFraxRaw) = _getFraxUsdChainlinkPrice();

        // Set return values
        _isBadData = _isBadDataChainlink;
        _usdPerFrax = (ORACLE_PRECISION * _usdPerFraxRaw) / FRAX_USD_CHAINLINK_FEED_PRECISION;
    }

    /// @notice The ```getUsdPerEthChainlink``` function returns USD per ETH using the Chainlink oracle
    /// @return _isBadData If the Chainlink oracle is stale
    /// @return _usdPerEth The Eth Price is usd units
    function getUsdPerEthChainlink() public view returns (bool _isBadData, uint256 _usdPerEth) {
        (bool _isBadDataChainlink, , uint256 _usdPerEthChainlinkRaw) = _getEthUsdChainlinkPrice();

        // Set return values
        _isBadData = _isBadDataChainlink;
        _usdPerEth = (ORACLE_PRECISION * _usdPerEthChainlinkRaw) / ETH_USD_CHAINLINK_FEED_PRECISION;
    }

    /// @notice The ```getFraxPerFrxEthUniV3Twap``` function gets the TWAP price of frxEth in frax units
    /// @return _fraxPerFrxEthTwap The TWAP price of frxEth in frax units
    function getFraxPerFrxEthUniV3Twap() public view returns (uint256 _fraxPerFrxEthTwap) {
        _fraxPerFrxEthTwap = _getUniswapV3Twap();
    }

    /// @notice The ```getFrxEthPerSfrxEthErc4626Vault``` function gets the price of sfrxEth in frxEth units from the ERC4626 vault
    /// @return _frxEthPerSfrxEth The price of sfrxEth in frxEth units
    function getFrxEthPerSfrxEthErc4626Vault() public view returns (uint256 _frxEthPerSfrxEth) {
        _frxEthPerSfrxEth = SFRXETH_ERC4626.pricePerShare();
    }

    /// @notice The ```calculatePrices``` function calculates the normalized prices in a pure function
    /// @return _isBadData True if any of the oracles return stale data
    /// @return _priceLow The normalized low price
    /// @return _priceHigh The normalized high price
    function calculatePrices(
        uint256 _wethPerFrxEthCurveEma,
        uint256 _fraxPerFrxEthTwap,
        bool _isBadDataEthUsdChainlink,
        uint256 _usdPerEthChainlink,
        bool _isBadDataFraxUsdChainlink,
        uint256 _usdPerFraxChainlink,
        uint256 _frxEthPerSfrxEth
    ) public view virtual returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
        uint256 _frxEthPerUsdCurveChainlink = (ORACLE_PRECISION * ORACLE_PRECISION * ORACLE_PRECISION) /
            (_wethPerFrxEthCurveEma * _usdPerEthChainlink);

        uint256 _frxEthPerUsdTwapChainlink = (ORACLE_PRECISION * ORACLE_PRECISION * ORACLE_PRECISION) /
            (_fraxPerFrxEthTwap * _usdPerFraxChainlink);

        // NOTE: break out these steps to prevent potential overflow
        uint256 _sfrxEthPerUsdCurveChainlink = (ORACLE_PRECISION * _frxEthPerUsdCurveChainlink) / _frxEthPerSfrxEth;
        uint256 _sfrxEthPerUsdTwapChainlink = (ORACLE_PRECISION * _frxEthPerUsdTwapChainlink) / _frxEthPerSfrxEth;

        // Set return values
        _isBadData = _isBadDataEthUsdChainlink || _isBadDataFraxUsdChainlink;
        _priceLow = _sfrxEthPerUsdCurveChainlink < _sfrxEthPerUsdTwapChainlink
            ? _sfrxEthPerUsdCurveChainlink
            : _sfrxEthPerUsdTwapChainlink;
        _priceHigh = _sfrxEthPerUsdCurveChainlink > _sfrxEthPerUsdTwapChainlink
            ? _sfrxEthPerUsdCurveChainlink
            : _sfrxEthPerUsdTwapChainlink;
    }

    /// @notice The ```getPrices``` function is intended to return two prices from different oracles
    /// @notice Returns the number of wei of the quote token equivalent to 1e18 wei of base token
    /// @return _isBadData is true when data is stale or otherwise bad
    /// @return _priceLow is the lower of the two prices
    /// @return _priceHigh is the higher of the two prices
    function getPrices() public view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
        uint256 _wethPerFrxEthCurveEma = getWethPerFrxEthCurveEma();
        uint256 _fraxPerFrxEthTwap = getFraxPerFrxEthUniV3Twap();
        (bool _isBadDataEthUsdChainlink, uint256 _usdPerEthChainlink) = getUsdPerEthChainlink();
        (bool _isBadDataFraxUsdChainlink, uint256 _usdPerFraxChainlink) = getUsdPerFraxChainlink();
        uint256 _frxEthPerSfrxEth = getFrxEthPerSfrxEthErc4626Vault();

        (_isBadData, _priceLow, _priceHigh) = calculatePrices({
            _wethPerFrxEthCurveEma: _wethPerFrxEthCurveEma,
            _fraxPerFrxEthTwap: _fraxPerFrxEthTwap,
            _isBadDataEthUsdChainlink: _isBadDataEthUsdChainlink,
            _usdPerEthChainlink: _usdPerEthChainlink,
            _isBadDataFraxUsdChainlink: _isBadDataFraxUsdChainlink,
            _usdPerFraxChainlink: _usdPerFraxChainlink,
            _frxEthPerSfrxEth: _frxEthPerSfrxEth
        });
    }

    /// @notice The ```getPricesNormalized``` function returns the normalized prices in human readable form
    /// @dev decimals of underlying tokens match so we can just return _getPrices()
    /// @return _isBadDataNormal If the oracle is stale
    /// @return _priceLowNormal The normalized low price
    /// @return _priceHighNormal The normalized high price
    function getPricesNormalized()
        external
        view
        override
        returns (bool _isBadDataNormal, uint256 _priceLowNormal, uint256 _priceHighNormal)
    {
        // NOTE: because precision of both tokens is the same, we can just return the prices
        (_isBadDataNormal, _priceLowNormal, _priceHighNormal) = getPrices();
    }
}

File 2 of 23 : Timelock2Step.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ========================== Timelock2Step ===========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Primary Author
// Drake Evans: https://github.com/DrakeEvans

// Reviewers
// Dennis: https://github.com/denett

// ====================================================================

/// @title Timelock2Step
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @dev Inspired by the OpenZeppelin's Ownable2Step contract
/// @notice  An abstract contract which contains 2-step transfer and renounce logic for a timelock address
abstract contract Timelock2Step {
    /// @notice The pending timelock address
    address public pendingTimelockAddress;

    /// @notice The current timelock address
    address public timelockAddress;

    constructor() {
        timelockAddress = msg.sender;
    }

    /// @notice Emitted when timelock is transferred
    error OnlyTimelock();

    /// @notice Emitted when pending timelock is transferred
    error OnlyPendingTimelock();

    /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
    /// @param previousTimelock The address of the previous timelock
    /// @param newTimelock The address of the new timelock
    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);

    /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
    /// @param previousTimelock The address of the previous timelock
    /// @param newTimelock The address of the new timelock
    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);

    /// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address
    /// @return Whether or not msg.sender is current timelock address
    function _isSenderTimelock() internal view returns (bool) {
        return msg.sender == timelockAddress;
    }

    /// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address
    function _requireTimelock() internal view {
        if (msg.sender != timelockAddress) revert OnlyTimelock();
    }

    /// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address
    /// @return Whether or not msg.sender is pending timelock address
    function _isSenderPendingTimelock() internal view returns (bool) {
        return msg.sender == pendingTimelockAddress;
    }

    /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
    function _requirePendingTimelock() internal view {
        if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();
    }

    /// @notice The ```_transferTimelock``` function initiates the timelock transfer
    /// @dev This function is to be implemented by a public function
    /// @param _newTimelock The address of the nominated (pending) timelock
    function _transferTimelock(address _newTimelock) internal {
        pendingTimelockAddress = _newTimelock;
        emit TimelockTransferStarted(timelockAddress, _newTimelock);
    }

    /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
    /// @dev This function is to be implemented by a public function
    function _acceptTransferTimelock() internal {
        pendingTimelockAddress = address(0);
        _setTimelock(msg.sender);
    }

    /// @notice The ```_setTimelock``` function sets the timelock address
    /// @dev This function is to be implemented by a public function
    /// @param _newTimelock The address of the new timelock
    function _setTimelock(address _newTimelock) internal {
        emit TimelockTransferred(timelockAddress, _newTimelock);
        timelockAddress = _newTimelock;
    }

    /// @notice The ```transferTimelock``` function initiates the timelock transfer
    /// @dev Must be called by the current timelock
    /// @param _newTimelock The address of the nominated (pending) timelock
    function transferTimelock(address _newTimelock) external virtual {
        _requireTimelock();
        _transferTimelock(_newTimelock);
    }

    /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
    /// @dev Must be called by the pending timelock
    function acceptTransferTimelock() external virtual {
        _requirePendingTimelock();
        _acceptTransferTimelock();
    }

    /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
    /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
    function renounceTimelock() external virtual {
        _requireTimelock();
        _requirePendingTimelock();
        _transferTimelock(address(0));
        _setTimelock(address(0));
    }
}

File 3 of 23 : ITimelock2Step.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

interface ITimelock2Step {
    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);

    function acceptTransferTimelock() external;

    function pendingTimelockAddress() external view returns (address);

    function renounceTimelock() external;

    function timelockAddress() external view returns (address);

    function transferTimelock(address _newTimelock) external;
}

File 4 of 23 : DualOracleBase.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ========================== DualOracleBase ==========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Author
// Drake Evans: https://github.com/DrakeEvans

// ====================================================================

import "interfaces/IDualOracle.sol";

struct ConstructorParams {
    address baseToken0;
    uint8 baseToken0Decimals;
    address quoteToken0;
    uint8 quoteToken0Decimals;
    address baseToken1;
    uint8 baseToken1Decimals;
    address quoteToken1;
    uint8 quoteToken1Decimals;
}

/// @title DualOracleBase
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice  Base Contract for Frax Dual Oracles
abstract contract DualOracleBase is IDualOracle {
    /// @notice The precision of the oracle
    uint256 public constant ORACLE_PRECISION = 1e18;

    /// @notice The first quote token
    address public immutable QUOTE_TOKEN_0;

    /// @notice The first quote token decimals
    uint256 public immutable QUOTE_TOKEN_0_DECIMALS;

    /// @notice The second quote token
    address public immutable QUOTE_TOKEN_1;

    /// @notice The second quote token decimals
    uint256 public immutable QUOTE_TOKEN_1_DECIMALS;

    /// @notice The first base token
    address public immutable BASE_TOKEN_0;

    /// @notice The first base token decimals
    uint256 public immutable BASE_TOKEN_0_DECIMALS;

    /// @notice The second base token
    address public immutable BASE_TOKEN_1;

    /// @notice The second base token decimals
    uint256 public immutable BASE_TOKEN_1_DECIMALS;

    /// @notice The first normalization factor which accounts for different decimals across ERC20s
    /// @dev Normalization = quoteTokenDecimals - baseTokenDecimals
    int256 public immutable NORMALIZATION_0;

    /// @notice The second normalization factor which accounts for different decimals across ERC20s
    /// @dev Normalization = quoteTokenDecimals - baseTokenDecimals
    int256 public immutable NORMALIZATION_1;

    constructor(ConstructorParams memory _params) {
        QUOTE_TOKEN_0 = _params.quoteToken0;
        QUOTE_TOKEN_0_DECIMALS = _params.quoteToken0Decimals;
        QUOTE_TOKEN_1 = _params.quoteToken1;
        QUOTE_TOKEN_1_DECIMALS = _params.quoteToken1Decimals;
        BASE_TOKEN_0 = _params.baseToken0;
        BASE_TOKEN_0_DECIMALS = _params.baseToken0Decimals;
        BASE_TOKEN_1 = _params.baseToken1;
        BASE_TOKEN_1_DECIMALS = _params.baseToken1Decimals;
        NORMALIZATION_0 = int256(QUOTE_TOKEN_0_DECIMALS) - int256(BASE_TOKEN_0_DECIMALS);
        NORMALIZATION_1 = int256(QUOTE_TOKEN_1_DECIMALS) - int256(BASE_TOKEN_1_DECIMALS);
    }

    // ====================================================================
    // View Helpers
    // ====================================================================

    function decimals() external pure returns (uint8) {
        return 18;
    }
}

File 5 of 23 : CurvePoolEmaPriceOracleWithMinMax.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ================ CurvePoolEmaPriceOracleWithMinMax =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Author
// Drake Evans: https://github.com/DrakeEvans

// Reviewers
// Dennis: https://github.com/denett

// ====================================================================

import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { ICurvePoolEmaPriceOracleWithMinMax } from "interfaces/oracles/abstracts/ICurvePoolEmaPriceOracleWithMinMax.sol";
import { IEmaPriceOracleStableSwap } from "interfaces/IEmaPriceOracleStableSwap.sol";

struct ConstructorParams {
    address curvePoolEmaPriceOracleAddress;
    uint256 minimumCurvePoolEma;
    uint256 maximumCurvePoolEma;
}

/// @title CurvePoolEmaPriceOracleWithMinMax
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice  An oracle for getting EMA prices from Curve
abstract contract CurvePoolEmaPriceOracleWithMinMax is ERC165Storage, ICurvePoolEmaPriceOracleWithMinMax {
    /// @notice Curve pool, source of EMA
    address public immutable CURVE_POOL_EMA_PRICE_ORACLE;

    /// @notice Precision of Curve pool price_oracle()
    uint256 public constant CURVE_POOL_EMA_PRICE_ORACLE_PRECISION = 1e18;

    /// @notice Maximum price of token1 in token0 units of the EMA
    /// @dev Must match precision of EMA
    uint256 public minimumCurvePoolEma;

    /// @notice Maximum price of token1 in token0 units of the EMA
    /// @dev Must match precision of EMA
    uint256 public maximumCurvePoolEma;

    constructor(ConstructorParams memory _params) {
        _registerInterface({ interfaceId: type(ICurvePoolEmaPriceOracleWithMinMax).interfaceId });

        CURVE_POOL_EMA_PRICE_ORACLE = _params.curvePoolEmaPriceOracleAddress;
        minimumCurvePoolEma = _params.minimumCurvePoolEma;
        maximumCurvePoolEma = _params.maximumCurvePoolEma;
    }

    /// @notice The ```setMaximumCurvePoolEma``` function sets the maximum price of the EMA
    /// @dev Must match precision of the EMA
    /// @param _maximumPrice The maximum price of the EMA
    function _setMaximumCurvePoolEma(uint256 _maximumPrice) internal {
        emit SetMaximumCurvePoolEma({ oldMaximum: maximumCurvePoolEma, newMaximum: _maximumPrice });
        maximumCurvePoolEma = _maximumPrice;
    }

    function setMaximumCurvePoolEma(uint256 _maximumPrice) external virtual;

    /// @notice The ```setEmaMinimum``` function sets the minimum price of the EMA
    /// @dev Must match precision of the EMA
    /// @param _minimumPrice The minimum price of the EMA
    function _setMinimumCurvePoolEma(uint256 _minimumPrice) internal {
        emit SetMinimumCurvePoolEma({ oldMinimum: minimumCurvePoolEma, newMinimum: _minimumPrice });
        minimumCurvePoolEma = _minimumPrice;
    }

    function setMinimumCurvePoolEma(uint256 _minimumPrice) external virtual;

    function _getCurvePoolToken1EmaPrice() internal view returns (uint256 _token1Price) {
        uint256 _priceRaw = IEmaPriceOracleStableSwap(CURVE_POOL_EMA_PRICE_ORACLE).price_oracle();
        uint256 _price = _priceRaw > maximumCurvePoolEma ? maximumCurvePoolEma : _priceRaw;

        _token1Price = _price < minimumCurvePoolEma ? minimumCurvePoolEma : _price;
    }

    /// @notice The ```getCurvePoolToken1EmaPrice``` function gets the price of the second token in the Curve pool (token1)
    /// @dev Returned in units of the first token (token0)
    /// @return _emaPrice The price of the second token in the Curve pool
    function getCurvePoolToken1EmaPrice() external view returns (uint256 _emaPrice) {
        return _getCurvePoolToken1EmaPrice();
    }
}

File 6 of 23 : EthUsdChainlinkOracleWithMaxDelay.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ================ EthUsdChainlinkOracleWithMaxDelay =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Author
// Drake Evans: https://github.com/DrakeEvans

// Reviewers
// Dennis: https://github.com/denett

// ====================================================================

import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IEthUsdChainlinkOracleWithMaxDelay } from "interfaces/oracles/abstracts/IEthUsdChainlinkOracleWithMaxDelay.sol";

struct ConstructorParams {
    address ethUsdChainlinkFeedAddress;
    uint256 maxEthUsdOracleDelay;
}

/// @title EthUsdChainlinkOracleWithMaxDelay
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice  An abstract oracle for getting eth/usd prices from Chainlink
abstract contract EthUsdChainlinkOracleWithMaxDelay is ERC165Storage, IEthUsdChainlinkOracleWithMaxDelay {
    /// @notice Chainlink aggregator
    address public immutable ETH_USD_CHAINLINK_FEED_ADDRESS;

    /// @notice Decimals of ETH/USD chainlink feed
    uint8 public immutable ETH_USD_CHAINLINK_FEED_DECIMALS;

    /// @notice Precision of ETH/USD chainlink feed
    uint256 public immutable ETH_USD_CHAINLINK_FEED_PRECISION;

    /// @notice Maximum delay of Chainlink data, after which it is considered stale
    uint256 public maximumEthUsdOracleDelay;

    constructor(ConstructorParams memory _params) {
        _registerInterface({ interfaceId: type(IEthUsdChainlinkOracleWithMaxDelay).interfaceId });

        ETH_USD_CHAINLINK_FEED_ADDRESS = _params.ethUsdChainlinkFeedAddress;
        ETH_USD_CHAINLINK_FEED_DECIMALS = AggregatorV3Interface(ETH_USD_CHAINLINK_FEED_ADDRESS).decimals();
        ETH_USD_CHAINLINK_FEED_PRECISION = 10 ** uint256(ETH_USD_CHAINLINK_FEED_DECIMALS);
        maximumEthUsdOracleDelay = _params.maxEthUsdOracleDelay;
    }

    /// @notice The ```_setMaximumEthUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
    /// @param _newMaxOracleDelay The new max oracle delay
    function _setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) internal {
        emit SetMaximumEthUsdOracleDelay({
            oldMaxOracleDelay: maximumEthUsdOracleDelay,
            newMaxOracleDelay: _newMaxOracleDelay
        });
        maximumEthUsdOracleDelay = _newMaxOracleDelay;
    }

    function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external virtual;

    /// @notice The ```_getEthUsdChainlinkPrice``` function is called to get the eth/usd price from Chainlink
    /// @dev If data is stale or negative, set bad data to true and return
    /// @return _isBadData If the data is stale
    /// @return _updatedAt The timestamp of the last update
    /// @return _usdPerEth The eth/usd price
    function _getEthUsdChainlinkPrice()
        internal
        view
        returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth)
    {
        (, int256 _answer, , uint256 _ethUsdChainlinkUpdatedAt, ) = AggregatorV3Interface(
            ETH_USD_CHAINLINK_FEED_ADDRESS
        ).latestRoundData();

        // If data is stale or negative, set bad data to true and return
        _isBadData = _answer <= 0 || ((block.timestamp - _ethUsdChainlinkUpdatedAt) > maximumEthUsdOracleDelay);
        _updatedAt = _ethUsdChainlinkUpdatedAt;
        _usdPerEth = uint256(_answer);
    }

    /// @notice The ```getEthUsdChainlinkPrice``` function is called to get the eth/usd price from Chainlink
    /// @return _isBadData If the data is stale
    /// @return _updatedAt The timestamp of the last update
    /// @return _usdPerEth The eth/usd price
    function getEthUsdChainlinkPrice()
        external
        view
        virtual
        returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth)
    {
        (_isBadData, _updatedAt, _usdPerEth) = _getEthUsdChainlinkPrice();
    }
}

File 7 of 23 : FraxUsdChainlinkOracleWithMaxDelay.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ================ FraxUsdChainlinkOracleWithMaxDelay =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Author
// Drake Evans: https://github.com/DrakeEvans

// Reviewers
// Dennis: https://github.com/denett

// ====================================================================

import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IFraxUsdChainlinkOracleWithMaxDelay } from "interfaces/oracles/abstracts/IFraxUsdChainlinkOracleWithMaxDelay.sol";

struct ConstructorParams {
    address fraxUsdChainlinkFeedAddress;
    uint256 fraxUsdMaximumOracleDelay;
}

/// @title FraxUsdChainlinkOracleWithMaxDelay
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice  An abstract oracle for getting frax/usd prices from Chainlink
abstract contract FraxUsdChainlinkOracleWithMaxDelay is ERC165Storage, IFraxUsdChainlinkOracleWithMaxDelay {
    /// @notice Chainlink aggregator
    address public immutable FRAX_USD_CHAINLINK_FEED_ADDRESS;

    /// @notice Decimals of FRAX/USD chainlink feed
    uint8 public immutable FRAX_USD_CHAINLINK_FEED_DECIMALS;

    /// @notice Precision of FRAX/USD chainlink feed
    uint256 public immutable FRAX_USD_CHAINLINK_FEED_PRECISION;

    /// @notice Maximum delay of Chainlink data, after which it is considered stale
    uint256 public maximumFraxUsdOracleDelay;

    constructor(ConstructorParams memory _params) {
        _registerInterface({ interfaceId: type(IFraxUsdChainlinkOracleWithMaxDelay).interfaceId });

        FRAX_USD_CHAINLINK_FEED_ADDRESS = _params.fraxUsdChainlinkFeedAddress;
        FRAX_USD_CHAINLINK_FEED_DECIMALS = AggregatorV3Interface(FRAX_USD_CHAINLINK_FEED_ADDRESS).decimals();
        FRAX_USD_CHAINLINK_FEED_PRECISION = 10 ** uint256(FRAX_USD_CHAINLINK_FEED_DECIMALS);
        maximumFraxUsdOracleDelay = _params.fraxUsdMaximumOracleDelay;
    }

    /// @notice The ```_setMaximumFraxUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
    /// @param _newMaxOracleDelay The new max oracle delay
    function _setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) internal {
        emit SetMaximumFraxUsdOracleDelay({
            oldMaxOracleDelay: maximumFraxUsdOracleDelay,
            newMaxOracleDelay: _newMaxOracleDelay
        });
        maximumFraxUsdOracleDelay = _newMaxOracleDelay;
    }

    function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external virtual;

    /// @notice The ```_getFraxUsdChainlinkPrice``` function is called to get the frax/usd price from Chainlink
    /// @dev If data is stale or negative, set bad data to true and return
    /// @return _isBadData If the data is stale
    /// @return _updatedAt The timestamp of the last update
    /// @return _usdPerFrax The frax/usd price
    function _getFraxUsdChainlinkPrice()
        internal
        view
        returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax)
    {
        (, int256 _answer, , uint256 _fraxUsdChainlinkUpdatedAt, ) = AggregatorV3Interface(
            FRAX_USD_CHAINLINK_FEED_ADDRESS
        ).latestRoundData();

        // If data is stale or negative, set bad data to true and return
        _isBadData = _answer <= 0 || ((block.timestamp - _fraxUsdChainlinkUpdatedAt) > maximumFraxUsdOracleDelay);
        _updatedAt = _fraxUsdChainlinkUpdatedAt;
        _usdPerFrax = uint256(_answer);
    }

    /// @notice The ```getFraxUsdChainlinkPrice``` function is called to get the frax/usd price from Chainlink
    /// @return _isBadData If the data is stale
    /// @return _updatedAt The timestamp of the last update
    /// @return _usdPerFrax The frax/usd price
    function getFraxUsdChainlinkPrice()
        external
        view
        virtual
        returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax)
    {
        (_isBadData, _updatedAt, _usdPerFrax) = _getFraxUsdChainlinkPrice();
    }
}

File 8 of 23 : UniswapV3SingleTwapOracle.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ==================== UniswapV3SingleTwapOracle =====================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Author
// Drake Evans: https://github.com/DrakeEvans

// Reviewers
// Dennis: https://github.com/denett

// ====================================================================

import { IStaticOracle } from "@mean-finance/uniswap-v3-oracle/solidity/interfaces/IStaticOracle.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IUniswapV3SingleTwapOracle } from "interfaces/oracles/abstracts/IUniswapV3SingleTwapOracle.sol";

struct ConstructorParams {
    address uniswapV3PairAddress;
    uint32 twapDuration;
    address baseToken;
    address quoteToken;
}

/// @title UniswapV3SingleTwapOracle
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice  An oracle for UniV3 Twap prices
abstract contract UniswapV3SingleTwapOracle is ERC165Storage, IUniswapV3SingleTwapOracle {
    /// @notice address of the Uniswap V3 pair
    address public immutable UNI_V3_PAIR_ADDRESS;

    /// @notice The precision of the twap
    uint128 public constant TWAP_PRECISION = 1e18;

    /// @notice The base token of the twap
    address public immutable UNISWAP_V3_TWAP_BASE_TOKEN;

    /// @notice The quote token of the twap
    address public immutable UNISWAP_V3_TWAP_QUOTE_TOKEN;

    /// @notice The duration of the twap
    uint32 public twapDuration;

    constructor(ConstructorParams memory _params) {
        _registerInterface({ interfaceId: type(IUniswapV3SingleTwapOracle).interfaceId });

        UNI_V3_PAIR_ADDRESS = _params.uniswapV3PairAddress;
        twapDuration = _params.twapDuration;
        UNISWAP_V3_TWAP_BASE_TOKEN = _params.baseToken;
        UNISWAP_V3_TWAP_QUOTE_TOKEN = _params.quoteToken;
    }

    /// @notice The ```_setTwapDuration``` function sets duration of the twap
    /// @param _newTwapDuration The new twap duration
    function _setTwapDuration(uint32 _newTwapDuration) internal {
        emit SetTwapDuration({ oldTwapDuration: twapDuration, newTwapDuration: _newTwapDuration });
        twapDuration = _newTwapDuration;
    }

    function setTwapDuration(uint32 _newTwapDuration) external virtual;

    /// @notice The ```_getUniswapV3Twap``` function is called to get the twap
    /// @return _twap The twap price
    function _getUniswapV3Twap() internal view returns (uint256 _twap) {
        address[] memory _pools = new address[](1);
        _pools[0] = UNI_V3_PAIR_ADDRESS;

        _twap = IStaticOracle(0xB210CE856631EeEB767eFa666EC7C1C57738d438).quoteSpecificPoolsWithTimePeriod({
            baseAmount: TWAP_PRECISION,
            baseToken: UNISWAP_V3_TWAP_BASE_TOKEN,
            quoteToken: UNISWAP_V3_TWAP_QUOTE_TOKEN,
            pools: _pools,
            period: twapDuration
        });
    }

    /// @notice The ```getUniswapV3Twap``` function is called to get the twap
    /// @return _twap The twap price
    function getUniswapV3Twap() external view virtual returns (uint256 _twap) {
        _twap = _getUniswapV3Twap();
    }
}

File 9 of 23 : IDualOracle.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IDualOracle is IERC165 {
    function ORACLE_PRECISION() external view returns (uint256);

    function BASE_TOKEN_0() external view returns (address);

    function BASE_TOKEN_0_DECIMALS() external view returns (uint256);

    function BASE_TOKEN_1() external view returns (address);

    function BASE_TOKEN_1_DECIMALS() external view returns (uint256);

    function decimals() external view returns (uint8);

    function getPricesNormalized() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);

    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);

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

    function NORMALIZATION_0() external view returns (int256);

    function NORMALIZATION_1() external view returns (int256);

    function QUOTE_TOKEN_0() external view returns (address);

    function QUOTE_TOKEN_0_DECIMALS() external view returns (uint256);

    function QUOTE_TOKEN_1() external view returns (address);

    function QUOTE_TOKEN_1_DECIMALS() external view returns (uint256);
}

File 10 of 23 : IPriceSource.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

import { IPriceSourceReceiver } from "./IPriceSourceReceiver.sol";

interface IPriceSource {
    function addRoundData(IPriceSourceReceiver _fraxOracle) external;
}

File 11 of 23 : IPriceSourceReceiver.sol
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

interface IPriceSourceReceiver {
    function addRoundData(bool isBadData, uint104 priceLow, uint104 priceHigh, uint40 timestamp) external;

    function getPrices() external view returns (bool isBadData, uint256 priceLow, uint256 priceHigh);
}

File 12 of 23 : ISfrxEth.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;

// NOTE: This file generated from sfrxEth contract at https://etherscan.io/address/0xac3e018457b222d93114458476f3e3416abbe38f#code
interface ISfrxEth {
    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function allowance(address, address) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function asset() external view returns (address);

    function balanceOf(address) external view returns (uint256);

    function convertToAssets(uint256 shares) external view returns (uint256);

    function convertToShares(uint256 assets) external view returns (uint256);

    function decimals() external view returns (uint8);

    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    function depositWithSignature(
        uint256 assets,
        address receiver,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 shares);

    function lastRewardAmount() external view returns (uint192);

    function lastSync() external view returns (uint32);

    function maxDeposit(address) external view returns (uint256);

    function maxMint(address) external view returns (uint256);

    function maxRedeem(address owner) external view returns (uint256);

    function maxWithdraw(address owner) external view returns (uint256);

    function mint(uint256 shares, address receiver) external returns (uint256 assets);

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

    function nonces(address) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function previewDeposit(uint256 assets) external view returns (uint256);

    function previewMint(uint256 shares) external view returns (uint256);

    function previewRedeem(uint256 shares) external view returns (uint256);

    function previewWithdraw(uint256 assets) external view returns (uint256);

    function pricePerShare() external view returns (uint256);

    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);

    function rewardsCycleEnd() external view returns (uint32);

    function rewardsCycleLength() external view returns (uint32);

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

    function syncRewards() external;

    function totalAssets() external view returns (uint256);

    function totalSupply() external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
}

File 13 of 23 : ERC165Storage.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol)

pragma solidity ^0.8.0;

import "./ERC165.sol";

/**
 * @dev Storage based implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165Storage is ERC165 {
    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

File 14 of 23 : ICurvePoolEmaPriceOracleWithMinMax.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface ICurvePoolEmaPriceOracleWithMinMax is IERC165 {
    event SetMaximumCurvePoolEma(uint256 oldMaximum, uint256 newMaximum);
    event SetMinimumCurvePoolEma(uint256 oldMinimum, uint256 newMinimum);

    function CURVE_POOL_EMA_PRICE_ORACLE() external view returns (address);

    function CURVE_POOL_EMA_PRICE_ORACLE_PRECISION() external view returns (uint256);

    function getCurvePoolToken1EmaPrice() external view returns (uint256 _emaPrice);

    function maximumCurvePoolEma() external view returns (uint256);

    function minimumCurvePoolEma() external view returns (uint256);

    function setMaximumCurvePoolEma(uint256 _maximumPrice) external;

    function setMinimumCurvePoolEma(uint256 _minimumPrice) external;
}

File 15 of 23 : IEmaPriceOracleStableSwap.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;

interface IEmaPriceOracleStableSwap {
    function price_oracle() external view returns (uint256);
}

File 16 of 23 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^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 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 17 of 23 : IEthUsdChainlinkOracleWithMaxDelay.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IEthUsdChainlinkOracleWithMaxDelay is IERC165 {
    event SetMaximumEthUsdOracleDelay(uint256 oldMaxOracleDelay, uint256 newMaxOracleDelay);

    function ETH_USD_CHAINLINK_FEED_ADDRESS() external view returns (address);

    function ETH_USD_CHAINLINK_FEED_DECIMALS() external view returns (uint8);

    function ETH_USD_CHAINLINK_FEED_PRECISION() external view returns (uint256);

    function maximumEthUsdOracleDelay() external view returns (uint256);

    function getEthUsdChainlinkPrice() external view returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth);

    function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external;
}

File 18 of 23 : IFraxUsdChainlinkOracleWithMaxDelay.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IFraxUsdChainlinkOracleWithMaxDelay is IERC165 {
    event SetMaximumFraxUsdOracleDelay(uint256 oldMaxOracleDelay, uint256 newMaxOracleDelay);

    function FRAX_USD_CHAINLINK_FEED_ADDRESS() external view returns (address);

    function FRAX_USD_CHAINLINK_FEED_DECIMALS() external view returns (uint8);

    function FRAX_USD_CHAINLINK_FEED_PRECISION() external view returns (uint256);

    function maximumFraxUsdOracleDelay() external view returns (uint256);

    function getFraxUsdChainlinkPrice()
        external
        view
        returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax);

    function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external;
}

File 19 of 23 : IStaticOracle.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.7.6 <0.9.0;

import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol';

/// @title Uniswap V3 Static Oracle
/// @notice Oracle contract for calculating price quoting against Uniswap V3
interface IStaticOracle {
  /// @notice Returns the address of the Uniswap V3 factory
  /// @dev This value is assigned during deployment and cannot be changed
  /// @return The address of the Uniswap V3 factory
  function UNISWAP_V3_FACTORY() external view returns (IUniswapV3Factory);

  /// @notice Returns how many observations are needed per minute in Uniswap V3 oracles, on the deployed chain
  /// @dev This value is assigned during deployment and cannot be changed
  /// @return Number of observation that are needed per minute
  function CARDINALITY_PER_MINUTE() external view returns (uint8);

  /// @notice Returns all supported fee tiers
  /// @return The supported fee tiers
  function supportedFeeTiers() external view returns (uint24[] memory);

  /// @notice Returns whether a specific pair can be supported by the oracle
  /// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order
  /// @return Whether the given pair can be supported by the oracle
  function isPairSupported(address tokenA, address tokenB) external view returns (bool);

  /// @notice Returns all existing pools for the given pair
  /// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order
  /// @return All existing pools for the given pair
  function getAllPoolsForPair(address tokenA, address tokenB) external view returns (address[] memory);

  /// @notice Returns a quote, based on the given tokens and amount, by querying all of the pair's pools
  /// @dev If some pools are not configured correctly for the given period, then they will be ignored
  /// @dev Will revert if there are no pools available/configured for the pair and period combination
  /// @param baseAmount Amount of token to be converted
  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
  /// @param period Number of seconds from which to calculate the TWAP
  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
  /// @return queriedPools The pools that were queried to calculate the quote
  function quoteAllAvailablePoolsWithTimePeriod(
    uint128 baseAmount,
    address baseToken,
    address quoteToken,
    uint32 period
  ) external view returns (uint256 quoteAmount, address[] memory queriedPools);

  /// @notice Returns a quote, based on the given tokens and amount, by querying only the specified fee tiers
  /// @dev Will revert if the pair does not have a pool for one of the given fee tiers, or if one of the pools
  /// is not prepared/configured correctly for the given period
  /// @param baseAmount Amount of token to be converted
  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
  /// @param feeTiers The fee tiers to consider when calculating the quote
  /// @param period Number of seconds from which to calculate the TWAP
  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
  /// @return queriedPools The pools that were queried to calculate the quote
  function quoteSpecificFeeTiersWithTimePeriod(
    uint128 baseAmount,
    address baseToken,
    address quoteToken,
    uint24[] calldata feeTiers,
    uint32 period
  ) external view returns (uint256 quoteAmount, address[] memory queriedPools);

  /// @notice Returns a quote, based on the given tokens and amount, by querying only the specified pools
  /// @dev Will revert if one of the pools is not prepared/configured correctly for the given period
  /// @param baseAmount Amount of token to be converted
  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
  /// @param pools The pools to consider when calculating the quote
  /// @param period Number of seconds from which to calculate the TWAP
  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
  function quoteSpecificPoolsWithTimePeriod(
    uint128 baseAmount,
    address baseToken,
    address quoteToken,
    address[] calldata pools,
    uint32 period
  ) external view returns (uint256 quoteAmount);

  /// @notice Will initialize all existing pools for the given pair, so that they can be queried with the given period in the future
  /// @dev Will revert if there are no pools available for the pair and period combination
  /// @param tokenA One of the pair's tokens
  /// @param tokenB The other of the pair's tokens
  /// @param period The period that will be guaranteed when quoting
  /// @return preparedPools The pools that were prepared
  function prepareAllAvailablePoolsWithTimePeriod(
    address tokenA,
    address tokenB,
    uint32 period
  ) external returns (address[] memory preparedPools);

  /// @notice Will initialize the pair's pools with the specified fee tiers, so that they can be queried with the given period in the future
  /// @dev Will revert if the pair does not have a pool for a given fee tier
  /// @param tokenA One of the pair's tokens
  /// @param tokenB The other of the pair's tokens
  /// @param feeTiers The fee tiers to consider when searching for the pair's pools
  /// @param period The period that will be guaranteed when quoting
  /// @return preparedPools The pools that were prepared
  function prepareSpecificFeeTiersWithTimePeriod(
    address tokenA,
    address tokenB,
    uint24[] calldata feeTiers,
    uint32 period
  ) external returns (address[] memory preparedPools);

  /// @notice Will initialize all given pools, so that they can be queried with the given period in the future
  /// @param pools The pools to initialize
  /// @param period The period that will be guaranteed when quoting
  function prepareSpecificPoolsWithTimePeriod(address[] calldata pools, uint32 period) external;

  /// @notice Will increase observations for all existing pools for the given pair, so they start accruing information for twap calculations
  /// @dev Will revert if there are no pools available for the pair and period combination
  /// @param tokenA One of the pair's tokens
  /// @param tokenB The other of the pair's tokens
  /// @param cardinality The cardinality that will be guaranteed when quoting
  /// @return preparedPools The pools that were prepared
  function prepareAllAvailablePoolsWithCardinality(
    address tokenA,
    address tokenB,
    uint16 cardinality
  ) external returns (address[] memory preparedPools);

  /// @notice Will increase the pair's pools with the specified fee tiers observations, so they start accruing information for twap calculations
  /// @dev Will revert if the pair does not have a pool for a given fee tier
  /// @param tokenA One of the pair's tokens
  /// @param tokenB The other of the pair's tokens
  /// @param feeTiers The fee tiers to consider when searching for the pair's pools
  /// @param cardinality The cardinality that will be guaranteed when quoting
  /// @return preparedPools The pools that were prepared
  function prepareSpecificFeeTiersWithCardinality(
    address tokenA,
    address tokenB,
    uint24[] calldata feeTiers,
    uint16 cardinality
  ) external returns (address[] memory preparedPools);

  /// @notice Will increase all given pools observations, so they start accruing information for twap calculations
  /// @param pools The pools to initialize
  /// @param cardinality The cardinality that will be guaranteed when quoting
  function prepareSpecificPoolsWithCardinality(address[] calldata pools, uint16 cardinality) external;

  /// @notice Adds support for a new fee tier
  /// @dev Will revert if the given tier is invalid, or already supported
  /// @param feeTier The new fee tier to add
  function addNewFeeTier(uint24 feeTier) external;
}

File 20 of 23 : IUniswapV3SingleTwapOracle.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IUniswapV3SingleTwapOracle is IERC165 {
    event SetTwapDuration(uint256 oldTwapDuration, uint256 newTwapDuration);

    function TWAP_PRECISION() external view returns (uint128);

    function UNISWAP_V3_TWAP_BASE_TOKEN() external view returns (address);

    function UNISWAP_V3_TWAP_QUOTE_TOKEN() external view returns (address);

    function UNI_V3_PAIR_ADDRESS() external view returns (address);

    function getUniswapV3Twap() external view returns (uint256 _twap);

    function twapDuration() external view returns (uint32);

    function setTwapDuration(uint32 _newTwapDuration) external;
}

File 21 of 23 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 22 of 23 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 23 of 23 : IUniswapV3Factory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Uniswap V3 Factory
/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees
interface IUniswapV3Factory {
    /// @notice Emitted when the owner of the factory is changed
    /// @param oldOwner The owner before the owner was changed
    /// @param newOwner The owner after the owner was changed
    event OwnerChanged(address indexed oldOwner, address indexed newOwner);

    /// @notice Emitted when a pool is created
    /// @param token0 The first token of the pool by address sort order
    /// @param token1 The second token of the pool by address sort order
    /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
    /// @param tickSpacing The minimum number of ticks between initialized ticks
    /// @param pool The address of the created pool
    event PoolCreated(
        address indexed token0,
        address indexed token1,
        uint24 indexed fee,
        int24 tickSpacing,
        address pool
    );

    /// @notice Emitted when a new fee amount is enabled for pool creation via the factory
    /// @param fee The enabled fee, denominated in hundredths of a bip
    /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee
    event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);

    /// @notice Returns the current owner of the factory
    /// @dev Can be changed by the current owner via setOwner
    /// @return The address of the factory owner
    function owner() external view returns (address);

    /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled
    /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context
    /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee
    /// @return The tick spacing
    function feeAmountTickSpacing(uint24 fee) external view returns (int24);

    /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
    /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
    /// @param tokenA The contract address of either token0 or token1
    /// @param tokenB The contract address of the other token
    /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
    /// @return pool The pool address
    function getPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external view returns (address pool);

    /// @notice Creates a pool for the given two tokens and fee
    /// @param tokenA One of the two tokens in the desired pool
    /// @param tokenB The other of the two tokens in the desired pool
    /// @param fee The desired fee for the pool
    /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved
    /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments
    /// are invalid.
    /// @return pool The address of the newly created pool
    function createPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external returns (address pool);

    /// @notice Updates the owner of the factory
    /// @dev Must be called by the current owner
    /// @param _owner The new owner of the factory
    function setOwner(address _owner) external;

    /// @notice Enables a fee amount with the given tickSpacing
    /// @dev Fee amounts may never be removed once enabled
    /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)
    /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount
    function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
}

Settings
{
  "remappings": [
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "frax-std/=node_modules/frax-standard-solidity/src/",
    "script/=src/script/",
    "src/=src/",
    "test/=src/test/",
    "interfaces/=src/contracts/interfaces/",
    "arbitrum/=node_modules/@arbitrum/",
    "rlp/=node_modules/solidity-rlp/contracts/",
    "@arbitrum/=node_modules/@arbitrum/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@mean-finance/=node_modules/@mean-finance/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@rari-capital/=node_modules/@rari-capital/",
    "@uniswap/=node_modules/@uniswap/",
    "base64-sol/=node_modules/base64-sol/",
    "frax-standard-solidity/=node_modules/frax-standard-solidity/",
    "hardhat/=node_modules/hardhat/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "solidity-rlp/=node_modules/solidity-rlp/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 99999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"address","name":"baseToken0","type":"address"},{"internalType":"uint8","name":"baseToken0Decimals","type":"uint8"},{"internalType":"address","name":"quoteToken0","type":"address"},{"internalType":"uint8","name":"quoteToken0Decimals","type":"uint8"},{"internalType":"address","name":"baseToken1","type":"address"},{"internalType":"uint8","name":"baseToken1Decimals","type":"uint8"},{"internalType":"address","name":"quoteToken1","type":"address"},{"internalType":"uint8","name":"quoteToken1Decimals","type":"uint8"},{"internalType":"address","name":"frxEthErc20","type":"address"},{"internalType":"address","name":"fraxErc20","type":"address"},{"internalType":"address","name":"uniV3PairAddress","type":"address"},{"internalType":"uint32","name":"twapDuration","type":"uint32"},{"internalType":"address","name":"fraxUsdChainlinkFeedAddress","type":"address"},{"internalType":"uint256","name":"fraxUsdMaximumOracleDelay","type":"uint256"},{"internalType":"address","name":"ethUsdChainlinkFeed","type":"address"},{"internalType":"uint256","name":"maxEthUsdOracleDelay","type":"uint256"},{"internalType":"address","name":"curvePoolEmaPriceOracleAddress","type":"address"},{"internalType":"uint256","name":"minimumCurvePoolEma","type":"uint256"},{"internalType":"uint256","name":"maximumCurvePoolEma","type":"uint256"},{"internalType":"address","name":"timelockAddress","type":"address"},{"internalType":"address","name":"sfrxEthErc4626Address","type":"address"}],"internalType":"struct ConstructorParams","name":"_params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OnlyPendingTimelock","type":"error"},{"inputs":[],"name":"OnlyTimelock","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaximum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaximum","type":"uint256"}],"name":"SetMaximumCurvePoolEma","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxOracleDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxOracleDelay","type":"uint256"}],"name":"SetMaximumEthUsdOracleDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxOracleDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxOracleDelay","type":"uint256"}],"name":"SetMaximumFraxUsdOracleDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMinimum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinimum","type":"uint256"}],"name":"SetMinimumCurvePoolEma","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTwapDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTwapDuration","type":"uint256"}],"name":"SetTwapDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferred","type":"event"},{"inputs":[],"name":"BASE_TOKEN_0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKEN_0_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKEN_1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKEN_1_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE_POOL_EMA_PRICE_ORACLE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVE_POOL_EMA_PRICE_ORACLE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_USD_CHAINLINK_FEED_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_USD_CHAINLINK_FEED_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_USD_CHAINLINK_FEED_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAX_USD_CHAINLINK_FEED_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAX_USD_CHAINLINK_FEED_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAX_USD_CHAINLINK_FEED_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NORMALIZATION_0","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NORMALIZATION_1","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_TOKEN_0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_TOKEN_0_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_TOKEN_1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_TOKEN_1_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SFRXETH_ERC4626","outputs":[{"internalType":"contract ISfrxEth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TWAP_PRECISION","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_V3_TWAP_BASE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_V3_TWAP_QUOTE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNI_V3_PAIR_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPriceSourceReceiver","name":"_fraxOracle","type":"address"}],"name":"addRoundData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_wethPerFrxEthCurveEma","type":"uint256"},{"internalType":"uint256","name":"_fraxPerFrxEthTwap","type":"uint256"},{"internalType":"bool","name":"_isBadDataEthUsdChainlink","type":"bool"},{"internalType":"uint256","name":"_usdPerEthChainlink","type":"uint256"},{"internalType":"bool","name":"_isBadDataFraxUsdChainlink","type":"bool"},{"internalType":"uint256","name":"_usdPerFraxChainlink","type":"uint256"},{"internalType":"uint256","name":"_frxEthPerSfrxEth","type":"uint256"}],"name":"calculatePrices","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_priceLow","type":"uint256"},{"internalType":"uint256","name":"_priceHigh","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getCurvePoolToken1EmaPrice","outputs":[{"internalType":"uint256","name":"_emaPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEthUsdChainlinkPrice","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_updatedAt","type":"uint256"},{"internalType":"uint256","name":"_usdPerEth","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFraxPerFrxEthUniV3Twap","outputs":[{"internalType":"uint256","name":"_fraxPerFrxEthTwap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFraxUsdChainlinkPrice","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_updatedAt","type":"uint256"},{"internalType":"uint256","name":"_usdPerFrax","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFrxEthPerSfrxEthErc4626Vault","outputs":[{"internalType":"uint256","name":"_frxEthPerSfrxEth","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrices","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_priceLow","type":"uint256"},{"internalType":"uint256","name":"_priceHigh","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricesNormalized","outputs":[{"internalType":"bool","name":"_isBadDataNormal","type":"bool"},{"internalType":"uint256","name":"_priceLowNormal","type":"uint256"},{"internalType":"uint256","name":"_priceHighNormal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUniswapV3Twap","outputs":[{"internalType":"uint256","name":"_twap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsdPerEthChainlink","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_usdPerEth","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsdPerFraxChainlink","outputs":[{"internalType":"bool","name":"_isBadData","type":"bool"},{"internalType":"uint256","name":"_usdPerFrax","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWethPerFrxEthCurveEma","outputs":[{"internalType":"uint256","name":"_wethPerFrxEth","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumCurvePoolEma","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumEthUsdOracleDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumFraxUsdOracleDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumCurvePoolEma","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"pendingTimelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maximumPrice","type":"uint256"}],"name":"setMaximumCurvePoolEma","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxOracleDelay","type":"uint256"}],"name":"setMaximumEthUsdOracleDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxOracleDelay","type":"uint256"}],"name":"setMaximumFraxUsdOracleDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumPrice","type":"uint256"}],"name":"setMinimumCurvePoolEma","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_newTwapDuration","type":"uint32"}],"name":"setTwapDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"transferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"twapDuration","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"_major","type":"uint256"},{"internalType":"uint256","name":"_minor","type":"uint256"},{"internalType":"uint256","name":"_patch","type":"uint256"}],"stateMutability":"pure","type":"function"}]

61032060405234620007f7576102a0620029608038038091620000258261032062000894565b6103203912620007f7576040516102a081016001600160401b0381118282101762000862576040526200005a610320620008b8565b815262000069610340620008cd565b60208201526200007b610360620008b8565b60408201526200008d610380620008cd565b60608201526200009f6103a0620008b8565b6080820152620000b16103c0620008cd565b60a0820152620000c36103e0620008b8565b60c0820152620000d5610400620008cd565b60e0820152620000e7610420620008b8565b610100820152620000fa610440620008b8565b6101208201526200010d610460620008b8565b6101408201526104805163ffffffff81168103620007f757610160820152620001386104a0620008b8565b6101808201526104c0516101a0820152620001556104e0620008b8565b6101c08201819052610500516101e0830181905262000176610520620008b8565b61020084015261054051610220840152610560516102408401526200019d610580620008b8565b610260840152620001b06105a0620008b8565b61028084015260405191620001c58362000878565b6001600160a01b03908116835260208301919091526101808301516101a08401516040519392909116620001f98462000878565b83526020830152610140830151610160840151610100850151610120860151604051936001600160a01b03918216939282169263ffffffff169116608085016001600160401b038111868210176200086257604052845260208401526040830152606082015260018060a01b0361020085015116610220850151610240860151906040519283606081011060018060401b0360608601111762000862576060840160405283526020830152604082015260018060a01b038551169060ff6020870151169160018060a01b0360408801511660ff6060890151169060018060a01b0360808a01511660ff60a08b01511660018060a01b0360c08c0151169060ff60e08d01511692604051958661010081011060018060401b03610100890111176200086257604099620003b79861010089018c5288526020880152858a8801526060870152608086015260a085015260c084015260e083015260805260ff6060820151168060a05260018060a01b0360c08301511660c05260ff60e08301511660e05260018060a01b038251166101005260ff60a081602085015116938461012052600180831b03608082015116610140520151166101605262000901565b61018052620003cd60e051610160519062000901565b6101a0526379e7dc3b60e11b60009081526020818152838220805460ff19908116600190811790925584516001600160a01b039081166101c05285840151835594909501516002556303b9884f60e21b83527fa69d87a466dcd0c797af2c29fa5657e1e342f4d0a9c93701acba2ba88caada0e8054861682179055855184166101e052858201516003805463ffffffff191663ffffffff929092169190911790556040868101518516610200526060909601518416610220526351eb09cd60e01b9092527f94d1b103d9bc485f84a2b98a4f4895b331f634f4dab769eb4ae1e8cd38844c7f8054909416909117909255845116610240819052915163313ce56760e01b815291829060049082905afa908115620008055760009162000811575b506004926200050660ff836020946102605216620008dc565b61028052015182556323e2f2e160e11b600090815260209081527ff5b620afdafd0e663b0432a8b75b69296bf0eeaab4c8c12db6a065f1a15fa6d2805460ff1916600117905581516001600160a01b03166102a081905260405163313ce56760e01b815293849182905afa9182156200080557600092620007b4575b506200059860ff836020946102c05216620008dc565b6102e05201516005556007546102608201516001600160a01b0316906001600160a01b03199081169082337f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6600080a333161717600755600060208190527f83596b7a35d435ace5a1c05bce0730b03f9eef0f3a2652b4523c55a9006a3ca18054600160ff1991821681179092557ffcd29878e9d0256214b7c9524e4dd1bcc5e64dc8edf5ffacf4077022b791e886805482168317905563cb757b9760e01b9092527ff3497f619d33404604a9e6030d229698a133fc84763acf4228437c26277e6ee2805490921617905561028001516001600160a01b0316610300526040516120446200091c8239608051816105d2015260a051816104f9015260c05181610dc9015260e05181610cc3015261010051816114830152610120518161040e01526101405181611415015261016051816112550152610180518161088a01526101a0518161174f01526101c05181818161133d0152611bf001526101e0518181816110f90152611eb2015261020051818181610bf20152611f1c015261022051818181610b110152611f44015261024051818181610aa30152611de3015261026051816104670152610280518181816106e001526119fb01526102a051818181610b840152611d1101526102c051816111fc01526102e051818181610d1b0152611a490152610300518181816105650152611ab1015261204490f35b91506020823d602011620007fc575b81620007d26020938362000894565b81010312620007f7576200059860ff620007ee602094620008cd565b93505062000582565b600080fd5b3d9150620007c3565b6040513d6000823e3d90fd5b90506020813d60201162000859575b816200082f6020938362000894565b81010312620007f7576004926200050660ff6200084e602094620008cd565b9350505092620004ed565b3d915062000820565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b038211176200086257604052565b601f909101601f19168101906001600160401b038211908210176200086257604052565b51906001600160a01b0382168203620007f757565b519060ff82168203620007f757565b604d8111620008eb57600a0a90565b634e487b7160e01b600052601160045260246000fd5b81810392916000138015828513169184121617620008eb5756fe608060408181526004908136101561001657600080fd5b600091823560e01c93846232e91a1461171a5750836301ffc9a71461167257836306fdde03146114f9578363090f3f50146114a75783630b7f3ffe14610d3e578363116d79761461143957836320888004146113cb5783632570c27a1461136157836326939205146112f357836326d89545146112b1578363313ce5671461127857836337f85f66146112205783633b17136a146111c55783633be38cf9146111585783633cb6f5fa1461111d578363417d25a9146110af5783634501409514611001578363471d778914610fc75783634bc66f3214610f755783634d3375e8146109c25783634f8b4ae714610ea157836354fd4d5014610e5d57836356ee4c0814610ded57836359c909e114610d7f57836359f768b214610d435783636485712114610d3e5783636ff484721461028e578363726de1a514610ce6578363781097d014610c8e5783637c99a49914610c525783638c1e2f9214610b35578363952dca4814610c16578363993e3d5414610ba857836399a64f2814610b3a5783639c0d313f14610b35578363a2cc770314610ac7578363b374839b14610a59578363b93cd81614610a1e578363bd9a548b146109c2578363c433c80a1461091d578363c809d4ed146108ad578363c82f2b1214610855578363cb757b9714610703578363cca992fa146106ab578363cfae8d641461066a578363d7360946146105f657508263e0d2e78014610589578263e0fba44b1461051c578263e5a66dfa146104c5578263eb995c431461048b578263ebf43bca14610431578263f097486c146103da578263f6ccaad41461032d578263f97697ff146102ee578263fc28b1431461029357505063ff21f5711461028e57600080fd5b6117b8565b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e6906102cd6119d5565b9151901515815260208101919091529081906040820190565b0390f35b5080fd5b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209051670de0b6b3a76400008152f35b50346103d757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d75761036461187d565b7fffffffffffffffffffffffff00000000000000000000000000000000000000008060065416600655600754903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6600080a316331760075580f35b80fd5b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e6906102cd611a23565b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f1b427db70b2e813aae1e9f4dc54fcd2ae904b1350f60b84a7bab7d379aa2b02e903591610651611832565b6005548151908152836020820152a160055580f35b8280fd5b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906106a4611a6e565b9051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b90346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665781359173ffffffffffffffffffffffffffffffffffffffff8316809303610851578361078c610760611bad565b610768611e62565b610770611a23565b61077b9291926119d5565b939092610786611a6e565b95611b1f565b918691963b156108515783608492875198899586947f45d9f5820000000000000000000000000000000000000000000000000000000086521515898601526cffffffffffffffffffffffffff809216602486015216604484015264ffffffffff421660648401525af1801561084757610803578380f35b67ffffffffffffffff831161081b5750528180808380f35b8360416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b82513d86823e3d90fd5b8380fd5b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f2d76fda59e51b6069c5600ca7d7f2cb8449933f16ba284b7a22f410d487ac904903591610908611832565b6001548151908152836020820152a160015580f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066657359063ffffffff808316809303610851577fa5868b8f066a74ed982ad7843f1f76a16fc96b95c00596d6249b5fe5dee544137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000926109a8611832565b6003549281519084168152856020820152a1161760035580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00610760611bad565b92519115158252602082015260408101919091529081906060820190565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00611da0565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b6117f1565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906002549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906005549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b611772565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906001549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577fcfde23b8b5cb70458592a0920d25ba0c811d04a57f0737cc8a379cbbf0dbbbb4903591610e48611832565b6002548151908152836020820152a160025580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760609181519160028352816020840152820152f35b82346103d757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d757610ed8611832565b610ee061187d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600654166006556007548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a31660075580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209073ffffffffffffffffffffffffffffffffffffffff600754169051908152f35b3461066657827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665760209250549051908152f35b9050346102ea5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea573573ffffffffffffffffffffffffffffffffffffffff8082168092036106665761105a611832565b817fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655600754167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00611cce565b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f5215771cad7bc88de36c71ac95764acc6eb44eeca03f4b9f90eb8a8c1131e3aa8135926111b3611832565b82548151908152846020820152a15580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160128152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209063ffffffff600354169051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b91346103d75760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d7576044359081151582036103d7576084359081151582036103d7575092610a00916102e69460c4359260a43592606435916024359035611b1f565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b3461066657827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665781519060a082019082821067ffffffffffffffff83111761164657508252606781526020907f76322073667278457468204475616c204f7261636c6520496e20555344207769828201527f746820437572766520506f6f6c2028574554482920454d4120616e6420556e69838201527f73776170207633205457415020616e64204672617820616e642045544820436860608201527f61696e6c696e6b00000000000000000000000000000000000000000000000000608082015282519382859384528251928382860152825b84811061163057505050828201840152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168101030190f35b81810183015188820188015287955082016115f4565b8460416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665735907fffffffff000000000000000000000000000000000000000000000000000000008216809203610666576020927f01ffc9a7000000000000000000000000000000000000000000000000000000008314928315611705575b5050519015158152f35b81528084528190205460ff16915083806116fb565b8390346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020907f00000000000000000000000000000000000000000000000000000000000000008152f35b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b35760206117ab611bad565b604051908152f35b600080fd5b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b35760206117ab611e62565b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b3576020604051670de0b6b3a76400008152f35b73ffffffffffffffffffffffffffffffffffffffff60075416330361185357565b60046040517f1c0be90a000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff60065416330361189e57565b60046040517ff5c49e64000000000000000000000000000000000000000000000000000000008152fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761190957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8181029291811591840414171561194b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b801561199c57760a70c3c40a64e6c51999090b65f67d92400000000000000490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b811561199c570490565b6119dd611da0565b919291670de0b6b3a7640000808202925082040361194b57611a20907f0000000000000000000000000000000000000000000000000000000000000000906119cb565b90565b611a2b611cce565b919291670de0b6b3a7640000808202925082040361194b57611a20907f0000000000000000000000000000000000000000000000000000000000000000906119cb565b6040517f99530b0600000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611b1357600091611ae5575090565b906020823d8211611b0b575b81611afe602093836118c8565b810103126103d757505190565b3d9150611af1565b6040513d6000823e3d90fd5b94611b3d611b38611b389395611b439597999a98611938565b61197a565b93611938565b94670de0b6b3a764000091808302908382040361194b5781611b64916119cb565b958083029283040361194b57611b79916119cb565b928115611ba5575b509282811015611b9f57805b9280821115611b9a575090565b905090565b82611b8d565b905038611b81565b6040517f86fc88d300000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611b1357600091611c47575b506002549081811115611c4057505b6001549081811015611b9a575090565b9050611c30565b906020823d8211611c70575b81611c60602093836118c8565b810103126103d757505138611c21565b3d9150611c53565b519069ffffffffffffffffffff821682036117b357565b908160a09103126117b357611ca381611c78565b91602082015191604081015191611a20608060608401519301611c78565b9190820391821161194b57565b6040517ffeaf968c00000000000000000000000000000000000000000000000000000000815260a08160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa918215611b13576000918293611d69575b5060008213801590611d5557929190565b50611d608342611cc1565b60055410929190565b909250611d8d915060a03d8111611d99575b611d8581836118c8565b810190611c8f565b50925050909138611d44565b503d611d7b565b6040517ffeaf968c00000000000000000000000000000000000000000000000000000000815260a08160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa918215611b13576000918293611e3b575b5060008213801590611e2757929190565b50611e328342611cc1565b60045410929190565b909250611e56915060a03d8111611d9957611d8581836118c8565b50925050909138611e16565b6040516040810181811067ffffffffffffffff82111761190957604052600190818152602090818101908236833780511561200857829073ffffffffffffffffffffffffffffffffffffffff92837f000000000000000000000000000000000000000000000000000000000000000016815263ffffffff600354166040519687937f07f7ca9f00000000000000000000000000000000000000000000000000000000855260a4850190670de0b6b3a76400006004870152877f0000000000000000000000000000000000000000000000000000000000000000166024870152877f000000000000000000000000000000000000000000000000000000000000000016604487015260a060648701525180915260c4850193966000905b828210611fec5750505050829394506084830152038173b210ce856631eeeb767efa666ec7c1c57738d4385afa908115611b1357600091611fc0575b50905090565b82813d8311611fe5575b611fd481836118c8565b810103126103d75750518038611fba565b503d611fca565b8851811686529787019789978b97509095019490830190611f7e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c6343000813000a00000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000012000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000012000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f00000000000000000000000000000000000000000000000000000000000000120000000000000000000000005e8422345238f34275888049021821e8e08caa1f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f560000000000000000000000000000000000000000000000000000000000000384000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd0000000000000000000000000000000000000000000000000000000000000f3c0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b84190000000000000000000000000000000000000000000000000000000000000f3c0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc0000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000008412ebf45bac1b340bbe8f318b928c466c4e39ca000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f

Deployed Bytecode

0x608060408181526004908136101561001657600080fd5b600091823560e01c93846232e91a1461171a5750836301ffc9a71461167257836306fdde03146114f9578363090f3f50146114a75783630b7f3ffe14610d3e578363116d79761461143957836320888004146113cb5783632570c27a1461136157836326939205146112f357836326d89545146112b1578363313ce5671461127857836337f85f66146112205783633b17136a146111c55783633be38cf9146111585783633cb6f5fa1461111d578363417d25a9146110af5783634501409514611001578363471d778914610fc75783634bc66f3214610f755783634d3375e8146109c25783634f8b4ae714610ea157836354fd4d5014610e5d57836356ee4c0814610ded57836359c909e114610d7f57836359f768b214610d435783636485712114610d3e5783636ff484721461028e578363726de1a514610ce6578363781097d014610c8e5783637c99a49914610c525783638c1e2f9214610b35578363952dca4814610c16578363993e3d5414610ba857836399a64f2814610b3a5783639c0d313f14610b35578363a2cc770314610ac7578363b374839b14610a59578363b93cd81614610a1e578363bd9a548b146109c2578363c433c80a1461091d578363c809d4ed146108ad578363c82f2b1214610855578363cb757b9714610703578363cca992fa146106ab578363cfae8d641461066a578363d7360946146105f657508263e0d2e78014610589578263e0fba44b1461051c578263e5a66dfa146104c5578263eb995c431461048b578263ebf43bca14610431578263f097486c146103da578263f6ccaad41461032d578263f97697ff146102ee578263fc28b1431461029357505063ff21f5711461028e57600080fd5b6117b8565b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e6906102cd6119d5565b9151901515815260208101919091529081906040820190565b0390f35b5080fd5b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209051670de0b6b3a76400008152f35b50346103d757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d75761036461187d565b7fffffffffffffffffffffffff00000000000000000000000000000000000000008060065416600655600754903373ffffffffffffffffffffffffffffffffffffffff83167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6600080a316331760075580f35b80fd5b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000128152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160ff7f0000000000000000000000000000000000000000000000000000000000000008168152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e6906102cd611a23565b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000128152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f168152f35b346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f168152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f1b427db70b2e813aae1e9f4dc54fcd2ae904b1350f60b84a7bab7d379aa2b02e903591610651611832565b6005548151908152836020820152a160055580f35b8280fd5b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906106a4611a6e565b9051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f0000000000000000000000000000000000000000000000000000000005f5e1008152f35b90346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665781359173ffffffffffffffffffffffffffffffffffffffff8316809303610851578361078c610760611bad565b610768611e62565b610770611a23565b61077b9291926119d5565b939092610786611a6e565b95611b1f565b918691963b156108515783608492875198899586947f45d9f5820000000000000000000000000000000000000000000000000000000086521515898601526cffffffffffffffffffffffffff809216602486015216604484015264ffffffffff421660648401525af1801561084757610803578380f35b67ffffffffffffffff831161081b5750528180808380f35b8360416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b82513d86823e3d90fd5b8380fd5b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f2d76fda59e51b6069c5600ca7d7f2cb8449933f16ba284b7a22f410d487ac904903591610908611832565b6001548151908152836020820152a160015580f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261066657359063ffffffff808316809303610851577fa5868b8f066a74ed982ad7843f1f76a16fc96b95c00596d6249b5fe5dee544137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000926109a8611832565b6003549281519084168152856020820152a1161760035580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00610760611bad565b92519115158252602082015260408101919091529081906060820190565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00611da0565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e168152f35b6117f1565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005e8422345238f34275888049021821e8e08caa1f168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906002549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906005549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000128152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f0000000000000000000000000000000000000000000000000000000005f5e1008152f35b611772565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020906001549051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f168152f35b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577fcfde23b8b5cb70458592a0920d25ba0c811d04a57f0737cc8a379cbbf0dbbbb4903591610e48611832565b6002548151908152836020820152a160025580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760609181519160028352816020840152820152f35b82346103d757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d757610ed8611832565b610ee061187d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000080600654166006556007548273ffffffffffffffffffffffffffffffffffffffff821681817f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8280a37f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc68280a31660075580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209073ffffffffffffffffffffffffffffffffffffffff600754169051908152f35b3461066657827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665760209250549051908152f35b9050346102ea5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea573573ffffffffffffffffffffffffffffffffffffffff8082168092036106665761105a611832565b817fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655600754167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a8380a380f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f56168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576102e690610a00611cce565b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610666577f5215771cad7bc88de36c71ac95764acc6eb44eeca03f4b9f90eb8a8c1131e3aa8135926111b3611832565b82548151908152846020820152a15580f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160ff7f0000000000000000000000000000000000000000000000000000000000000008168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea57602090517f00000000000000000000000000000000000000000000000000000000000000128152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905160128152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209063ffffffff600354169051908152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc168152f35b91346103d75760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103d7576044359081151582036103d7576084359081151582036103d7575092610a00916102e69460c4359260a43592606435916024359035611b1f565b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000348168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000348168152f35b50346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea5760209073ffffffffffffffffffffffffffffffffffffffff600654169051908152f35b3461066657827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665781519060a082019082821067ffffffffffffffff83111761164657508252606781526020907f76322073667278457468204475616c204f7261636c6520496e20555344207769828201527f746820437572766520506f6f6c2028574554482920454d4120616e6420556e69838201527f73776170207633205457415020616e64204672617820616e642045544820436860608201527f61696e6c696e6b00000000000000000000000000000000000000000000000000608082015282519382859384528251928382860152825b84811061163057505050828201840152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168101030190f35b81810183015188820188015287955082016115f4565b8460416024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b346106665760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106665735907fffffffff000000000000000000000000000000000000000000000000000000008216809203610666576020927f01ffc9a7000000000000000000000000000000000000000000000000000000008314928315611705575b5050519015158152f35b81528084528190205460ff16915083806116fb565b8390346102ea57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102ea576020907f00000000000000000000000000000000000000000000000000000000000000008152f35b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b35760206117ab611bad565b604051908152f35b600080fd5b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b35760206117ab611e62565b346117b35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126117b3576020604051670de0b6b3a76400008152f35b73ffffffffffffffffffffffffffffffffffffffff60075416330361185357565b60046040517f1c0be90a000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff60065416330361189e57565b60046040517ff5c49e64000000000000000000000000000000000000000000000000000000008152fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761190957604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8181029291811591840414171561194b57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b801561199c57760a70c3c40a64e6c51999090b65f67d92400000000000000490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b811561199c570490565b6119dd611da0565b919291670de0b6b3a7640000808202925082040361194b57611a20907f0000000000000000000000000000000000000000000000000000000005f5e100906119cb565b90565b611a2b611cce565b919291670de0b6b3a7640000808202925082040361194b57611a20907f0000000000000000000000000000000000000000000000000000000005f5e100906119cb565b6040517f99530b0600000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f165afa908115611b1357600091611ae5575090565b906020823d8211611b0b575b81611afe602093836118c8565b810103126103d757505190565b3d9150611af1565b6040513d6000823e3d90fd5b94611b3d611b38611b389395611b439597999a98611938565b61197a565b93611938565b94670de0b6b3a764000091808302908382040361194b5781611b64916119cb565b958083029283040361194b57611b79916119cb565b928115611ba5575b509282811015611b9f57805b9280821115611b9a575090565b905090565b82611b8d565b905038611b81565b6040517f86fc88d300000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc165afa908115611b1357600091611c47575b506002549081811115611c4057505b6001549081811015611b9a575090565b9050611c30565b906020823d8211611c70575b81611c60602093836118c8565b810103126103d757505138611c21565b3d9150611c53565b519069ffffffffffffffffffff821682036117b357565b908160a09103126117b357611ca381611c78565b91602082015191604081015191611a20608060608401519301611c78565b9190820391821161194b57565b6040517ffeaf968c00000000000000000000000000000000000000000000000000000000815260a08160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419165afa918215611b13576000918293611d69575b5060008213801590611d5557929190565b50611d608342611cc1565b60055410929190565b909250611d8d915060a03d8111611d99575b611d8581836118c8565b810190611c8f565b50925050909138611d44565b503d611d7b565b6040517ffeaf968c00000000000000000000000000000000000000000000000000000000815260a08160048173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd165afa918215611b13576000918293611e3b575b5060008213801590611e2757929190565b50611e328342611cc1565b60045410929190565b909250611e56915060a03d8111611d9957611d8581836118c8565b50925050909138611e16565b6040516040810181811067ffffffffffffffff82111761190957604052600190818152602090818101908236833780511561200857829073ffffffffffffffffffffffffffffffffffffffff92837f00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f5616815263ffffffff600354166040519687937f07f7ca9f00000000000000000000000000000000000000000000000000000000855260a4850190670de0b6b3a76400006004870152877f0000000000000000000000005e8422345238f34275888049021821e8e08caa1f166024870152877f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e16604487015260a060648701525180915260c4850193966000905b828210611fec5750505050829394506084830152038173b210ce856631eeeb767efa666ec7c1c57738d4385afa908115611b1357600091611fc0575b50905090565b82813d8311611fe5575b611fd481836118c8565b810103126103d75750518038611fba565b503d611fca565b8851811686529787019789978b97509095019490830190611f7e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c6343000813000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000012000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000012000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f00000000000000000000000000000000000000000000000000000000000000120000000000000000000000005e8422345238f34275888049021821e8e08caa1f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f560000000000000000000000000000000000000000000000000000000000000384000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd0000000000000000000000000000000000000000000000000000000000000f3c0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b84190000000000000000000000000000000000000000000000000000000000000f3c0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc0000000000000000000000000000000000000000000000000c7d713b49da00000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000008412ebf45bac1b340bbe8f318b928c466c4e39ca000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f

-----Decoded View---------------
Arg [0] : _params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000348
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [2] : 000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000348
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [6] : 000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [8] : 0000000000000000000000005e8422345238f34275888049021821e8e08caa1f
Arg [9] : 000000000000000000000000853d955acef822db058eb8505911ed77f175b99e
Arg [10] : 00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f56
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000384
Arg [12] : 000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000f3c
Arg [14] : 0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000f3c
Arg [16] : 0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc
Arg [17] : 0000000000000000000000000000000000000000000000000c7d713b49da0000
Arg [18] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [19] : 0000000000000000000000008412ebf45bac1b340bbe8f318b928c466c4e39ca
Arg [20] : 000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f


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
Loading...
Loading
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.