Contract 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 3

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xfd431261f1e61b9c5fe863ab047dde24d0d8cd30379f223625baca2a4a996aa7_set Pending Anc...634233652023-02-22 11:49:39400 days 21 hrs agodForce Network: Deployer IN  0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH0.00003582 0.1
0xa0d6dc3f76c33a562be552990ca096c345b67c3e8d579aa782611af25f9a2fe1_set Poster634232982023-02-22 11:49:23400 days 21 hrs agodForce Network: Deployer IN  0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH0.00003412 0.1
0x5b295434163b87ef66b1aa0346ddc7a07c86cf007bc8f353d16f8e8a640c02e0Set Price48184672022-01-20 9:50:04798 days 23 hrs agodForce Network: Deployer IN  0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH0.001187768624 ETH1.169296084
0xdf57a990bc99929dc5afd16c5ede74fdc2e64979f92821b7cf53a914e2e28c57_set Asset Aggre...48184612022-01-20 9:50:04798 days 23 hrs agodForce Network: Deployer IN  0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH0.000974998831 ETH1.169296084
0x098dde4fcb95e027ce7968d3d4c647d895b6fbea57c406bb5429736eea66b074_set Aggregator ...48184562022-01-20 9:49:42798 days 23 hrs agodForce Network: Deployer IN  0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH0.000921883556 ETH1.169296084
0x987a70103c6faff4223ba749040cdfc82f104d9de2cc851a1ed81f2759f6a65f0x6080604048184052022-01-20 9:45:01798 days 23 hrs agodForce Network: Deployer IN  Contract Creation0 ETH0.10202068463 ETH1.169296084
[ Download CSV Export 
Latest 24 internal transactions
Parent Txn Hash Block From To Value
0x670850a0c97376f0908a7f7def10f16f1d7649a37b887b7e5059149bb961e62e634490582023-02-22 13:36:27400 days 19 hrs ago 0x1e96e916a64199069ccea2e6cf4d63d30a61b93d 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0xa91728702e6f0c0f24d0792e707eb0bcf70c8b502aec32a8046974b013ba6276190045132022-07-31 5:20:17607 days 3 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x3a5985f97222f7ab85c1a7e01563896e5c5c617c0 ETH
0xa91728702e6f0c0f24d0792e707eb0bcf70c8b502aec32a8046974b013ba6276190045132022-07-31 5:20:17607 days 3 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x40be37096ce3b8a2e9ec002468ab91071501c4990 ETH
0xa91728702e6f0c0f24d0792e707eb0bcf70c8b502aec32a8046974b013ba6276190045132022-07-31 5:20:17607 days 3 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0x677854b1065137994ad98bdd00d7ebfbfc697739a95662186b5726353c28e4bc51266982022-01-27 12:08:55791 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x7d25d250fbd63b0dac4a38c661075930c9a87aea0 ETH
0x677854b1065137994ad98bdd00d7ebfbfc697739a95662186b5726353c28e4bc51266982022-01-27 12:08:55791 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x3a5985f97222f7ab85c1a7e01563896e5c5c617c0 ETH
0x677854b1065137994ad98bdd00d7ebfbfc697739a95662186b5726353c28e4bc51266982022-01-27 12:08:55791 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x40be37096ce3b8a2e9ec002468ab91071501c4990 ETH
0x677854b1065137994ad98bdd00d7ebfbfc697739a95662186b5726353c28e4bc51266982022-01-27 12:08:55791 days 21 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0x677854b1065137994ad98bdd00d7ebfbfc697739a95662186b5726353c28e4bc51266982022-01-27 12:08:55791 days 21 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0xc21abc1d1b3cf56817d9696ab9fca46d1d5fde6a006e43451f68a88f8474398848208462022-01-20 12:03:02798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x7d25d250fbd63b0dac4a38c661075930c9a87aea0 ETH
0xc21abc1d1b3cf56817d9696ab9fca46d1d5fde6a006e43451f68a88f8474398848208462022-01-20 12:03:02798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x3a5985f97222f7ab85c1a7e01563896e5c5c617c0 ETH
0xc21abc1d1b3cf56817d9696ab9fca46d1d5fde6a006e43451f68a88f8474398848208462022-01-20 12:03:02798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x40be37096ce3b8a2e9ec002468ab91071501c4990 ETH
0xc21abc1d1b3cf56817d9696ab9fca46d1d5fde6a006e43451f68a88f8474398848208462022-01-20 12:03:02798 days 21 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0x8384923b8511e77dced45f44e6e9ba88545c07e7fd22c4851bc5276436b3fa6e48208132022-01-20 12:01:23798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x7d25d250fbd63b0dac4a38c661075930c9a87aea0 ETH
0x8384923b8511e77dced45f44e6e9ba88545c07e7fd22c4851bc5276436b3fa6e48208132022-01-20 12:01:23798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x3a5985f97222f7ab85c1a7e01563896e5c5c617c0 ETH
0x8384923b8511e77dced45f44e6e9ba88545c07e7fd22c4851bc5276436b3fa6e48208132022-01-20 12:01:23798 days 21 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x40be37096ce3b8a2e9ec002468ab91071501c4990 ETH
0x8384923b8511e77dced45f44e6e9ba88545c07e7fd22c4851bc5276436b3fa6e48208132022-01-20 12:01:23798 days 21 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0x8384923b8511e77dced45f44e6e9ba88545c07e7fd22c4851bc5276436b3fa6e48208132022-01-20 12:01:23798 days 21 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0xb916882a7f0667b08ee3b5436024d123d818c8d2a20e3c2509dc285f96f1955848184822022-01-20 9:51:17798 days 23 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x7d25d250fbd63b0dac4a38c661075930c9a87aea0 ETH
0xb916882a7f0667b08ee3b5436024d123d818c8d2a20e3c2509dc285f96f1955848184822022-01-20 9:51:17798 days 23 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x3a5985f97222f7ab85c1a7e01563896e5c5c617c0 ETH
0xb916882a7f0667b08ee3b5436024d123d818c8d2a20e3c2509dc285f96f1955848184822022-01-20 9:51:17798 days 23 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x40be37096ce3b8a2e9ec002468ab91071501c4990 ETH
0xb916882a7f0667b08ee3b5436024d123d818c8d2a20e3c2509dc285f96f1955848184822022-01-20 9:51:17798 days 23 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0xe2fcf5f501bf757213d7ed83ac789e8b8fc7b3b9dc7f9f560491e3690ac635f548184802022-01-20 9:50:48798 days 23 hrs ago 0xa300a84d8970718dac32f54f61bd568142d8bcf4 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c350 ETH
0xdf57a990bc99929dc5afd16c5ede74fdc2e64979f92821b7cf53a914e2e28c5748184612022-01-20 9:50:04798 days 23 hrs ago 0x5f7ca155cd53f552e60f8d1b088d6e4ca5885c35 0x1ee116b869ecc7cd13c629a8a2ae39fa361265cf0 ETH
[ Download CSV Export 
Loading

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

Contract Name:
PriceOracleV2

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 1 : PriceOracleV2.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

contract ErrorReporter {
    /**
     * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
     * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
     */
    event Failure(uint256 error, uint256 info, uint256 detail);

    enum Error {
        NO_ERROR,
        OPAQUE_ERROR, // To be used when reporting errors from upgradeable contracts; the opaque code should be given as `detail` in the `Failure` event
        UNAUTHORIZED,
        INTEGER_OVERFLOW,
        INTEGER_UNDERFLOW,
        DIVISION_BY_ZERO,
        BAD_INPUT,
        TOKEN_INSUFFICIENT_ALLOWANCE,
        TOKEN_INSUFFICIENT_BALANCE,
        TOKEN_TRANSFER_FAILED,
        MARKET_NOT_SUPPORTED,
        SUPPLY_RATE_CALCULATION_FAILED,
        BORROW_RATE_CALCULATION_FAILED,
        TOKEN_INSUFFICIENT_CASH,
        TOKEN_TRANSFER_OUT_FAILED,
        INSUFFICIENT_LIQUIDITY,
        INSUFFICIENT_BALANCE,
        INVALID_COLLATERAL_RATIO,
        MISSING_ASSET_PRICE,
        EQUITY_INSUFFICIENT_BALANCE,
        INVALID_CLOSE_AMOUNT_REQUESTED,
        ASSET_NOT_PRICED,
        INVALID_LIQUIDATION_DISCOUNT,
        INVALID_COMBINED_RISK_PARAMETERS
    }

    /**
     * Note: FailureInfo (but not Error) is kept in alphabetical order
     *       This is because FailureInfo grows significantly faster, and
     *       the order of Error has some meaning, while the order of FailureInfo
     *       is entirely arbitrary.
     */
    enum FailureInfo {
        BORROW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED,
        BORROW_ACCOUNT_SHORTFALL_PRESENT,
        BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        BORROW_AMOUNT_LIQUIDITY_SHORTFALL,
        BORROW_AMOUNT_VALUE_CALCULATION_FAILED,
        BORROW_MARKET_NOT_SUPPORTED,
        BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED,
        BORROW_NEW_BORROW_RATE_CALCULATION_FAILED,
        BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
        BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
        BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED,
        BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED,
        BORROW_ORIGINATION_FEE_CALCULATION_FAILED,
        BORROW_TRANSFER_OUT_FAILED,
        EQUITY_WITHDRAWAL_AMOUNT_VALIDATION,
        EQUITY_WITHDRAWAL_CALCULATE_EQUITY,
        EQUITY_WITHDRAWAL_MODEL_OWNER_CHECK,
        EQUITY_WITHDRAWAL_TRANSFER_OUT_FAILED,
        LIQUIDATE_ACCUMULATED_BORROW_BALANCE_CALCULATION_FAILED,
        LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET,
        LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET,
        LIQUIDATE_AMOUNT_SEIZE_CALCULATION_FAILED,
        LIQUIDATE_BORROW_DENOMINATED_COLLATERAL_CALCULATION_FAILED,
        LIQUIDATE_CLOSE_AMOUNT_TOO_HIGH,
        LIQUIDATE_DISCOUNTED_REPAY_TO_EVEN_AMOUNT_CALCULATION_FAILED,
        LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET,
        LIQUIDATE_NEW_BORROW_RATE_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET,
        LIQUIDATE_NEW_SUPPLY_RATE_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_TOTAL_BORROW_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_TOTAL_CASH_CALCULATION_FAILED_BORROWED_ASSET,
        LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET,
        LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET,
        LIQUIDATE_TRANSFER_IN_FAILED,
        LIQUIDATE_TRANSFER_IN_NOT_POSSIBLE,
        REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED,
        REPAY_BORROW_NEW_BORROW_RATE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
        REPAY_BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED,
        REPAY_BORROW_TRANSFER_IN_FAILED,
        REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
        SET_ADMIN_OWNER_CHECK,
        SET_ASSET_PRICE_CHECK_ORACLE,
        SET_MARKET_INTEREST_RATE_MODEL_OWNER_CHECK,
        SET_ORACLE_OWNER_CHECK,
        SET_ORIGINATION_FEE_OWNER_CHECK,
        SET_RISK_PARAMETERS_OWNER_CHECK,
        SET_RISK_PARAMETERS_VALIDATION,
        SUPPLY_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        SUPPLY_MARKET_NOT_SUPPORTED,
        SUPPLY_NEW_BORROW_INDEX_CALCULATION_FAILED,
        SUPPLY_NEW_BORROW_RATE_CALCULATION_FAILED,
        SUPPLY_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
        SUPPLY_NEW_SUPPLY_RATE_CALCULATION_FAILED,
        SUPPLY_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        SUPPLY_NEW_TOTAL_CASH_CALCULATION_FAILED,
        SUPPLY_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        SUPPLY_TRANSFER_IN_FAILED,
        SUPPLY_TRANSFER_IN_NOT_POSSIBLE,
        SUPPORT_MARKET_OWNER_CHECK,
        SUPPORT_MARKET_PRICE_CHECK,
        SUSPEND_MARKET_OWNER_CHECK,
        WITHDRAW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED,
        WITHDRAW_ACCOUNT_SHORTFALL_PRESENT,
        WITHDRAW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        WITHDRAW_AMOUNT_LIQUIDITY_SHORTFALL,
        WITHDRAW_AMOUNT_VALUE_CALCULATION_FAILED,
        WITHDRAW_CAPACITY_CALCULATION_FAILED,
        WITHDRAW_NEW_BORROW_INDEX_CALCULATION_FAILED,
        WITHDRAW_NEW_BORROW_RATE_CALCULATION_FAILED,
        WITHDRAW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
        WITHDRAW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
        WITHDRAW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        WITHDRAW_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        WITHDRAW_TRANSFER_OUT_FAILED,
        WITHDRAW_TRANSFER_OUT_NOT_POSSIBLE
    }

    /**
     * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
     */
    function fail(Error err, FailureInfo info) internal returns (uint256) {
        emit Failure(uint256(err), uint256(info), 0);

        return uint256(err);
    }

    /**
     * @dev use this when reporting an opaque error from an upgradeable collaborator contract
     */
    function failOpaque(FailureInfo info, uint256 opaqueError)
        internal
        returns (uint256)
    {
        emit Failure(uint256(Error.OPAQUE_ERROR), uint256(info), opaqueError);

        return uint256(Error.OPAQUE_ERROR);
    }
}

contract CarefulMath is ErrorReporter {
    /**
     * @dev Multiplies two numbers, returns an error on overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (Error, uint256) {
        if (a == 0) {
            return (Error.NO_ERROR, 0);
        }

        uint256 c = a * b;

        if (c / a != b) {
            return (Error.INTEGER_OVERFLOW, 0);
        } else {
            return (Error.NO_ERROR, c);
        }
    }

    /**
     * @dev Integer division of two numbers, truncating the quotient.
     */
    function div(uint256 a, uint256 b) internal pure returns (Error, uint256) {
        if (b == 0) {
            return (Error.DIVISION_BY_ZERO, 0);
        }

        return (Error.NO_ERROR, a / b);
    }

    /**
     * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (Error, uint256) {
        if (b <= a) {
            return (Error.NO_ERROR, a - b);
        } else {
            return (Error.INTEGER_UNDERFLOW, 0);
        }
    }

    /**
     * @dev Adds two numbers, returns an error on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (Error, uint256) {
        uint256 c = a + b;

        if (c >= a) {
            return (Error.NO_ERROR, c);
        } else {
            return (Error.INTEGER_OVERFLOW, 0);
        }
    }

    /**
     * @dev add a and b and then subtract c
     */
    function addThenSub(
        uint256 a,
        uint256 b,
        uint256 c
    ) internal pure returns (Error, uint256) {
        (Error err0, uint256 sum) = add(a, b);

        if (err0 != Error.NO_ERROR) {
            return (err0, 0);
        }

        return sub(sum, c);
    }

    /**
     * @dev Add two numbers together, overflow will lead to revert.
     */
    function srcAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }

    /**
     * @dev Integer subtraction of two numbers, overflow will lead to revert.
     */
    function srcSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x, "ds-math-sub-underflow");
    }

    /**
     * @dev Multiplies two numbers, overflow will lead to revert.
     */
    function srcMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    /**
     * @dev Integer division of two numbers, truncating the quotient.
     */
    function srcDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y > 0, "ds-math-div-overflow");
        z = x / y;
    }

    /**
     * @dev x to the power of y power(base, exponent)
     */
    function pow(uint256 base, uint256 exponent) internal pure returns (uint256) {
        if (exponent == 0) {
            return 1;
        } else if (exponent == 1) {
            return base;
        } else if (base == 0 && exponent != 0) {
            return 0;
        } else {
            uint256 z = base;
            for (uint256 i = 1; i < exponent; i++) z = srcMul(z, base);
            return z;
        }
    }
}

contract Exponential is CarefulMath {
    // TODO: We may wish to put the result of 10**18 here instead of the expression.
    // Per https://solidity.readthedocs.io/en/latest/contracts.html#constant-state-variables
    // the optimizer MAY replace the expression 10**18 with its calculated value.
    uint256 constant expScale = 10**18;

    // See TODO on expScale
    uint256 constant halfExpScale = expScale / 2;

    struct Exp {
        uint256 mantissa;
    }

    uint256 constant mantissaOne = 10**18;
    uint256 constant mantissaOneTenth = 10**17;

    /**
     * @dev Creates an exponential from numerator and denominator values.
     *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
     *            or if `denom` is zero.
     */
    function getExp(uint256 num, uint256 denom)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error err0, uint256 scaledNumerator) = mul(num, expScale);
        if (err0 != Error.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        (Error err1, uint256 rational) = div(scaledNumerator, denom);
        if (err1 != Error.NO_ERROR) {
            return (err1, Exp({ mantissa: 0 }));
        }

        return (Error.NO_ERROR, Exp({ mantissa: rational }));
    }

    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error error, uint256 result) = add(a.mantissa, b.mantissa);

        return (error, Exp({ mantissa: result }));
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error error, uint256 result) = sub(a.mantissa, b.mantissa);

        return (error, Exp({ mantissa: result }));
    }

    /**
     * @dev Multiply an Exp by a scalar, returning a new Exp.
     */
    function mulScalar(Exp memory a, uint256 scalar)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error err0, uint256 scaledMantissa) = mul(a.mantissa, scalar);
        if (err0 != Error.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        return (Error.NO_ERROR, Exp({ mantissa: scaledMantissa }));
    }

    /**
     * @dev Divide an Exp by a scalar, returning a new Exp.
     */
    function divScalar(Exp memory a, uint256 scalar)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error err0, uint256 descaledMantissa) = div(a.mantissa, scalar);
        if (err0 != Error.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        return (Error.NO_ERROR, Exp({ mantissa: descaledMantissa }));
    }

    /**
     * @dev Divide a scalar by an Exp, returning a new Exp.
     */
    function divScalarByExp(uint256 scalar, Exp memory divisor)
        internal
        pure
        returns (Error, Exp memory)
    {
        /*
            We are doing this as:
            getExp(mul(expScale, scalar), divisor.mantissa)

            How it works:
            Exp = a / b;
            Scalar = s;
            `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
        (Error err0, uint256 numerator) = mul(expScale, scalar);
        if (err0 != Error.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }
        return getExp(numerator, divisor.mantissa);
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b)
        internal
        pure
        returns (Error, Exp memory)
    {
        (Error err0, uint256 doubleScaledProduct) = mul(a.mantissa, b.mantissa);
        if (err0 != Error.NO_ERROR) {
            return (err0, Exp({ mantissa: 0 }));
        }

        // We add half the scale before dividing so that we get rounding instead of truncation.
        //  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
        // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
        (Error err1, uint256 doubleScaledProductWithHalfScale) =
            add(halfExpScale, doubleScaledProduct);
        if (err1 != Error.NO_ERROR) {
            return (err1, Exp({ mantissa: 0 }));
        }

        (Error err2, uint256 product) =
            div(doubleScaledProductWithHalfScale, expScale);
        // The only error `div` can return is Error.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
        assert(err2 == Error.NO_ERROR);

        return (Error.NO_ERROR, Exp({ mantissa: product }));
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
     *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
     */
    function divExp(Exp memory a, Exp memory b)
        internal
        pure
        returns (Error, Exp memory)
    {
        return getExp(a.mantissa, b.mantissa);
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * (10**18)}) = 15
     */
    function truncate(Exp memory exp) internal pure returns (uint256) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / 10**18;
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right)
        internal
        pure
        returns (bool)
    {
        return left.mantissa < right.mantissa;
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right)
        internal
        pure
        returns (bool)
    {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if first Exp is greater than second Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right)
        internal
        pure
        returns (bool)
    {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) internal pure returns (bool) {
        return value.mantissa == 0;
    }
}

interface ExchangeRateModel {
    function scale() external view returns (uint256);

    function token() external view returns (address);

    function getExchangeRate() external view returns (uint256);

    function getMaxSwingRate(uint256 interval) external view returns (uint256);

    function getFixedInterestRate(uint256 interval)
        external
        view
        returns (uint256);

    function getFixedExchangeRate(uint256 interval)
        external
        view
        returns (uint256);
}

interface IERC20 {
    function decimals() external view returns (uint8);
}

interface IAggregator {

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

interface IAggregatorProxy {

    function getAggregatorData(address _asset, IAggregator _aggregator) external returns (uint256, uint8);
}

interface IStatusOracle {

    function getAssetPriceStatus(address _asset) external view returns (bool);
}

contract PriceOracleV2 is Exponential {
    // Flag for whether or not contract is paused.
    bool public paused;

    // Approximately 1 hour: 60 seconds/minute * 60 minutes/hour * 1 block/15 seconds.
    uint256 public constant numBlocksPerPeriod = 240;

    uint256 public constant maxSwingMantissa = (5 * 10**15); // 0.005

    uint256 public constant MINIMUM_SWING = 10**15;
    uint256 public constant MAXIMUM_SWING = 10**17;

    uint256 public constant SECONDS_PER_WEEK = 604800;

    /**
     * @dev An administrator who can set the pending anchor value for assets.
     *      Set in the constructor.
     */
    address public anchorAdmin;

    /**
     * @dev Pending anchor administrator for this contract.
     */
    address public pendingAnchorAdmin;

    /**
     * @dev Address of the price poster.
     *      Set in the constructor.
     */
    address public poster;

    /**
     * @dev The maximum allowed percentage difference between a new price and the anchor's price
     *      Set only in the constructor
     */
    Exp public maxSwing;

    /**
     * @dev The maximum allowed percentage difference for all assets between a new price and the anchor's price
     */
    mapping(address => Exp) public maxSwings;

    /**
     * @dev Mapping of asset addresses to exchange rate information.
     *      Dynamic changes in asset prices based on exchange rates.
     * map: assetAddress -> ExchangeRateInfo
     */
    struct ExchangeRateInfo {
        address exchangeRateModel; // Address of exchange rate model contract
        uint256 exchangeRate; // Exchange rate between token and wrapped token
        uint256 maxSwingRate; // Maximum changing ratio of the exchange rate
        uint256 maxSwingDuration; // Duration of maximum changing ratio of the exchange rate
    }
    mapping(address => ExchangeRateInfo) public exchangeRates;

    /**
     * @dev Mapping of asset addresses to asset addresses. Stable coin can share a price.
     *
     * map: assetAddress -> Reader
     */
    struct Reader {
        address asset; // Asset to read price
        int256 decimalsDifference; // Standard decimal is 18, so this is equal to the decimal of `asset` - 18.
    }
    mapping(address => Reader) public readers;

    /**
     * @dev Mapping of asset addresses and their corresponding price in terms of Eth-Wei
     *      which is simply equal to AssetWeiPrice * 10e18. For instance, if OMG token was
     *      worth 5x Eth then the price for OMG would be 5*10e18 or Exp({mantissa: 5000000000000000000}).
     * map: assetAddress -> Exp
     */
    mapping(address => Exp) public _assetPrices;

    /**
     * @dev Asset price aggregator proxy address.
     */
    IAggregatorProxy public aggregatorProxy;
    
    /**
     * @dev Mapping of asset addresses to aggregator.
     */
    mapping(address => address) public aggregator;

    /**
     * @dev Mapping of asset addresses to statusOracle.
     */
    mapping(address => IStatusOracle) public statusOracle;

    constructor(address _poster, uint256 _maxSwing) public {
        anchorAdmin = msg.sender;
        poster = _poster;
        _setMaxSwing(_maxSwing);
    }

    /**
     * @notice Do not pay into PriceOracle.
     */
    receive() external payable {
        revert();
    }

    enum OracleError { NO_ERROR, UNAUTHORIZED, FAILED_TO_SET_PRICE }

    enum OracleFailureInfo {
        ACCEPT_ANCHOR_ADMIN_PENDING_ANCHOR_ADMIN_CHECK,
        SET_PAUSED_OWNER_CHECK,
        SET_PENDING_ANCHOR_ADMIN_OWNER_CHECK,
        SET_PENDING_ANCHOR_PERMISSION_CHECK,
        SET_PRICE_CALCULATE_SWING,
        SET_PRICE_CAP_TO_MAX,
        SET_PRICE_MAX_SWING_CHECK,
        SET_PRICE_NO_ANCHOR_PRICE_OR_INITIAL_PRICE_ZERO,
        SET_PRICE_PERMISSION_CHECK,
        SET_PRICE_ZERO_PRICE,
        SET_PRICES_PARAM_VALIDATION,
        SET_PRICE_IS_READER_ASSET,
        ADMIN_CONFIG
    }

    /**
     * @dev `msgSender` is msg.sender; `error` corresponds to enum OracleError;
     *      `info` corresponds to enum OracleFailureInfo, and `detail` is an arbitrary
     *      contract-specific code that enables us to report opaque error codes from upgradeable contracts.
     */
    event OracleFailure(
        address msgSender,
        address asset,
        uint256 error,
        uint256 info,
        uint256 detail
    );

    /**
     * @dev Use this when reporting a known error from the price oracle or a non-upgradeable collaborator
     *      Using Oracle in name because we already inherit a `fail` function from ErrorReporter.sol
     *      via Exponential.sol
     */
    function failOracle(
        address _asset,
        OracleError _err,
        OracleFailureInfo _info
    ) internal returns (uint256) {
        emit OracleFailure(msg.sender, _asset, uint256(_err), uint256(_info), 0);

        return uint256(_err);
    }

    /**
     * @dev Use this to report an error when set asset price.
     *      Give the `error` corresponds to enum Error as `_details`.
     */
    function failOracleWithDetails(
        address _asset,
        OracleError _err,
        OracleFailureInfo _info,
        uint256 _details
    ) internal returns (uint256) {
        emit OracleFailure(
            msg.sender,
            _asset,
            uint256(_err),
            uint256(_info),
            _details
        );

        return uint256(_err);
    }

    struct Anchor {
        // Floor(block.number / numBlocksPerPeriod) + 1
        uint256 period;
        // Price in ETH, scaled by 10**18
        uint256 priceMantissa;
    }

    /**
     * @dev Anchors by asset.
     */
    mapping(address => Anchor) public anchors;

    /**
     * @dev Pending anchor prices by asset.
     */
    mapping(address => uint256) public pendingAnchors;

    /**
     * @dev Emitted when a pending anchor is set.
     * @param asset Asset for which to set a pending anchor.
     * @param oldScaledPrice If an unused pending anchor was present, its value; otherwise 0.
     * @param newScaledPrice The new scaled pending anchor price.
     */
    event NewPendingAnchor(
        address anchorAdmin,
        address asset,
        uint256 oldScaledPrice,
        uint256 newScaledPrice
    );

    /**
     * @notice Provides ability to override the anchor price for an asset.
     * @dev Admin function to set the anchor price for an asset.
     * @param _asset Asset for which to override the anchor price.
     * @param _newScaledPrice New anchor price.
     * @return uint 0=success, otherwise a failure (see enum OracleError for details).
     */
    function _setPendingAnchor(address _asset, uint256 _newScaledPrice)
        external
        returns (uint256)
    {
        // Check caller = anchorAdmin.
        // Note: Deliberately not allowing admin. They can just change anchorAdmin if desired.
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.SET_PENDING_ANCHOR_PERMISSION_CHECK
                );
        }

        uint256 _oldScaledPrice = pendingAnchors[_asset];
        pendingAnchors[_asset] = _newScaledPrice;

        emit NewPendingAnchor(
            msg.sender,
            _asset,
            _oldScaledPrice,
            _newScaledPrice
        );

        return uint256(OracleError.NO_ERROR);
    }

    /**
     * @dev Emitted for all exchangeRates changes.
     */
    event SetExchangeRate(
        address asset,
        address exchangeRateModel,
        uint256 exchangeRate,
        uint256 maxSwingRate,
        uint256 maxSwingDuration
    );
    event SetMaxSwingRate(
        address asset,
        uint256 oldMaxSwingRate,
        uint256 newMaxSwingRate,
        uint256 maxSwingDuration
    );

    /**
     * @dev Emitted for all readers changes.
     */
    event ReaderPosted(
        address asset,
        address oldReader,
        address newReader,
        int256 decimalsDifference
    );

    /**
     * @dev Emitted for max swing changes.
     */
    event SetMaxSwing(uint256 maxSwing);

    /**
     * @dev Emitted for asset max swing changes.
     */
    event SetMaxSwingForAsset(address asset, uint256 maxSwing);

    /**
     * @dev Emitted for aggregator proxy changes.
     */
    event SetAggregatorProxy(address oldAggregator, address newAggregator);

    /**
     * @dev Emitted for asset aggregator changes.
     */
    event SetAssetAggregator(address asset, address aggregator);

    /**
     * @dev Emitted for statusOracle changes.
     */
    event SetAssetStatusOracle(address asset, IStatusOracle statusOracle);

    /**
     * @dev Emitted for all price changes.
     */
    event PricePosted(
        address asset,
        uint256 previousPriceMantissa,
        uint256 requestedPriceMantissa,
        uint256 newPriceMantissa
    );

    /**
     * @dev Emitted if this contract successfully posts a capped-to-max price.
     */
    event CappedPricePosted(
        address asset,
        uint256 requestedPriceMantissa,
        uint256 anchorPriceMantissa,
        uint256 cappedPriceMantissa
    );

    /**
     * @dev Emitted when admin either pauses or resumes the contract; `newState` is the resulting state.
     */
    event SetPaused(bool newState);

    /**
     * @dev Emitted when `pendingAnchorAdmin` is changed.
     */
    event NewPendingAnchorAdmin(
        address oldPendingAnchorAdmin,
        address newPendingAnchorAdmin
    );

    /**
     * @dev Emitted when `pendingAnchorAdmin` is accepted, which means anchor admin is updated.
     */
    event NewAnchorAdmin(address oldAnchorAdmin, address newAnchorAdmin);

    /**
     * @dev Emitted when `poster` is changed.
     */
    event NewPoster(address oldPoster, address newPoster);

    /**
     * @notice Set `paused` to the specified state.
     * @dev Admin function to pause or resume the contract.
     * @param _requestedState Value to assign to `paused`.
     * @return uint 0=success, otherwise a failure.
     */
    function _setPaused(bool _requestedState) external returns (uint256) {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.SET_PAUSED_OWNER_CHECK
                );
        }

        paused = _requestedState;
        emit SetPaused(_requestedState);

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Begins to transfer the right of anchor admin.
     *         The `_newPendingAnchorAdmin` must call `_acceptAnchorAdmin` to finalize the transfer.
     * @dev Admin function to change the anchor admin.
     *      The `_newPendingAnchorAdmin` must call `_acceptAnchorAdmin` to finalize the transfer.
     * @param _newPendingAnchorAdmin New pending anchor admin.
     * @return uint 0=success, otherwise a failure.
     */
    function _setPendingAnchorAdmin(address _newPendingAnchorAdmin)
        external
        returns (uint256)
    {
        // Check caller = anchorAdmin.
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.SET_PENDING_ANCHOR_ADMIN_OWNER_CHECK
                );
        }

        // Save current value, if any, for inclusion in log.
        address _oldPendingAnchorAdmin = pendingAnchorAdmin;
        // Store pendingAdmin = newPendingAdmin.
        pendingAnchorAdmin = _newPendingAnchorAdmin;

        emit NewPendingAnchorAdmin(
            _oldPendingAnchorAdmin,
            _newPendingAnchorAdmin
        );

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Accepts transfer of anchor admin rights. `msg.sender` must be `pendingAnchorAdmin`.
     * @dev Admin function for pending anchor admin to accept role and update anchor admin`
     * @return uint 0=success, otherwise a failure`
     */
    function _acceptAnchorAdmin() external returns (uint256) {
        // Check caller = pendingAnchorAdmin.
        // `msg.sender` can't be zero.
        if (msg.sender != pendingAnchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo
                        .ACCEPT_ANCHOR_ADMIN_PENDING_ANCHOR_ADMIN_CHECK
                );
        }

        // Save current value for inclusion in log.
        address _oldAnchorAdmin = anchorAdmin;
        // Store admin = pendingAnchorAdmin.
        anchorAdmin = pendingAnchorAdmin;
        // Clear the pending value.
        pendingAnchorAdmin = address(0);

        emit NewAnchorAdmin(_oldAnchorAdmin, msg.sender);

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Set new poster.
     * @dev Admin function to change of poster.
     * @param _newPoster New poster.
     * @return uint 0=success, otherwise a failure.
     *
     * TODO: Should we add a second arg to verify, like a checksum of `newAnchorAdmin` address?
     */
    function _setPoster(address _newPoster) external returns (uint256) {
        assert(poster != _newPoster);
        // Check caller = anchorAdmin.
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        // Save current value, if any, for inclusion in log.
        address _oldPoster = poster;
        // Store poster = newPoster.
        poster = _newPoster;

        emit NewPoster(_oldPoster, _newPoster);

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Set new exchange rate model.
     * @dev Function to set exchangeRateModel for an asset.
     * @param _asset Asset to set the new `_exchangeRateModel`.
     * @param _exchangeRateModel New `_exchangeRateModel` cnotract address,
     *                          if the `_exchangeRateModel` is address(0), revert to cancle.
     * @param _maxSwingDuration A value greater than zero and less than the seconds of a week.
     * @return uint 0=success, otherwise a failure (see enum OracleError for details).
     */
    function setExchangeRate(
        address _asset,
        address _exchangeRateModel,
        uint256 _maxSwingDuration
    ) external returns (uint256) {
        // Check caller = anchorAdmin.
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        require(
            _exchangeRateModel != address(0),
            "setExchangeRate: exchangeRateModel cannot be a zero address."
        );
        require(
            _maxSwingDuration > 0 && _maxSwingDuration <= SECONDS_PER_WEEK,
            "setExchangeRate: maxSwingDuration cannot be zero, less than 604800 (seconds per week)."
        );

        uint256 _currentExchangeRate =
            ExchangeRateModel(_exchangeRateModel).getExchangeRate();
        require(
            _currentExchangeRate > 0,
            "setExchangeRate: currentExchangeRate not zero."
        );

        uint256 _maxSwingRate =
            ExchangeRateModel(_exchangeRateModel).getMaxSwingRate(
                _maxSwingDuration
            );
        require(
            _maxSwingRate > 0 &&
                _maxSwingRate <=
                ExchangeRateModel(_exchangeRateModel).getMaxSwingRate(
                    SECONDS_PER_WEEK
                ),
            "setExchangeRate: maxSwingRate cannot be zero, less than 604800 (seconds per week)."
        );

        exchangeRates[_asset].exchangeRateModel = _exchangeRateModel;
        exchangeRates[_asset].exchangeRate = _currentExchangeRate;
        exchangeRates[_asset].maxSwingRate = _maxSwingRate;
        exchangeRates[_asset].maxSwingDuration = _maxSwingDuration;

        emit SetExchangeRate(
            _asset,
            _exchangeRateModel,
            _currentExchangeRate,
            _maxSwingRate,
            _maxSwingDuration
        );
        return uint256(OracleError.NO_ERROR);
    }

    /**
     * @notice Set the asset’s `exchangeRateModel` to disabled.
     * @dev Admin function to disable of exchangeRateModel.
     * @param _asset Asset for which to disable the `exchangeRateModel`.
     * @return uint 0=success, otherwise a failure.
     */
    function _disableExchangeRate(address _asset)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin.
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        exchangeRates[_asset].exchangeRateModel = address(0);
        exchangeRates[_asset].exchangeRate = 0;
        exchangeRates[_asset].maxSwingRate = 0;
        exchangeRates[_asset].maxSwingDuration = 0;

        emit SetExchangeRate(
            _asset,
            address(0),
            0,
            0,
            0
        );
        return uint256(OracleError.NO_ERROR);
    }

    /**
     * @notice Set a new `maxSwingRate`.
     * @dev Function to set exchange rate `maxSwingRate` for an asset.
     * @param _asset Asset for which to set the exchange rate `maxSwingRate`.
     * @param _maxSwingDuration Interval time.
     * @return uint 0=success, otherwise a failure (see enum OracleError for details)
     */
    function setMaxSwingRate(address _asset, uint256 _maxSwingDuration)
        external
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        require(
            _maxSwingDuration > 0 && _maxSwingDuration <= SECONDS_PER_WEEK,
            "setMaxSwingRate: maxSwingDuration cannot be zero, less than 604800 (seconds per week)."
        );

        ExchangeRateModel _exchangeRateModel =
            ExchangeRateModel(exchangeRates[_asset].exchangeRateModel);
        uint256 _newMaxSwingRate =
            _exchangeRateModel.getMaxSwingRate(_maxSwingDuration);
        uint256 _oldMaxSwingRate = exchangeRates[_asset].maxSwingRate;
        require(
            _oldMaxSwingRate != _newMaxSwingRate,
            "setMaxSwingRate: the same max swing rate."
        );
        require(
            _newMaxSwingRate > 0 &&
                _newMaxSwingRate <=
                _exchangeRateModel.getMaxSwingRate(SECONDS_PER_WEEK),
            "setMaxSwingRate: maxSwingRate cannot be zero, less than 31536000 (seconds per week)."
        );

        exchangeRates[_asset].maxSwingRate = _newMaxSwingRate;
        exchangeRates[_asset].maxSwingDuration = _maxSwingDuration;

        emit SetMaxSwingRate(
            _asset,
            _oldMaxSwingRate,
            _newMaxSwingRate,
            _maxSwingDuration
        );
        return uint256(OracleError.NO_ERROR);
    }

    /**
     * @notice Entry point for updating prices.
     * @dev Set reader for an asset.
     * @param _asset Asset for which to set the reader.
     * @param _readAsset Reader address, if the reader is address(0), cancel the reader.
     * @return uint 0=success, otherwise a failure (see enum OracleError for details).
     */
    function setReaders(address _asset, address _readAsset)
        external
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        address _oldReadAsset = readers[_asset].asset;
        // require(_readAsset != _oldReadAsset, "setReaders: Old and new values cannot be the same.");
        require(
            _readAsset != _asset,
            "setReaders: asset and readAsset cannot be the same."
        );

        readers[_asset].asset = _readAsset;
        if (_readAsset == address(0)) readers[_asset].decimalsDifference = 0;
        else
            readers[_asset].decimalsDifference = int256(
                IERC20(_asset).decimals() - IERC20(_readAsset).decimals()
            );

        emit ReaderPosted(
            _asset,
            _oldReadAsset,
            _readAsset,
            readers[_asset].decimalsDifference
        );
        return uint256(OracleError.NO_ERROR);
    }

    /**
     * @notice Set `maxSwing` to the specified value.
     * @dev Admin function to change of max swing.
     * @param _maxSwing Value to assign to `maxSwing`.
     * @return uint 0=success, otherwise a failure.
     */
    function _setMaxSwing(uint256 _maxSwing) public returns (uint256) {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        uint256 _oldMaxSwing = maxSwing.mantissa;
        require(
            _maxSwing != _oldMaxSwing,
            "_setMaxSwing: Old and new values cannot be the same."
        );

        require(
            _maxSwing >= MINIMUM_SWING && _maxSwing <= MAXIMUM_SWING,
            "_setMaxSwing: 0.1% <= _maxSwing <= 10%."
        );
        maxSwing = Exp({ mantissa: _maxSwing });
        emit SetMaxSwing(_maxSwing);

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Set `maxSwing` for asset to the specified value.
     * @dev Admin function to change of max swing.
     * @param _asset Asset for which to set the `maxSwing`.
     * @param _maxSwing Value to assign to `maxSwing`.
     * @return uint 0=success, otherwise a failure.
     */
    function _setMaxSwingForAsset(address _asset, uint256 _maxSwing)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        uint256 _oldMaxSwing = maxSwings[_asset].mantissa;
        require(
            _maxSwing != _oldMaxSwing,
            "_setMaxSwingForAsset: Old and new values cannot be the same."
        );
        require(
            _maxSwing >= MINIMUM_SWING && _maxSwing <= MAXIMUM_SWING,
            "_setMaxSwingForAsset: 0.1% <= _maxSwing <= 10%."
        );
        maxSwings[_asset] = Exp({ mantissa: _maxSwing });
        emit SetMaxSwingForAsset(_asset, _maxSwing);

        return uint256(Error.NO_ERROR);
    }

    function _setMaxSwingForAssetBatch(
        address[] calldata _assets,
        uint256[] calldata _maxSwings
    ) external {
        require(
            _assets.length == _maxSwings.length,
            "_setMaxSwingForAssetBatch: assets & maxSwings must match the current length."
        );
        for (uint256 i = 0; i < _assets.length; i++)
            _setMaxSwingForAsset(_assets[i], _maxSwings[i]);
    }

    /**
     * @notice Set `aggregatorProxy` for asset to the specified address.
     * @dev Admin function to change of aggregatorProxy.
     * @param _aggregatorProxy Address to assign to `aggregatorProxy`.
     * @return uint 0=success, otherwise a failure.
     */
    function _setAggregatorProxy(IAggregatorProxy _aggregatorProxy)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        // require(
        //     _aggregatorProxy.decimals() > 0,
        //     "_setAggregatorProxy: This is not the aggregatorProxy contract!"
        // );

        IAggregatorProxy _oldAssetAggregator = aggregatorProxy;
        require(
            _aggregatorProxy != _oldAssetAggregator,
            "_setAggregatorProxy: Old and new address cannot be the same."
        );
        
        aggregatorProxy = IAggregatorProxy(_aggregatorProxy);
        emit SetAggregatorProxy(address(_oldAssetAggregator), address(_aggregatorProxy));

        return uint256(Error.NO_ERROR);
    }

    /**
     * @notice Set `aggregator` for asset to the specified address.
     * @dev Admin function to change of aggregator.
     * @param _asset Asset for which to set the `aggregator`.
     * @param _aggregator Address to assign to `aggregator`.
     * @return uint 0=success, otherwise a failure.
     */
    function _setAssetAggregator(address _asset, address _aggregator)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        require(
            IAggregator(_aggregator).version() >= 0,
            "_setAssetAggregator: This is not the aggregator contract!"
        );

        address _oldAssetAggregator = aggregator[_asset];
        require(
            _aggregator != _oldAssetAggregator,
            "_setAssetAggregator: Old and new address cannot be the same."
        );
        
        aggregator[_asset] = _aggregator;
        emit SetAssetAggregator(_asset, _aggregator);

        return uint256(Error.NO_ERROR);
    }

    function _setAssetAggregatorBatch(
        address[] calldata _assets,
        address[] calldata _aggregators
    ) external {
        require(
            _assets.length == _aggregators.length,
            "_setAssetAggregatorBatch: assets & aggregators must match the current length."
        );
        for (uint256 i = 0; i < _assets.length; i++)
            _setAssetAggregator(_assets[i], _aggregators[i]);
    }

    /**
     * @notice Set the asset’s `aggregator` to disabled.
     * @dev Admin function to disable of aggregator.
     * @param _asset Asset for which to disable the `aggregator`.
     * @return uint 0=success, otherwise a failure.
     */
    function _disableAssetAggregator(address _asset)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        require(
            _getReaderPrice(_asset) > 0,
            "_disableAssetAggregator: The price of local assets cannot be 0!"
        );
        
        delete aggregator[_asset];
        emit SetAssetAggregator(_asset, aggregator[_asset]);

        return uint256(Error.NO_ERROR);
    }

    function _disableAssetAggregatorBatch(address[] calldata _assets) external {
        for (uint256 i = 0; i < _assets.length; i++)
            _disableAssetAggregator(_assets[i]);
    }

    /**
     * @notice Set `statusOracle` for asset to the specified address.
     * @dev Admin function to change of statusOracle.
     * @param _asset Asset for which to set the `statusOracle`.
     * @param _statusOracle Address to assign to `statusOracle`.
     * @return uint 0=success, otherwise a failure.SetAssetStatusOracle
     */
    function _setAssetStatusOracle(address _asset, IStatusOracle _statusOracle)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }

        _statusOracle.getAssetPriceStatus(_asset);
        
        statusOracle[_asset] = _statusOracle;
        emit SetAssetStatusOracle(_asset, _statusOracle);

        return uint256(Error.NO_ERROR);
    }

    function _setAssetStatusOracleBatch(
        address[] calldata _assets,
        IStatusOracle[] calldata _statusOracles
    ) external {
        require(
            _assets.length == _statusOracles.length,
            "_setAssetStatusOracleBatch: assets & _statusOracles must match the current length."
        );
        for (uint256 i = 0; i < _assets.length; i++)
            _setAssetStatusOracle(_assets[i], _statusOracles[i]);
    }

    /**
     * @notice Set the `statusOracle` to disabled.
     * @dev Admin function to disable of statusOracle.
     * @return uint 0=success, otherwise a failure.
     */
    function _disableAssetStatusOracle(address _asset)
        public
        returns (uint256)
    {
        // Check caller = anchorAdmin
        if (msg.sender != anchorAdmin) {
            return
                failOracle(
                    address(0),
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.ADMIN_CONFIG
                );
        }
        statusOracle[_asset] = IStatusOracle(0);
        
        emit SetAssetStatusOracle(_asset, IStatusOracle(0));

        return uint256(Error.NO_ERROR);
    }

    function _disableAssetStatusOracleBatch(address[] calldata _assets) external {
        for (uint256 i = 0; i < _assets.length; i++)
            _disableAssetStatusOracle(_assets[i]);
    }

    /**
     * @notice Asset prices are provided by chain link or other aggregator.
     * @dev Get price of `asset` from aggregator.
     * @param _asset Asset for which to get the price.
     * @return Uint mantissa of asset price (scaled by 1e18) or zero if unset or under unexpected case.
     */
    function _getAssetAggregatorPrice(address _asset) internal returns (uint256) {
        address _assetAggregator = aggregator[_asset];
        if (_assetAggregator == address(0))
            return 0;

        IAggregatorProxy _aggregatorProxy = aggregatorProxy;
        if (address(_aggregatorProxy) == address(0))
            return 0;

        (uint256 _aggregatorPrice, uint8 _decimals) = _aggregatorProxy.getAggregatorData(_asset, IAggregator(_assetAggregator));

        return srcMul(
            _aggregatorPrice, 
            10 ** (srcSub(36, srcAdd(uint256(IERC20(_asset).decimals()), uint256(_decimals))))
        );
    }

    function getAssetAggregatorPrice(address _asset) external returns (uint256) {
        return _getAssetAggregatorPrice(_asset);
    }

    /**
     * @notice Asset prices are provided by aggregator or a reader.
     * @dev Get price of `asset`.
     * @param _asset Asset for which to get the price.
     * @return Uint mantissa of asset price (scaled by 1e18) or zero if unset or under unexpected case.
     */
    function _getAssetPrice(address _asset) internal returns (uint256) {
        uint256 _assetPrice = _getAssetAggregatorPrice(_asset);
        if (_assetPrice == 0)
            return _getReaderPrice(_asset);
        
        return _assetPrice;
    }

    function getAssetPrice(address _asset) external returns (uint256) {
        return _getAssetPrice(_asset);
    }

    /**
     * @notice This is a basic function to read price, although this is a public function,
     *         It is not recommended, the recommended function is `assetPrices(asset)`.
     *         If `asset` does not has a reader to reader price, then read price from original
     *         structure `_assetPrices`;
     *         If `asset` has a reader to read price, first gets the price of reader, then
     *         `readerPrice * 10 ** |(18-assetDecimals)|`
     * @dev Get price of `asset`.
     * @param _asset Asset for which to get the price.
     * @return Uint mantissa of asset price (scaled by 1e18) or zero if unset.
     */
    function _getReaderPrice(address _asset) internal view returns (uint256) {
        Reader storage _reader = readers[_asset];
        if (_reader.asset == address(0)) return _assetPrices[_asset].mantissa;

        uint256 readerPrice = _assetPrices[_reader.asset].mantissa;

        if (_reader.decimalsDifference < 0)
            return
                srcMul(
                    readerPrice,
                    pow(10, uint256(0 - _reader.decimalsDifference))
                );

        return srcDiv(readerPrice, pow(10, uint256(_reader.decimalsDifference)));
    }

    function getReaderPrice(address _asset) external view returns (uint256) {
        return _getReaderPrice(_asset);
    }

    /**
     * @notice Retrieves price of an asset.
     * @dev Get price for an asset.
     * @param _asset Asset for which to get the price.
     * @return Uint mantissa of asset price (scaled by 1e18) or zero if unset or contract paused.
     */
    function assetPrices(address _asset) internal returns (uint256) {
        // Note: zero is treated by the xSwap as an invalid
        //       price and will cease operations with that asset
        //       when zero.
        //
        // We get the price as:
        //
        //  1. If the contract is paused, return 0.
        //  2. If the asset has an exchange rate model, the asset price is calculated based on the exchange rate.
        //  3. Return price in `_assetPrices`, which may be zero.

        if (paused) {
            return 0;
        } else {
            uint256 _assetPrice = _getAssetPrice(_asset);
            ExchangeRateInfo storage _exchangeRateInfo = exchangeRates[_asset];
            if (_exchangeRateInfo.exchangeRateModel != address(0)) {
                uint256 _scale =
                    ExchangeRateModel(_exchangeRateInfo.exchangeRateModel)
                        .scale();
                uint256 _currentExchangeRate =
                    ExchangeRateModel(_exchangeRateInfo.exchangeRateModel)
                        .getExchangeRate();
                uint256 _currentChangeRate;
                Error _err;
                (_err, _currentChangeRate) = mul(_currentExchangeRate, _scale);
                if (_err != Error.NO_ERROR) return 0;

                _currentChangeRate =
                    _currentChangeRate /
                    _exchangeRateInfo.exchangeRate;
                // require(_currentExchangeRate >= _exchangeRateInfo.exchangeRate && _currentChangeRate <= _exchangeRateInfo.maxSwingRate, "assetPrices: Abnormal exchange rate.");
                if (
                    _currentExchangeRate < _exchangeRateInfo.exchangeRate ||
                    _currentChangeRate > _exchangeRateInfo.maxSwingRate
                ) return 0;

                uint256 _price;
                (_err, _price) = mul(_assetPrice, _currentExchangeRate);
                if (_err != Error.NO_ERROR) return 0;

                return _price / _scale;
            } else {
                return _assetPrice;
            }
        }
    }

    /**
     * @notice Retrieves price of an asset.
     * @dev Get price for an asset.
     * @param _asset Asset for which to get the price.
     * @return Uint mantissa of asset price (scaled by 1e18) or zero if unset or contract paused.
     */
    function getUnderlyingPrice(address _asset) external returns (uint256) {
        return assetPrices(_asset);
    }

    /**
     * @notice The asset price status is provided by statusOracle.
     * @dev Get price status of `asset` from statusOracle.
     * @param _asset Asset for which to get the price status.
     * @return The asset price status is Boolean, the price status model is not set to true.true: available, false: unavailable.
     */
    function _getAssetPriceStatus(address _asset) internal view returns (bool) {

        IStatusOracle _statusOracle = statusOracle[_asset];
        if (_statusOracle == IStatusOracle(0))
            return true;

        return _statusOracle.getAssetPriceStatus(_asset);
    }

    function getAssetPriceStatus(address _asset) external view returns (bool) {
        return _getAssetPriceStatus(_asset);
    }

    /**
     * @notice Retrieve asset price and status.
     * @dev Get the price and status of the asset.
     * @param _asset The asset whose price and status are to be obtained.
     * @return Asset price and status.
     */
    function getUnderlyingPriceAndStatus(address _asset) external returns (uint256, bool) {
        uint256 _assetPrice = assetPrices(_asset);
        return (_assetPrice, _getAssetPriceStatus(_asset));
    }

    /**
     * @dev Get exchange rate info of an asset in the time of `interval`.
     * @param _asset Asset for which to get the exchange rate info.
     * @param _interval Time to get accmulator interest rate.
     * @return Asset price, exchange rate model address, the token that is using this exchange rate model,
     *         exchange rate model contract address,
     *         the token that is using this exchange rate model,
     *         scale between token and wrapped token,
     *         exchange rate between token and wrapped token,
     *         After the time of `_interval`, get the accmulator interest rate.
     */
    function getExchangeRateInfo(address _asset, uint256 _interval)
        external
        view
        returns (
            uint256,
            address,
            address,
            uint256,
            uint256,
            uint256
        )
    {
        if (exchangeRates[_asset].exchangeRateModel == address(0))
            return (_getReaderPrice(_asset), address(0), address(0), 0, 0, 0);

        return (
            _getReaderPrice(_asset),
            exchangeRates[_asset].exchangeRateModel,
            ExchangeRateModel(exchangeRates[_asset].exchangeRateModel).token(),
            ExchangeRateModel(exchangeRates[_asset].exchangeRateModel).scale(),
            ExchangeRateModel(exchangeRates[_asset].exchangeRateModel)
                .getExchangeRate(),
            ExchangeRateModel(exchangeRates[_asset].exchangeRateModel)
                .getFixedInterestRate(_interval)
        );
    }

    struct SetPriceLocalVars {
        Exp price;
        Exp swing;
        Exp maxSwing;
        Exp anchorPrice;
        uint256 anchorPeriod;
        uint256 currentPeriod;
        bool priceCapped;
        uint256 cappingAnchorPriceMantissa;
        uint256 pendingAnchorMantissa;
    }

    /**
     * @notice Entry point for updating prices.
     *         1) If admin has set a `readerPrice` for this asset, then poster can not use this function.
     *         2) Standard stablecoin has 18 deicmals, and its price should be 1e18,
     *            so when the poster set a new price for a token,
     *            `requestedPriceMantissa` = actualPrice * 10 ** (18-tokenDecimals),
     *            actualPrice is scaled by 10**18.
     * @dev Set price for an asset.
     * @param _asset Asset for which to set the price.
     * @param _requestedPriceMantissa Requested new price, scaled by 10**18.
     * @return Uint 0=success, otherwise a failure (see enum OracleError for details).
     */
    function setPrice(address _asset, uint256 _requestedPriceMantissa)
        external
        returns (uint256)
    {
        // Fail when msg.sender is not poster
        if (msg.sender != poster) {
            return
                failOracle(
                    _asset,
                    OracleError.UNAUTHORIZED,
                    OracleFailureInfo.SET_PRICE_PERMISSION_CHECK
                );
        }

        return setPriceInternal(_asset, _requestedPriceMantissa);
    }

    function setPriceInternal(address _asset, uint256 _requestedPriceMantissa)
        internal
        returns (uint256)
    {
        // re-used for intermediate errors
        Error _err;
        SetPriceLocalVars memory _localVars;
        // We add 1 for currentPeriod so that it can never be zero and there's no ambiguity about an unset value.
        // (It can be a problem in tests with low block numbers.)
        _localVars.currentPeriod = (block.number / numBlocksPerPeriod) + 1;
        _localVars.pendingAnchorMantissa = pendingAnchors[_asset];
        _localVars.price = Exp({ mantissa: _requestedPriceMantissa });

        if (exchangeRates[_asset].exchangeRateModel != address(0)) {
            uint256 _currentExchangeRate =
                ExchangeRateModel(exchangeRates[_asset].exchangeRateModel)
                    .getExchangeRate();
            uint256 _scale =
                ExchangeRateModel(exchangeRates[_asset].exchangeRateModel)
                    .scale();
            uint256 _currentChangeRate;
            (_err, _currentChangeRate) = mul(_currentExchangeRate, _scale);
            assert(_err == Error.NO_ERROR);

            _currentChangeRate =
                _currentChangeRate /
                exchangeRates[_asset].exchangeRate;
            require(
                _currentExchangeRate >= exchangeRates[_asset].exchangeRate &&
                    _currentChangeRate <= exchangeRates[_asset].maxSwingRate,
                "setPriceInternal: Abnormal exchange rate."
            );
            exchangeRates[_asset].exchangeRate = _currentExchangeRate;
        }

        if (readers[_asset].asset != address(0)) {
            return
                failOracle(
                    _asset,
                    OracleError.FAILED_TO_SET_PRICE,
                    OracleFailureInfo.SET_PRICE_IS_READER_ASSET
                );
        }

        _localVars.maxSwing = maxSwings[_asset].mantissa == 0
            ? maxSwing
            : maxSwings[_asset];
        if (_localVars.pendingAnchorMantissa != 0) {
            // let's explicitly set to 0 rather than relying on default of declaration
            _localVars.anchorPeriod = 0;
            _localVars.anchorPrice = Exp({
                mantissa: _localVars.pendingAnchorMantissa
            });

            // Verify movement is within max swing of pending anchor (currently: 10%)
            (_err, _localVars.swing) = calculateSwing(
                _localVars.anchorPrice,
                _localVars.price
            );
            if (_err != Error.NO_ERROR) {
                return
                    failOracleWithDetails(
                        _asset,
                        OracleError.FAILED_TO_SET_PRICE,
                        OracleFailureInfo.SET_PRICE_CALCULATE_SWING,
                        uint256(_err)
                    );
            }

            // Fail when swing > maxSwing
            // if (greaterThanExp(_localVars.swing, maxSwing)) {
            if (greaterThanExp(_localVars.swing, _localVars.maxSwing)) {
                return
                    failOracleWithDetails(
                        _asset,
                        OracleError.FAILED_TO_SET_PRICE,
                        OracleFailureInfo.SET_PRICE_MAX_SWING_CHECK,
                        _localVars.swing.mantissa
                    );
            }
        } else {
            _localVars.anchorPeriod = anchors[_asset].period;
            _localVars.anchorPrice = Exp({
                mantissa: anchors[_asset].priceMantissa
            });

            if (_localVars.anchorPeriod != 0) {
                // (_err, _localVars.priceCapped, _localVars.price) = capToMax(_localVars.anchorPrice, _localVars.price);
                (_err, _localVars.priceCapped, _localVars.price) = capToMax(
                    _localVars.anchorPrice,
                    _localVars.price,
                    _localVars.maxSwing
                );
                if (_err != Error.NO_ERROR) {
                    return
                        failOracleWithDetails(
                            _asset,
                            OracleError.FAILED_TO_SET_PRICE,
                            OracleFailureInfo.SET_PRICE_CAP_TO_MAX,
                            uint256(_err)
                        );
                }
                if (_localVars.priceCapped) {
                    // save for use in log
                    _localVars.cappingAnchorPriceMantissa = _localVars
                        .anchorPrice
                        .mantissa;
                }
            } else {
                // Setting first price. Accept as is (already assigned above from _requestedPriceMantissa) and use as anchor
                _localVars.anchorPrice = Exp({
                    mantissa: _requestedPriceMantissa
                });
            }
        }

        // Fail if anchorPrice or price is zero.
        // zero anchor represents an unexpected situation likely due to a problem in this contract
        // zero price is more likely as the result of bad input from the caller of this function
        if (isZeroExp(_localVars.anchorPrice)) {
            // If we get here price could also be zero, but it does not seem worthwhile to distinguish the 3rd case
            return
                failOracle(
                    _asset,
                    OracleError.FAILED_TO_SET_PRICE,
                    OracleFailureInfo
                        .SET_PRICE_NO_ANCHOR_PRICE_OR_INITIAL_PRICE_ZERO
                );
        }

        if (isZeroExp(_localVars.price)) {
            return
                failOracle(
                    _asset,
                    OracleError.FAILED_TO_SET_PRICE,
                    OracleFailureInfo.SET_PRICE_ZERO_PRICE
                );
        }

        // BEGIN SIDE EFFECTS

        // Set pendingAnchor = Nothing
        // Pending anchor is only used once.
        if (pendingAnchors[_asset] != 0) {
            pendingAnchors[_asset] = 0;
        }

        // If currentPeriod > anchorPeriod:
        //  Set anchors[_asset] = (currentPeriod, price)
        //  The new anchor is if we're in a new period or we had a pending anchor, then we become the new anchor
        if (_localVars.currentPeriod > _localVars.anchorPeriod) {
            anchors[_asset] = Anchor({
                period: _localVars.currentPeriod,
                priceMantissa: _localVars.price.mantissa
            });
        }

        uint256 _previousPrice = _assetPrices[_asset].mantissa;

        setPriceStorageInternal(_asset, _localVars.price.mantissa);

        emit PricePosted(
            _asset,
            _previousPrice,
            _requestedPriceMantissa,
            _localVars.price.mantissa
        );

        if (_localVars.priceCapped) {
            // We have set a capped price. Log it so we can detect the situation and investigate.
            emit CappedPricePosted(
                _asset,
                _requestedPriceMantissa,
                _localVars.cappingAnchorPriceMantissa,
                _localVars.price.mantissa
            );
        }

        return uint256(OracleError.NO_ERROR);
    }

    // As a function to allow harness overrides
    function setPriceStorageInternal(address _asset, uint256 _priceMantissa)
        internal
    {
        _assetPrices[_asset] = Exp({ mantissa: _priceMantissa });
    }

    // abs(price - anchorPrice) / anchorPrice
    function calculateSwing(Exp memory _anchorPrice, Exp memory _price)
        internal
        pure
        returns (Error, Exp memory)
    {
        Exp memory numerator;
        Error err;

        if (greaterThanExp(_anchorPrice, _price)) {
            (err, numerator) = subExp(_anchorPrice, _price);
            // can't underflow
            assert(err == Error.NO_ERROR);
        } else {
            (err, numerator) = subExp(_price, _anchorPrice);
            // Given greaterThan check above, _price >= _anchorPrice so can't underflow.
            assert(err == Error.NO_ERROR);
        }

        return divExp(numerator, _anchorPrice);
    }

    // Base on the current anchor price, get the final valid price.
    function capToMax(
        Exp memory _anchorPrice,
        Exp memory _price,
        Exp memory _maxSwing
    )
        internal
        pure
        returns (
            Error,
            bool,
            Exp memory
        )
    {
        Exp memory one = Exp({ mantissa: mantissaOne });
        Exp memory onePlusMaxSwing;
        Exp memory oneMinusMaxSwing;
        Exp memory max;
        Exp memory min;
        // re-used for intermediate errors
        Error err;

        (err, onePlusMaxSwing) = addExp(one, _maxSwing);
        if (err != Error.NO_ERROR) {
            return (err, false, Exp({ mantissa: 0 }));
        }

        // max = _anchorPrice * (1 + _maxSwing)
        (err, max) = mulExp(_anchorPrice, onePlusMaxSwing);
        if (err != Error.NO_ERROR) {
            return (err, false, Exp({ mantissa: 0 }));
        }

        // If _price > _anchorPrice * (1 + _maxSwing)
        // Set _price = _anchorPrice * (1 + _maxSwing)
        if (greaterThanExp(_price, max)) {
            return (Error.NO_ERROR, true, max);
        }

        (err, oneMinusMaxSwing) = subExp(one, _maxSwing);
        if (err != Error.NO_ERROR) {
            return (err, false, Exp({ mantissa: 0 }));
        }

        // min = _anchorPrice * (1 - _maxSwing)
        (err, min) = mulExp(_anchorPrice, oneMinusMaxSwing);
        // We can't overflow here or we would have already overflowed above when calculating `max`
        assert(err == Error.NO_ERROR);

        // If  _price < _anchorPrice * (1 - _maxSwing)
        // Set _price = _anchorPrice * (1 - _maxSwing)
        if (lessThanExp(_price, min)) {
            return (Error.NO_ERROR, true, min);
        }

        return (Error.NO_ERROR, false, _price);
    }

    /**
     * @notice Entry point for updating multiple prices.
     * @dev Set prices for a variable number of assets.
     * @param _assets A list of up to assets for which to set a price.
     *        Notice: 0 < _assets.length == _requestedPriceMantissas.length
     * @param _requestedPriceMantissas Requested new prices for the assets, scaled by 10**18.
     *        Notice: 0 < _assets.length == _requestedPriceMantissas.length
     * @return Uint values in same order as inputs.
     *         For each: 0=success, otherwise a failure (see enum OracleError for details)
     */
    function setPrices(
        address[] memory _assets,
        uint256[] memory _requestedPriceMantissas
    ) external returns (uint256[] memory) {
        uint256 numAssets = _assets.length;
        uint256 numPrices = _requestedPriceMantissas.length;
        uint256[] memory result;

        // Fail when msg.sender is not poster
        if (msg.sender != poster) {
            result = new uint256[](1);
            result[0] = failOracle(
                address(0),
                OracleError.UNAUTHORIZED,
                OracleFailureInfo.SET_PRICE_PERMISSION_CHECK
            );
            return result;
        }

        if ((numAssets == 0) || (numPrices != numAssets)) {
            result = new uint256[](1);
            result[0] = failOracle(
                address(0),
                OracleError.FAILED_TO_SET_PRICE,
                OracleFailureInfo.SET_PRICES_PARAM_VALIDATION
            );
            return result;
        }

        result = new uint256[](numAssets);

        for (uint256 i = 0; i < numAssets; i++) {
            result[i] = setPriceInternal(_assets[i], _requestedPriceMantissas[i]);
        }

        return result;
    }
}

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_poster","type":"address"},{"internalType":"uint256","name":"_maxSwing","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"requestedPriceMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"anchorPriceMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cappedPriceMantissa","type":"uint256"}],"name":"CappedPricePosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAnchorAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAnchorAdmin","type":"address"}],"name":"NewAnchorAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"anchorAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldScaledPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newScaledPrice","type":"uint256"}],"name":"NewPendingAnchor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAnchorAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAnchorAdmin","type":"address"}],"name":"NewPendingAnchorAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPoster","type":"address"},{"indexed":false,"internalType":"address","name":"newPoster","type":"address"}],"name":"NewPoster","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"msgSender","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"OracleFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousPriceMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedPriceMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPriceMantissa","type":"uint256"}],"name":"PricePosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"oldReader","type":"address"},{"indexed":false,"internalType":"address","name":"newReader","type":"address"},{"indexed":false,"internalType":"int256","name":"decimalsDifference","type":"int256"}],"name":"ReaderPosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAggregator","type":"address"},{"indexed":false,"internalType":"address","name":"newAggregator","type":"address"}],"name":"SetAggregatorProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"aggregator","type":"address"}],"name":"SetAssetAggregator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"contract IStatusOracle","name":"statusOracle","type":"address"}],"name":"SetAssetStatusOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"exchangeRateModel","type":"address"},{"indexed":false,"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxSwingRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxSwingDuration","type":"uint256"}],"name":"SetExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxSwing","type":"uint256"}],"name":"SetMaxSwing","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxSwing","type":"uint256"}],"name":"SetMaxSwingForAsset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldMaxSwingRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxSwingRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxSwingDuration","type":"uint256"}],"name":"SetMaxSwingRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"newState","type":"bool"}],"name":"SetPaused","type":"event"},{"inputs":[],"name":"MAXIMUM_SWING","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_SWING","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_PER_WEEK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acceptAnchorAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_assetPrices","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"_disableAssetAggregator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"_disableAssetAggregatorBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"_disableAssetStatusOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"_disableAssetStatusOracleBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"_disableExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAggregatorProxy","name":"_aggregatorProxy","type":"address"}],"name":"_setAggregatorProxy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_aggregator","type":"address"}],"name":"_setAssetAggregator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"address[]","name":"_aggregators","type":"address[]"}],"name":"_setAssetAggregatorBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"contract IStatusOracle","name":"_statusOracle","type":"address"}],"name":"_setAssetStatusOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"contract IStatusOracle[]","name":"_statusOracles","type":"address[]"}],"name":"_setAssetStatusOracleBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxSwing","type":"uint256"}],"name":"_setMaxSwing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_maxSwing","type":"uint256"}],"name":"_setMaxSwingForAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"uint256[]","name":"_maxSwings","type":"uint256[]"}],"name":"_setMaxSwingForAssetBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_requestedState","type":"bool"}],"name":"_setPaused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_newScaledPrice","type":"uint256"}],"name":"_setPendingAnchor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPendingAnchorAdmin","type":"address"}],"name":"_setPendingAnchorAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPoster","type":"address"}],"name":"_setPoster","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"aggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregatorProxy","outputs":[{"internalType":"contract IAggregatorProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"anchorAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"anchors","outputs":[{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"priceMantissa","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exchangeRates","outputs":[{"internalType":"address","name":"exchangeRateModel","type":"address"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"uint256","name":"maxSwingRate","type":"uint256"},{"internalType":"uint256","name":"maxSwingDuration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetAggregatorPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetPriceStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_interval","type":"uint256"}],"name":"getExchangeRateInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getReaderPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getUnderlyingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getUnderlyingPriceAndStatus","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxSwing","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSwingMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxSwings","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numBlocksPerPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAnchorAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingAnchors","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"readers","outputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"int256","name":"decimalsDifference","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_exchangeRateModel","type":"address"},{"internalType":"uint256","name":"_maxSwingDuration","type":"uint256"}],"name":"setExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_maxSwingDuration","type":"uint256"}],"name":"setMaxSwingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_requestedPriceMantissa","type":"uint256"}],"name":"setPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"uint256[]","name":"_requestedPriceMantissas","type":"uint256[]"}],"name":"setPrices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_readAsset","type":"address"}],"name":"setReaders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"statusOracle","outputs":[{"internalType":"contract IStatusOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106102b15760003560e01c806384ae2a7411610175578063be67098b116100dc578063e2f0c3ff11610095578063ed5cf2dc1161006f578063ed5cf2dc14610f11578063f3bea35214610f5d578063fa5e429614610f98578063fc57d4df14610fcb576102bb565b8063e2f0c3ff14610e2a578063e709194d14610e5d578063e9f16bd114610ed8576102bb565b8063be67098b14610c90578063c5faf1d514610d5b578063c9d5089214610d70578063cc5ca69214610da9578063ccb13cbd14610ddc578063de9d0e8514610df1576102bb565b8063ac14b9a21161012e578063ac14b9a214610b3d578063af8b075b14610b70578063b1f08a4014610b9a578063b3596f0714610c15578063bb940ac714610c48578063bbe3f6f514610c5d576102bb565b806384ae2a74146109b457806385c15d9a146109c957806386be833f14610a2c5780638bdd602b14610aa45780639964622c14610ad75780639e8c4d9514610b0a576102bb565b80634352fa9f116102195780635d496818116101d25780635d49681814610895578063692374e3146108c8578063782aaeea146109145780637e77518714610957578063809597211461096c578063817abb3c14610981576102bb565b80634352fa9f1461066b578063451b1e3a146107eb578063485feabe1461080057806349aba51f1461081557806351e59ffb1461082a5780635c975abb14610880576102bb565b80631604bf3a1161026b5780631604bf3a1461040e578063183f3444146104db578063194bef0e1461050e5780631b46eb88146105d957806326617c281461060c5780633f09932f14610638576102bb565b8062e4768b146102c057806308f318571461030b5780630910e4dd1461033c5780630a2b53bf146103775780630c9c6301146103be5780631226f96e146103d3576102bb565b366102bb57600080fd5b600080fd5b3480156102cc57600080fd5b506102f9600480360360408110156102e357600080fd5b506001600160a01b038135169060200135610ffe565b60408051918252519081900360200190f35b34801561031757600080fd5b5061032061103a565b604080516001600160a01b039092168252519081900360200190f35b34801561034857600080fd5b506102f96004803603604081101561035f57600080fd5b506001600160a01b038135811691602001351661104e565b34801561038357600080fd5b506103aa6004803603602081101561039a57600080fd5b50356001600160a01b03166111e9565b604080519115158252519081900360200190f35b3480156103ca57600080fd5b506102f96111fc565b3480156103df57600080fd5b506102f9600480360360408110156103f657600080fd5b506001600160a01b0381358116916020013516611207565b34801561041a57600080fd5b506104d96004803603604081101561043157600080fd5b810190602081018135600160201b81111561044b57600080fd5b82018360208201111561045d57600080fd5b803590602001918460208302840111600160201b8311171561047e57600080fd5b919390929091602081019035600160201b81111561049b57600080fd5b8201836020820111156104ad57600080fd5b803590602001918460208302840111600160201b831117156104ce57600080fd5b509092509050611316565b005b3480156104e757600080fd5b506102f9600480360360208110156104fe57600080fd5b50356001600160a01b03166113af565b34801561051a57600080fd5b506104d96004803603604081101561053157600080fd5b810190602081018135600160201b81111561054b57600080fd5b82018360208201111561055d57600080fd5b803590602001918460208302840111600160201b8311171561057e57600080fd5b919390929091602081019035600160201b81111561059b57600080fd5b8201836020820111156105ad57600080fd5b803590602001918460208302840111600160201b831117156105ce57600080fd5b5090925090506113c1565b3480156105e557600080fd5b50610320600480360360208110156105fc57600080fd5b50356001600160a01b031661144a565b34801561061857600080fd5b506102f96004803603602081101561062f57600080fd5b50351515611465565b34801561064457600080fd5b506102f96004803603602081101561065b57600080fd5b50356001600160a01b03166114dc565b34801561067757600080fd5b5061079b6004803603604081101561068e57600080fd5b810190602081018135600160201b8111156106a857600080fd5b8201836020820111156106ba57600080fd5b803590602001918460208302840111600160201b831117156106db57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561072a57600080fd5b82018360208201111561073c57600080fd5b803590602001918460208302840111600160201b8311171561075d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506114e7945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156107d75781810151838201526020016107bf565b505050509050019250505060405180910390f35b3480156107f757600080fd5b5061032061163c565b34801561080c57600080fd5b506102f961164b565b34801561082157600080fd5b50610320611650565b34801561083657600080fd5b5061085d6004803603602081101561084d57600080fd5b50356001600160a01b031661165f565b604080516001600160a01b03909316835260208301919091528051918290030190f35b34801561088c57600080fd5b506103aa611684565b3480156108a157600080fd5b506102f9600480360360208110156108b857600080fd5b50356001600160a01b031661168d565b3480156108d457600080fd5b506108fb600480360360208110156108eb57600080fd5b50356001600160a01b0316611736565b6040805192835260208301919091528051918290030190f35b34801561092057600080fd5b506102f96004803603606081101561093757600080fd5b506001600160a01b0381358116916020810135909116906040013561174f565b34801561096357600080fd5b506102f9611a80565b34801561097857600080fd5b50610320611a8b565b34801561098d57600080fd5b506102f9600480360360208110156109a457600080fd5b50356001600160a01b0316611a9a565b3480156109c057600080fd5b506102f9611aa5565b3480156109d557600080fd5b506109fc600480360360208110156109ec57600080fd5b50356001600160a01b0316611aac565b604080516001600160a01b0390951685526020850193909352838301919091526060830152519081900360800190f35b348015610a3857600080fd5b50610a6560048036036040811015610a4f57600080fd5b506001600160a01b038135169060200135611add565b604080519687526001600160a01b03958616602088015293909416858401526060850191909152608084015260a0830191909152519081900360c00190f35b348015610ab057600080fd5b506102f960048036036020811015610ac757600080fd5b50356001600160a01b0316611d80565b348015610ae357600080fd5b506102f960048036036020811015610afa57600080fd5b50356001600160a01b0316611e34565b348015610b1657600080fd5b506102f960048036036020811015610b2d57600080fd5b50356001600160a01b0316611ec0565b348015610b4957600080fd5b506102f960048036036020811015610b6057600080fd5b50356001600160a01b0316611ed2565b348015610b7c57600080fd5b506102f960048036036020811015610b9357600080fd5b5035611ee4565b348015610ba657600080fd5b506104d960048036036020811015610bbd57600080fd5b810190602081018135600160201b811115610bd757600080fd5b820183602082011115610be957600080fd5b803590602001918460208302840111600160201b83111715610c0a57600080fd5b509092509050611ff2565b348015610c2157600080fd5b506102f960048036036020811015610c3857600080fd5b50356001600160a01b031661202f565b348015610c5457600080fd5b506102f961203a565b348015610c6957600080fd5b506102f960048036036020811015610c8057600080fd5b50356001600160a01b0316612046565b348015610c9c57600080fd5b506104d960048036036040811015610cb357600080fd5b810190602081018135600160201b811115610ccd57600080fd5b820183602082011115610cdf57600080fd5b803590602001918460208302840111600160201b83111715610d0057600080fd5b919390929091602081019035600160201b811115610d1d57600080fd5b820183602082011115610d2f57600080fd5b803590602001918460208302840111600160201b83111715610d5057600080fd5b5090925090506120d4565b348015610d6757600080fd5b506102f9612166565b348015610d7c57600080fd5b506102f960048036036040811015610d9357600080fd5b506001600160a01b03813516906020013561216c565b348015610db557600080fd5b506102f960048036036020811015610dcc57600080fd5b50356001600160a01b03166123f6565b348015610de857600080fd5b506102f96124cb565b348015610dfd57600080fd5b506102f960048036036040811015610e1457600080fd5b506001600160a01b038135169060200135612575565b348015610e3657600080fd5b506102f960048036036020811015610e4d57600080fd5b50356001600160a01b0316612608565b348015610e6957600080fd5b506104d960048036036020811015610e8057600080fd5b810190602081018135600160201b811115610e9a57600080fd5b820183602082011115610eac57600080fd5b803590602001918460208302840111600160201b83111715610ecd57600080fd5b5090925090506126e0565b348015610ee457600080fd5b506102f960048036036040811015610efb57600080fd5b506001600160a01b038135169060200135612718565b348015610f1d57600080fd5b50610f4460048036036020811015610f3457600080fd5b50356001600160a01b0316612857565b6040805192835290151560208301528051918290030190f35b348015610f6957600080fd5b506102f960048036036040811015610f8057600080fd5b506001600160a01b038135811691602001351661287b565b348015610fa457600080fd5b5061032060048036036020811015610fbb57600080fd5b50356001600160a01b0316612ab6565b348015610fd757600080fd5b506102f960048036036020811015610fee57600080fd5b50356001600160a01b0316612ad1565b6002546000906001600160a01b03163314611027576110208360016008612adc565b9050611034565b6110318383612b5d565b90505b92915050565b60005461010090046001600160a01b031681565b6000805461010090046001600160a01b031633146110745761102060006001600c612adc565b6000826001600160a01b03166354fd4d506040518163ffffffff1660e01b815260040160206040518083038186803b1580156110af57600080fd5b505afa1580156110c3573d6000803e3d6000fd5b505050506040513d60208110156110d957600080fd5b505110156111185760405162461bcd60e51b81526004018080602001828103825260398152602001806141136039913960400191505060405180910390fd5b6001600160a01b0380841660009081526009602052604090205481169083168114156111755760405162461bcd60e51b815260040180806020018281038252603c815260200180613e5a603c913960400191505060405180910390fd5b6001600160a01b0384811660008181526009602090815260409182902080546001600160a01b0319169488169485179055815192835282019290925281517f460ab9e5772fabf7bb2770919ba806ba6fe91f9d8b881c25ed824af37ff8cabf929181900390910190a160005b949350505050565b60006111f48261312b565b90505b919050565b6611c37937e0800081565b6000805461010090046001600160a01b0316331461122d5761102060006001600c612adc565b816001600160a01b0316630a2b53bf846040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561127a57600080fd5b505afa15801561128e573d6000803e3d6000fd5b505050506040513d60208110156112a457600080fd5b50506001600160a01b038381166000818152600a602090815260409182902080546001600160a01b0319169487169485179055815192835282019290925281517f349d4686c9e28043d5ceccc23d00cad18edb2b83fb3d38f8f4721d066c6e495f929181900390910190a16000611031565b8281146113545760405162461bcd60e51b8152600401808060200182810382526052815260200180613eeb6052913960600191505060405180910390fd5b60005b838110156113a85761139f85858381811061136e57fe5b905060200201356001600160a01b031684848481811061138a57fe5b905060200201356001600160a01b0316611207565b50600101611357565b5050505050565b60076020526000908152604090205481565b8281146113ff5760405162461bcd60e51b815260040180806020018281038252604c8152602001806140c7604c913960600191505060405180910390fd5b60005b838110156113a85761144185858381811061141957fe5b905060200201356001600160a01b031684848481811061143557fe5b90506020020135612718565b50600101611402565b600a602052600090815260409020546001600160a01b031681565b6000805461010090046001600160a01b031633146114915761148a6000600180612adc565b90506111f7565b6000805483151560ff19909116811790915560408051918252517f3c70af01296aef045b2f5c9d3c30b05d4428fd257145b9c7fcd76418e65b59809181900360200190a160006111f4565b60006111f4826131d7565b81518151600254606092919083906001600160a01b03163314611554576040805160018082528183019092529060208083019080368337019050509050611532600060016008612adc565b8160008151811061153f57fe5b60209081029190910101529250611034915050565b8215806115615750828214155b1561159457604080516001808252818301909252906020808301908036833701905050905061153260006002600a612adc565b8267ffffffffffffffff811180156115ab57600080fd5b506040519080825280602002602001820160405280156115d5578160200160208202803683370190505b50905060005b83811015611632576116138782815181106115f257fe5b602002602001015187838151811061160657fe5b6020026020010151612b5d565b82828151811061161f57fe5b60209081029190910101526001016115db565b5095945050505050565b6001546001600160a01b031681565b60f081565b6008546001600160a01b031681565b600660205260009081526040902080546001909101546001600160a01b039091169082565b60005460ff1681565b6002546000906001600160a01b03838116911614156116a857fe5b60005461010090046001600160a01b031633146116cd5761148a60006001600c612adc565b600280546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd8209502cb6dab3843acd5ce51ae027a6f3488c57c2d4aedac2d94501dfcfc8d929181900390910190a160005b9392505050565b600b602052600090815260409020805460019091015482565b6000805461010090046001600160a01b0316331461177b57611774846001600c612adc565b905061172f565b6001600160a01b0383166117c05760405162461bcd60e51b815260040180806020018281038252603c81526020018061404f603c913960400191505060405180910390fd5b6000821180156117d3575062093a808211155b61180e5760405162461bcd60e51b81526004018080602001828103825260568152602001806142786056913960600191505060405180910390fd5b6000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561184957600080fd5b505afa15801561185d573d6000803e3d6000fd5b505050506040513d602081101561187357600080fd5b50519050806118b35760405162461bcd60e51b815260040180806020018281038252602e815260200180613e96602e913960400191505060405180910390fd5b6000846001600160a01b03166316b09af3856040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156118f957600080fd5b505afa15801561190d573d6000803e3d6000fd5b505050506040513d602081101561192357600080fd5b5051905080158015906119a85750846001600160a01b03166316b09af362093a806040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561197857600080fd5b505afa15801561198c573d6000803e3d6000fd5b505050506040513d60208110156119a257600080fd5b50518111155b6119e35760405162461bcd60e51b81526004018080602001828103825260528152602001806141c96052913960600191505060405180910390fd5b6001600160a01b038087166000818152600560209081526040918290208054948a166001600160a01b03199095168517815560018101879055600281018690556003018890558151928352820192909252808201849052606081018390526080810186905290517f8f040edee3352bd667ecb467e130dd5c5f9cdf6db626ea8dcaf4ff0a1fcbb7879181900360a00190a150600095945050505050565b66038d7ea4c6800081565b6002546001600160a01b031681565b60006111f48261327e565b62093a8081565b60056020526000908152604090208054600182015460028301546003909301546001600160a01b0390921692909184565b6001600160a01b0382811660009081526005602052604081205490918291829182918291829116611b2a57611b11886131d7565b6000806000806000955095509550955095509550611d76565b611b33886131d7565b6001600160a01b03808a16600090815260056020908152604091829020548251637e062a3560e11b81529251931692839263fc0c546a926004808301939192829003018186803b158015611b8657600080fd5b505afa158015611b9a573d6000803e3d6000fd5b505050506040513d6020811015611bb057600080fd5b50516001600160a01b03808c16600090815260056020908152604091829020548251637a8f0c0d60e11b8152925193169263f51e181a926004808201939291829003018186803b158015611c0357600080fd5b505afa158015611c17573d6000803e3d6000fd5b505050506040513d6020811015611c2d57600080fd5b50516001600160a01b03808d166000908152600560209081526040918290205482516339aa885b60e21b8152925193169263e6aa216c926004808201939291829003018186803b158015611c8057600080fd5b505afa158015611c94573d6000803e3d6000fd5b505050506040513d6020811015611caa57600080fd5b8101908080519060200190929190505050600560008e6001600160a01b03166001600160a01b0316815260200190815260200160002060000160009054906101000a90046001600160a01b03166001600160a01b0316636d5b54db8d6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611d3a57600080fd5b505afa158015611d4e573d6000803e3d6000fd5b505050506040513d6020811015611d6457600080fd5b5051949a509298509096509450925090505b9295509295509295565b6000805461010090046001600160a01b03163314611da55761148a826001600c612adc565b6001600160a01b038216600081815260056020908152604080832080546001600160a01b031916815560018101849055600281018490556003018390558051938452908301829052828101829052606083018290526080830191909152517f8f040edee3352bd667ecb467e130dd5c5f9cdf6db626ea8dcaf4ff0a1fcbb7879181900360a00190a160006111f4565b6000805461010090046001600160a01b03163314611e5a5761148a600060016002612adc565b600180546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f6c773973d5bcf264b509f4194ceb99e891251f6aabb325523a863c282958b13e929181900390910190a1600061172f565b600c6020526000908152604090205481565b60046020526000908152604090205481565b6000805461010090046001600160a01b03163314611f0a5761148a60006001600c612adc565b60035482811415611f4c5760405162461bcd60e51b815260040180806020018281038252603481526020018061421b6034913960400191505060405180910390fd5b66038d7ea4c680008310158015611f6b575067016345785d8a00008311155b611fa65760405162461bcd60e51b8152600401808060200182810382526027815260200180613ec46027913960400191505060405180910390fd5b6040805160208082018352908590526003859055815185815291517f2d8b75edba0b3a319274edc8de327c1163f1b657579353fd93e6fc4a5eaafc5e9281900390910190a1600061172f565b60005b8181101561202a5761202183838381811061200c57fe5b905060200201356001600160a01b03166123f6565b50600101611ff5565b505050565b60006111f4826133e6565b67016345785d8a000081565b6000805461010090046001600160a01b0316331461206c5761148a60006001600c612adc565b6001600160a01b0382166000818152600a6020908152604080832080546001600160a01b031916905580519384529083019190915280517f349d4686c9e28043d5ceccc23d00cad18edb2b83fb3d38f8f4721d066c6e495f9281900390910190a160006111f4565b8281146121125760405162461bcd60e51b815260040180806020018281038252604d815260200180613fac604d913960600191505060405180910390fd5b60005b838110156113a85761215d85858381811061212c57fe5b905060200201356001600160a01b031684848481811061214857fe5b905060200201356001600160a01b031661104e565b50600101612115565b60035481565b6000805461010090046001600160a01b0316331461219157611020836001600c612adc565b6000821180156121a4575062093a808211155b6121df5760405162461bcd60e51b8152600401808060200182810382526056815260200180613ff96056913960600191505060405180910390fd5b6001600160a01b0380841660009081526005602090815260408083205481516316b09af360e01b815260048101889052915194169384926316b09af39260248082019391829003018186803b15801561223757600080fd5b505afa15801561224b573d6000803e3d6000fd5b505050506040513d602081101561226157600080fd5b50516001600160a01b038616600090815260056020526040902060020154909150808214156122c15760405162461bcd60e51b815260040180806020018281038252602981526020018061424f6029913960400191505060405180910390fd5b6000821180156123435750826001600160a01b03166316b09af362093a806040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561231357600080fd5b505afa158015612327573d6000803e3d6000fd5b505050506040513d602081101561233d57600080fd5b50518211155b61237e5760405162461bcd60e51b81526004018080602001828103825260548152602001806141756054913960600191505060405180910390fd5b6001600160a01b038616600081815260056020908152604091829020600281018690556003018890558151928352820183905281810184905260608201879052517f83aca13f288f7821e1417b0ba093f7efd9a1ed6dc3036ddbfcd09f54c78a81049181900360800190a160005b9695505050505050565b6000805461010090046001600160a01b0316331461241c5761148a60006001600c612adc565b6000612427836131d7565b116124635760405162461bcd60e51b815260040180806020018281038252603f815260200180613dec603f913960400191505060405180910390fd5b6001600160a01b038216600081815260096020908152604080832080546001600160a01b031916905580519384529083019190915280517f460ab9e5772fabf7bb2770919ba806ba6fe91f9d8b881c25ed824af37ff8cabf9281900390910190a160006111f4565b6001546000906001600160a01b031633146124f5576124ee600060016000612adc565b9050612572565b60008054600180546001600160a01b03818116610100908102610100600160a81b03198616179095556001600160a01b0319909116909155604080519390920416808352336020840152815190927fbef9248fe57ae972dd47833f68c43f0b3b2d14217612dfbc804a520a23730d4692908290030190a160009150505b90565b6000805461010090046001600160a01b0316331461259a576110208360016003612adc565b6001600160a01b0383166000818152600c60209081526040918290208054908690558251338152918201939093528082018390526060810185905290517ff0aa20c29c1f8e751bfe0a78bc49a520ed14f2dab274087d90d1341d8b76af5c9181900360800190a160006111e1565b6000805461010090046001600160a01b0316331461262e5761148a60006001600c612adc565b6008546001600160a01b0390811690831681141561267d5760405162461bcd60e51b815260040180806020018281038252603c81526020018061408b603c913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f1fe1cdf7df984977af799c502079f980e764afd14c1d2721eeb4583145ba99119281900390910190a1600061172f565b60005b8181101561202a5761270f8383838181106126fa57fe5b905060200201356001600160a01b0316612046565b506001016126e3565b6000805461010090046001600160a01b0316331461273e5761102060006001600c612adc565b6001600160a01b038316600090815260046020526040902054828114156127965760405162461bcd60e51b815260040180806020018281038252603c815260200180613f70603c913960400191505060405180910390fd5b66038d7ea4c6800083101580156127b5575067016345785d8a00008311155b6127f05760405162461bcd60e51b815260040180806020018281038252602f815260200180613e2b602f913960400191505060405180910390fd5b60408051602080820183528582526001600160a01b03871660008181526004835284902092519092558251918252810185905281517fffc5444f492f84518884b69eb285d3240addfed786281339c6a98da499c4e87f929181900390910190a160006111e1565b60008060006128658461340a565b9050806128718561312b565b9250925050915091565b6000805461010090046001600160a01b031633146128a057611020836001600c612adc565b6001600160a01b03808416600081815260066020526040902054821691841614156128fc5760405162461bcd60e51b8152600401808060200182810382526033815260200180613f3d6033913960400191505060405180910390fd5b6001600160a01b03848116600090815260066020526040902080546001600160a01b031916918516918217905561294e576001600160a01b038416600090815260066020526040812060010155612a44565b826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561298757600080fd5b505afa15801561299b573d6000803e3d6000fd5b505050506040513d60208110156129b157600080fd5b50516040805163313ce56760e01b815290516001600160a01b0387169163313ce567916004808301926020929190829003018186803b1580156129f357600080fd5b505afa158015612a07573d6000803e3d6000fd5b505050506040513d6020811015612a1d57600080fd5b50516001600160a01b038616600090815260066020526040902091900360ff166001909101555b6001600160a01b038085166000818152600660209081526040918290206001015482519384528486169184019190915292861682820152606082019290925290517fc8266567d4ed85f6bd46d4de2cf1db932209f8fcf612ecac8928539a0b2496e89181900360800190a160006111e1565b6009602052600090815260409020546001600160a01b031681565b60006111f48261340a565b60007f96f29b65cebbd6816352fb242b6af7180b49e8a09e19e589225d35bc8444f0b73385856002811115612b0d57fe5b85600c811115612b1957fe5b604080516001600160a01b0395861681529390941660208401528284019190915260608201526000608082015290519081900360a00190a18260028111156111e157fe5b600080612b68613d72565b60f0430460010160a08201526001600160a01b038581166000818152600c60209081526040808320546101008701528051808301825289815286529282526005905220541615612da3576001600160a01b0380861660009081526005602090815260408083205481516339aa885b60e21b815291519394169263e6aa216c92600480840193919291829003018186803b158015612c0457600080fd5b505afa158015612c18573d6000803e3d6000fd5b505050506040513d6020811015612c2e57600080fd5b50516001600160a01b038088166000908152600560209081526040808320548151637a8f0c0d60e11b815291519596509294929093169263f51e181a9260048083019392829003018186803b158015612c8657600080fd5b505afa158015612c9a573d6000803e3d6000fd5b505050506040513d6020811015612cb057600080fd5b505190506000612cc083836135f6565b90955090506000856017811115612cd357fe5b14612cda57fe5b6001600160a01b0388166000908152600560205260409020600101548181612cfe57fe5b6001600160a01b038a1660009081526005602052604090206001015491900491508310801590612d4957506001600160a01b0388166000908152600560205260409020600201548111155b612d845760405162461bcd60e51b815260040180806020018281038252602981526020018061414c6029913960400191505060405180910390fd5b50506001600160a01b0386166000908152600560205260409020600101555b6001600160a01b038581166000908152600660205260409020541615612dd957612dd0856002600b612adc565b92505050611034565b6001600160a01b03851660009081526004602052604090205415612e14576001600160a01b0385166000908152600460205260409020612e17565b60035b604080516020810182529154825282015261010081015115612ec5576000608082015260408051602081019091526101008201518152606082018190528151612e609190613638565b602083015291506000826017811115612e7557fe5b14612e9357612dd08560026004856017811115612e8e57fe5b6136bd565b612ea581602001518260400151613747565b15612ec057612dd085600260068460200151600001516136bd565b612f82565b6001600160a01b0385166000818152600b60208181526040808420805460808801908152825180850190935295909452919052600190910154815260608301525115612f6e57612f2281606001518260000151836040015161374e565b8352151560c083015291506000826017811115612f3b57fe5b14612f5457612dd08560026005856017811115612e8e57fe5b8060c0015115612ec05760608101515160e0820152612f82565b604080516020810190915284815260608201525b612f8f81606001516138ef565b15612fa157612dd08560026007612adc565b8051612fac906138ef565b15612fbe57612dd08560026009612adc565b6001600160a01b0385166000908152600c602052604090205415612ff6576001600160a01b0385166000908152600c60205260408120555b80608001518160a0015111156130465760408051808201825260a0830151815282515160208083019182526001600160a01b0389166000908152600b909152929092209051815590516001909101555b6001600160a01b03851660009081526007602052604090205481515161306d9087906138f4565b815151604080516001600160a01b0389168152602081018490528082018890526060810192909252517fdd71a1d19fcba687442a1d5c58578f1e409af71a79d10fd95a4d66efd8fa9ae79181900360800190a18160c00151156131245760e0820151825151604080516001600160a01b038a16815260208101899052808201939093526060830191909152517f7221f7a2708437039cc63319145b6b873a40594b9782a3bee45b975e2f3b0f689181900360800190a15b60006123ec565b6001600160a01b038082166000908152600a6020526040812054909116806131575760019150506111f7565b806001600160a01b0316630a2b53bf846040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156131a457600080fd5b505afa1580156131b8573d6000803e3d6000fd5b505050506040513d60208110156131ce57600080fd5b50519392505050565b6001600160a01b0380821660009081526006602052604081208054919290911661321b5750506001600160a01b0381166000908152600760205260409020546111f7565b80546001600160a01b03166000908152600760205260408120546001830154909113156132665761325d81613258600a856001015460000361391f565b613980565b925050506111f7565b6111e181613279600a856001015461391f565b6139e3565b6001600160a01b03808216600090815260096020526040812054909116806132aa5760009150506111f7565b6008546001600160a01b0316806132c6576000925050506111f7565b604080516315f34dbf60e31b81526001600160a01b0386811660048301528481166024830152825160009384939286169263af9a6df8926044808301939282900301818787803b15801561331957600080fd5b505af115801561332d573d6000803e3d6000fd5b505050506040513d604081101561334357600080fd5b5080516020918201516040805163313ce56760e01b815290519295509093506123ec9285926133de926024926133d9926001600160a01b038e169263313ce567926004808301939192829003018186803b1580156133a057600080fd5b505afa1580156133b4573d6000803e3d6000fd5b505050506040513d60208110156133ca57600080fd5b505160ff908116908716613a41565b613a90565b600a0a613980565b6000806133f28361327e565b9050806111f457613402836131d7565b9150506111f7565b6000805460ff161561341e575060006111f7565b6000613429836133e6565b6001600160a01b03808516600090815260056020526040902080549293509116156135ee57805460408051637a8f0c0d60e11b815290516000926001600160a01b03169163f51e181a916004808301926020929190829003018186803b15801561349257600080fd5b505afa1580156134a6573d6000803e3d6000fd5b505050506040513d60208110156134bc57600080fd5b50518254604080516339aa885b60e21b815290519293506000926001600160a01b039092169163e6aa216c91600480820192602092909190829003018186803b15801561350857600080fd5b505afa15801561351c573d6000803e3d6000fd5b505050506040513d602081101561353257600080fd5b5051905060008061354383856135f6565b92509050600081601781111561355557fe5b1461356957600096505050505050506111f7565b8460010154828161357657fe5b049150846001015483108061358e5750846002015482115b156135a257600096505050505050506111f7565b60006135ae87856135f6565b909250905060008260178111156135c157fe5b146135d65760009750505050505050506111f7565b8481816135df57fe5b049750505050505050506111f7565b5090506111f7565b6000808361360957506000905080613631565b8383028385828161361657fe5b041461362a57600360009250925050613631565b6000925090505b9250929050565b6000613642613dd8565b61364a613dd8565b60006136568686613747565b15613683576136658686613ae0565b92509050600081601781111561367757fe5b1461367e57fe5b6136a6565b61368d8587613ae0565b92509050600081601781111561369f57fe5b146136a657fe5b6136b08287613b1a565b9350935050509250929050565b60007f96f29b65cebbd6816352fb242b6af7180b49e8a09e19e589225d35bc8444f0b733868660028111156136ee57fe5b86600c8111156136fa57fe5b604080516001600160a01b0395861681529390941660208401528284019190915260608201526080810185905290519081900360a00190a183600281111561373e57fe5b95945050505050565b5190511190565b600080613759613dd8565b613761613dd8565b506040805160208101909152670de0b6b3a76400008152613780613dd8565b613788613dd8565b613790613dd8565b613798613dd8565b60006137a4868b613b3d565b9550905060008160178111156137b657fe5b146137df57806000604051806020016040528060008152509850985098505050505050506138e6565b6137e98c86613b5c565b9350905060008160178111156137fb57fe5b1461382457806000604051806020016040528060008152509850985098505050505050506138e6565b61382e8b84613747565b156138495760006001849850985098505050505050506138e6565b613853868b613ae0565b94509050600081601781111561386557fe5b1461388e57806000604051806020016040528060008152509850985098505050505050506138e6565b6138988c85613b5c565b9250905060008160178111156138aa57fe5b146138b157fe5b6138bb8b83613c46565b156138d55750600097506001965094506138e69350505050565b6000808c9850985098505050505050505b93509350939050565b511590565b60408051602080820183529281526001600160a01b0390931660009081526007909252902090519055565b60008161392e57506001611034565b816001141561393e575081611034565b8215801561394b57508115155b1561395857506000611034565b8260015b838110156139785761396e8286613980565b915060010161395c565b509050611034565b600081158061399b5750508082028282828161399857fe5b04145b611034576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b6000808211613a30576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6469762d6f766572666c6f7760601b604482015290519081900360640190fd5b818381613a3957fe5b049392505050565b80820182811015611034576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b80820382811115611034576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000613aea613dd8565b600080613aff86600001518660000151613c4d565b60408051602081019091529081529097909650945050505050565b6000613b24613dd8565b83518351613b329190613c70565b915091509250929050565b6000613b47613dd8565b600080613aff86600001518660000151613d21565b6000613b66613dd8565b600080613b7b866000015186600001516135f6565b90925090506000826017811115613b8e57fe5b14613bad57506040805160208101909152600081529092509050613631565b600080613bc26706f05b59d3b2000084613d21565b90925090506000826017811115613bd557fe5b14613bf85781604051806020016040528060008152509550955050505050613631565b600080613c0d83670de0b6b3a7640000613d47565b90925090506000826017811115613c2057fe5b14613c2757fe5b604080516020810190915290815260009a909950975050505050505050565b5190511090565b600080838311613c64575060009050818303613631565b50600490506000613631565b6000613c7a613dd8565b600080613c8f86670de0b6b3a76400006135f6565b90925090506000826017811115613ca257fe5b14613cc157506040805160208101909152600081529092509050613631565b600080613cce8388613d47565b90925090506000826017811115613ce157fe5b14613d045781604051806020016040528060008152509550955050505050613631565b604080516020810190915290815260009890975095505050505050565b600080838301848110613d3957600092509050613631565b600360009250925050613631565b60008082613d5b5750600590506000613631565b6000838581613d6657fe5b04915091509250929050565b604051806101200160405280613d86613dd8565b8152602001613d93613dd8565b8152602001613da0613dd8565b8152602001613dad613dd8565b8152602001600081526020016000815260200160001515815260200160008152602001600081525090565b604051806020016040528060008152509056fe5f64697361626c65417373657441676772656761746f723a20546865207072696365206f66206c6f63616c206173736574732063616e6e6f742062652030215f7365744d61785377696e67466f7241737365743a20302e3125203c3d205f6d61785377696e67203c3d203130252e5f736574417373657441676772656761746f723a204f6c6420616e64206e657720616464726573732063616e6e6f74206265207468652073616d652e73657445786368616e6765526174653a2063757272656e7445786368616e676552617465206e6f74207a65726f2e5f7365744d61785377696e673a20302e3125203c3d205f6d61785377696e67203c3d203130252e5f73657441737365745374617475734f7261636c6542617463683a206173736574732026205f7374617475734f7261636c6573206d757374206d61746368207468652063757272656e74206c656e6774682e736574526561646572733a20617373657420616e64207265616441737365742063616e6e6f74206265207468652073616d652e5f7365744d61785377696e67466f7241737365743a204f6c6420616e64206e65772076616c7565732063616e6e6f74206265207468652073616d652e5f736574417373657441676772656761746f7242617463683a2061737365747320262061676772656761746f7273206d757374206d61746368207468652063757272656e74206c656e6774682e7365744d61785377696e67526174653a206d61785377696e674475726174696f6e2063616e6e6f74206265207a65726f2c206c657373207468616e2036303438303020287365636f6e647320706572207765656b292e73657445786368616e6765526174653a2065786368616e6765526174654d6f64656c2063616e6e6f742062652061207a65726f20616464726573732e5f73657441676772656761746f7250726f78793a204f6c6420616e64206e657720616464726573732063616e6e6f74206265207468652073616d652e5f7365744d61785377696e67466f72417373657442617463683a206173736574732026206d61785377696e6773206d757374206d61746368207468652063757272656e74206c656e6774682e5f736574417373657441676772656761746f723a2054686973206973206e6f74207468652061676772656761746f7220636f6e7472616374217365745072696365496e7465726e616c3a2041626e6f726d616c2065786368616e676520726174652e7365744d61785377696e67526174653a206d61785377696e67526174652063616e6e6f74206265207a65726f2c206c657373207468616e20333135333630303020287365636f6e647320706572207765656b292e73657445786368616e6765526174653a206d61785377696e67526174652063616e6e6f74206265207a65726f2c206c657373207468616e2036303438303020287365636f6e647320706572207765656b292e5f7365744d61785377696e673a204f6c6420616e64206e65772076616c7565732063616e6e6f74206265207468652073616d652e7365744d61785377696e67526174653a207468652073616d65206d6178207377696e6720726174652e73657445786368616e6765526174653a206d61785377696e674475726174696f6e2063616e6e6f74206265207a65726f2c206c657373207468616e2036303438303020287365636f6e647320706572207765656b292ea2646970667358221220113faf9f150eb241ae9983f6c2159174450ac5d1bd57d616ba65e958c6ca3eab64736f6c634300060c0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.